AI Illustrator: генеративно-состязательные сети

искусственный интеллект

содержание

7.1 Введение в принцип GAN

7.2 Генерация аниме-аватаров с помощью GAN

7.3 Анализ экспериментальных результатов


Генеративно-состязательная сеть (GAN) — очень популярное направление в глубоком обучении в последние годы. ЛеКун Ян, отец сверточных сетей и ветеран глубокого обучения, однажды сказал: «GAN — самая интересная идея за последние 10 лет в области машинного обучения. ». Особенно в последние два года статьи по GAN продемонстрировали тенденцию к резкому увеличению количества публикаций на GitHub. ган-зоо ]**. Автор также подсчитал тенденцию количества статей GAN, опубликованных с течением времени, как показано на рисунке ниже, который показывает популярность GAN. В этом разделе кратко представлены основные принципы GAN, и читатель сможет реализовать простую генеративно-состязательную сеть для создания аватаров аниме-персонажей.

image.png

Количество статей GAN накапливается месяц за месяцем

7.1 Введение в принцип GAN


Новаторской работой GAN является классическая статья «Генеративные состязательные сети», опубликованная Яном Гудфеллоу, известным как «отец GAN», в 2014 г. В этой статье он предложил генеративно-состязательную сеть и разработал первый эксперимент с GAN. рукописных цифр.

Создание GAN произошло благодаря гениальной идее:

«То, что я не могу создать, я не понимаю» — Ричард Фейнман.

Так же. Если глубокое обучение не может создавать картинки, то оно и не понимает их. В то время глубокое обучение начало завоевывать различные области компьютерного зрения и совершило прорыв практически во всех задачах. Тем не менее, люди всегда подвергали сомнению модель нейронных сетей «черный ящик», поэтому все больше и больше людей исследуют функции и комбинации функций, изученных с помощью сверточных сетей, с визуальной точки зрения, в то время как GAN показывает нейронную сеть с точки зрения генеративного обучения. способность. GAN решают известную проблему неконтролируемого обучения: по заданной партии образцов обучайте систему генерировать аналогичные образцы.

Сетевая структура генеративно-состязательной сети показана на рисунке ниже, которая в основном включает следующие две подсети:

Генератор: введите случайный шум и сгенерируйте изображение.
Дискриминатор: определите, является ли входное изображение реальным изображением или поддельным изображением.


При обучении дискриминатора нужно использовать поддельные картинки, сгенерированные генератором, и настоящие картинки из реального мира, при обучении генератора использовать только шум для генерации поддельных картинок. Дискриминатор используется для оценки качества сгенерированных поддельных изображений, предлагая генератору соответствующим образом настроить параметры.

Цель генератора — генерировать как можно больше реальных изображений, чтобы дискриминатор считал это реальным изображением; цель дискриминатора — отличить изображения, сгенерированные генератором, от изображений реального мира. Видно, что они имеют противоположные цели и борются друг с другом в процессе обучения, поэтому это называется генеративно-состязательной сетью.

Приведенное выше описание может быть немного абстрактным, давайте проиллюстрируем это на примере коллекционеров каллиграфии и живописи и торговцев фальшивыми картинами, которые собирают работы Ци Байши (работы Ци Байши показаны на рисунке ниже). Продавцы поддельных картин приравниваются к генераторам: они надеются имитировать оригинальные работы мастеров, чтобы подделывать поддельные картины, похожие на настоящие, чтобы обманывать коллекционеров и продавать их по высоким ценам; коллекционеры каллиграфии и живописи надеются отличить подделки от подлинных работ. , так что подлинные произведения могут быть распространены в мире. Можно сказать, что картина Ци Байши с изображением креветок является шедевром в мире живописи и всегда пользовалась спросом у всего мира.

В этом примере торговцы поддельными картинами и коллекционеры каллиграфии и живописи поначалу являются новичками и имеют смутное представление о подлинности и подделке. Поддельные картины, созданные торговцами поддельными картинами, почти все представляют собой случайные граффити, а коллекционеры каллиграфии и живописи плохо идентифицируют себя Многие подделки рассматриваются им как подлинные работы, а многие подлинные работы считаются подделками.

Прежде всего, коллекционеры каллиграфии и живописи собрали на рынке большое количество подделок и оригинальных работ Мастера Ци Байши, внимательно изучили сравнение, и изначально изучили строение креветки на картине», все поддельные картины. не удовлетворяющие этому условию, отсеиваются. Когда коллекционеры используют этот стандарт для проведения оценки на рынке, фальшивые картины в принципе не в состоянии обмануть коллекционеров, и торговцы фальшивыми картинами несут большие убытки. Однако среди подделок, сфальсифицированных торговцами фальшивой краской, все же есть прошедшие проверку фальшивки с изогнутыми формами и парой «хелипедов», похожих на плоскогубцы. Таким образом, торговцы поддельными картинами начали модифицировать методы подделки, добавляя к подделкам изогнутые формы и пару клещеобразных «хелиперов». В дополнение к этим функциям другие места, такие как цвета и линии, рисуются случайным образом. Первая версия подделки, созданная фейковым арт-дилером, показана ниже.

Когда торговцы фальшивыми картинами выставляют эти картины на рынок, они могут легко обмануть коллекционеров, потому что на картине изображено кривое существо, а перед существом стоит пара клещей, что соответствует стандартам коллекционеров как подлинное. коллекционеры выкупают его как подлинный. С течением случайного времени коллекционеры покупали все больше и больше поддельных картин и терпели большие убытки, поэтому он закрыл свою дверь, чтобы изучить разницу между подделками и подлинными работами.Форма креветки, щупальца креветки длинные, а все тело полупрозрачное, а детали креветки очень богатые, и каждая часть креветки белая.

После того, как коллекционеры узнали, они вышли снова, но навыки подделок у торговцев поддельными картинами не улучшились, и произведенные подделки были легко замечены коллекционерами. Так и торговцы подделками стали пробовать разные способы раскрашивания креветок, большинство из которых были напрасными, но среди множества попыток все же были подделки, которые обманывали взоры коллекционеров. Продавцы поддельной живописи нашли эти подделки с длинными щупальцами, полностью прозрачными, а нарисованные креветки очень детализированы, как показано ниже. В результате торговцы фальшивыми картинами стали массово имитировать такие картины и продавать их на рынке, причем многие из них успешно обманывали коллекционеров.

Коллекционеры снова понесли большие потери и были вынуждены закрыть свои двери, чтобы изучить разницу между оригинальными работами Ци Байши и подделками, изучить характеристики подлинных работ Ци Байши и улучшить их способность идентифицировать. Таким образом, благодаря игре между коллекционерами и торговцами поддельными картинами, коллекционеры постепенно улучшали свою способность идентифицировать подлинные работы и подделки с нуля, в то время как торговцы поддельными картинами также постоянно улучшали свой уровень имитации подлинных работ Ци Байши. Коллекционеры используют подделки, предоставленные торговцами поддельными картинами, для сравнения с настоящими работами, чтобы они могли лучше оценить оригинальные работы раскрашенных креветок Ци Байши; и торговцы поддельными картинами также постоянно пытаются повысить уровень имитации и качество поддельных картин, даже если они в итоге.Это все равно подделка, но очень близкая к настоящей. Коллекционеры и торговцы поддельными картинами соревнуются друг с другом, и в то же время они постоянно способствуют обучению и прогрессу друг друга, чтобы достичь цели общего совершенствования.

В этом примере фальшивый дилер выступает в роли генератора, а коллектор — в роли дискриминатора. И генератор, и дискриминатор поначалу работают плохо, потому что оба инициализируются случайным образом. Процесс обучения делится на два чередующихся шага: первый шаг — обучение дискриминатора (только изменение параметров дискриминатора и фиксация генератора), цель — отличить оригинал от подделки, второй шаг — обучение генератор (только изменить генератор) Параметры фиксированного дискриминатора), чтобы сгенерированные фальшивые картины могли быть распознаны дискриминатором как подлинные произведения (признанные коллекционерами как подлинные произведения). Эти два шага чередуются, и генератор и дискриминатор достигают высокого уровня. В конце обучения ниже показана картинка сгенерированной креветки, которая практически неотличима от оригинальной работы Ци Байши.

Теперь давайте подумаем о дизайне сетевой структуры. Цель дискриминатора состоит в том, чтобы определить, является ли входное изображение подлинным или поддельным, поэтому его можно рассматривать как сеть с двумя классами.Ссылаясь на эксперимент «Собаки против кошек» в главе 6, мы можем разработать простую сверточную сеть. Задача генератора — сгенерировать цветное изображение из шума.Здесь мы используем широко используемую структуру DCGAN (Deep Convolutional Generative Adversarial Networks), то есть полностью свёрточную сеть, структура которой показана ниже. Вход сети — это 100-мерный шум, а выход — изображение 3*64*64. Вход здесь можно рассматривать как картинку 100 * 1 * 1, которая медленно увеличивается до 4 * 4, 8 * 8, 16 * 16, 32 * 32 и 64 * 64 посредством свертки вверх. Апконволюция или транспонированная свертка — это специальная операция свертки, аналогичная обратной операции свертки. Когда шаг свертки равен 2, выходные данные понижаются до половины размера входных данных, а когда шаг повышающей свертки равен 2, выходные данные повышаются до удвоенного размера входных данных. Этот метод повышения дискретизации можно понять, поскольку информация об изображении хранится в векторах 100. В соответствии с информацией, описанной этими 100 векторами, нейронная сеть сначала выделяет основную информацию, такую ​​​​как контур и тон, на первых нескольких шагах повышения дискретизации, и следующие несколько шагов. Повышение частоты дискретизации медленно уточняет детали. Чем глубже сеть, тем подробнее детали.

image.png

В DCGAN структура дискриминатора симметрична генератору: в генераторе используется свертка с повышающей дискретизацией, дискриминатор использует свертку с понижающей дискретизацией, а генератор выдает изображение 64*64*3 в соответствии с шумом, в то время как дискриминатор выводит оценку (вероятность) положительных и отрицательных образцов в соответствии с входным изображением 64 * 64 * 3.

7.2 Генерация аниме-аватаров с помощью GAN

В этом разделе GAN будет использоваться для реализации примера создания аватаров аниме-персонажей. На японском технологическом блоге есть блогер (предположительно двухмерный энтузиаст)
@mattya, используйте DCGAN, чтобы учиться на 200 000 аниме-аватаров, и, наконец, используйте программу для автоматического создания аниме-аватаров.Эффект сгенерированных картинок показан на рисунке ниже. Исходная программа реализована с использованием фреймворка Chainer, в этом разделе мы попытаемся реализовать ее с помощью PyTorch.

Исходное изображение сканируется с веб-сайта, а OpenCV используется для перехвата аватара, который сложнее обрабатывать. Здесь мы используем 50 000 изображений, просканированных и обработанных пользователем Zhihu He Zhiyuan. Вы можете загрузить все сжатые пакеты изображений по ссылке на сетевой диск Baidu в файле README.MD вспомогательной программы этой книги и извлечь их в указанную папку. Следует отметить, что разрешение картинки здесь 3*96*96, а не 3*64*64 в бумаге, поэтому структуру сети нужно соответствующим образом скорректировать, чтобы размер сгенерированного изображения был 96.

Давайте сначала посмотрим на структуру кода этого эксперимента.

checkpoints/    # 无代码,用来保存模型
imgs/    # 无代码,用来保存生成的图片
data/    # 无代码,用来保存训练所需的图片
main.py    # 训练和生成
model.py    # 模型定义
visualize.py    # 可视化工具visdom的封装
requirements.txt    # 程序中用到的第三方库
README.MD    # 说明


Далее давайте посмотрим, как генератор определен в model.py.

# coding:utf8
from torch import nn


class NetG(nn.Module):
    """
    生成器定义
    """

    def __init__(self, opt):
        super(NetG, self).__init__()
        ngf = opt.ngf  # 生成器feature map数

        self.main = nn.Sequential(
            # 输入是一个nz维度的噪声,我们可以认为它是一个1*1*nz的feature map
            nn.ConvTranspose2d(opt.nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            # 上一步的输出形状:(ngf*8) x 4 x 4

            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            # 上一步的输出形状: (ngf*4) x 8 x 8

            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            # 上一步的输出形状: (ngf*2) x 16 x 16

            nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            # 上一步的输出形状:(ngf) x 32 x 32

            nn.ConvTranspose2d(ngf, 3, 5, 3, 1, bias=False),
            nn.Tanh()  # 输出范围 -1~1 故而采用Tanh
            # 输出形状:3 x 96 x 96
        )

    def forward(self, input):
        return self.main(input)


Видно, что конструкция генератора относительно проста.Вы можете напрямую использовать nn.Sequential для операций сплайсинга, таких как свертка вверх, активация и объединение.Здесь вам нужно обратить внимание на использование свертки вверх ConvTranspose2d . Когда kernel_size равен 4, шаг равен 2, а отступ равен 1, в соответствии с формулойH^{_{out}}=(H^{_{in}}-1)*stride-2*padding+kernelsize,Выходной размер ровно в два раза больше входного. Последний слой использует размер ядра 5, шаг 3 и отступ 1, чтобы повысить дискретизацию 32*32 до 96*96, что является размером изображения в этом примере, который отличается от размера 64*64 в бумага. Последний слой использует Tanh для нормализации пикселей выходного изображения до -1 ~ 1. Если вы хотите нормализовать до 0 ~ 1, вам нужно использовать Sigmoid.

Далее давайте посмотрим на сетевую структуру дискриминатора.

class NetD(nn.Module):
    """
    判别器定义
    """

    def __init__(self, opt):
        super(NetD, self).__init__()
        ndf = opt.ndf
        self.main = nn.Sequential(
            # 输入 3 x 96 x 96
            nn.Conv2d(3, ndf, 5, 3, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            # 输出 (ndf) x 32 x 32

            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            # 输出 (ndf*2) x 16 x 16

            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            # 输出 (ndf*4) x 8 x 8

            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            # 输出 (ndf*8) x 4 x 4

            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()  # 输出一个数(概率)
        )

    def forward(self, input):
        return self.main(input).view(-1)


Видно, что сетевые структуры дискриминатора и генератора практически симметричны, начиная от размера ядра свертки и заканчивая настройками типа заполнения и шага, которые практически идентичны. Например, масштаб последнего сверточного слоя генератора равен (5,3,1), а масштаб первого сверточного слоя дискриминатора также равен (5,3,1). Кроме того, здесь следует отметить, что функция активации генератора использует ReLU, в то время как дискриминатор использует LeakyReLU, Между ними нет существенной разницы, Выбор здесь - это скорее обобщение опыта. После того, как каждый образец проходит через дискриминатор, он выводит число от 0 до 1, указывающее вероятность того, что образец является реальным изображением.

Прежде чем приступить к написанию обучающей функции, давайте взглянем на параметры конфигурации модели.

class Config(object):
    data_path = 'data/'  # 数据集存放路径
    num_workers = 4  # 多进程加载数据所用的进程数
    image_size = 96  # 图片尺寸
    batch_size = 256
    max_epoch = 200
    lr1 = 2e-4  # 生成器的学习率
    lr2 = 2e-4  # 判别器的学习率
    beta1 = 0.5  # Adam优化器的beta1参数
    gpu = True  # 是否使用GPU
    nz = 100  # 噪声维度
    ngf = 64  # 生成器feature map数
    ndf = 64  # 判别器feature map数

    save_path = 'imgs/'  # 生成图片保存路径

    vis = True  # 是否使用visdom可视化
    env = 'GAN'  # visdom的env
    plot_every = 20  # 每间隔20 batch,visdom画图一次

    debug_file = '/tmp/debuggan'  # 存在该文件则进入debug模式
    d_every = 1  # 每1个batch训练一次判别器
    g_every = 5  # 每5个batch训练一次生成器
    save_every = 10  # 没10个epoch保存一次模型
    netd_path = None  # 'checkpoints/netd_.pth' #预训练模型
    netg_path = None  # 'checkpoints/netg_211.pth'

    # 只测试不训练
    gen_img = 'result.png'
    # 从512张生成的图片中保存最好的64张
    gen_num = 64
    gen_search_num = 512
    gen_mean = 0  # 噪声的均值
    gen_std = 1  # 噪声的方差


opt = Config()


Это просто параметры модели по умолчанию, вы также можете использовать такие инструменты, как огонь, для передачи через командную строку, чтобы переопределить значения по умолчанию. Кроме того, мы также можем напрямую использовать opt.attr, а также использовать функцию автоматического завершения, предоставляемую IDE/IPython, что очень удобно. Большинство настроек гиперпараметров здесь скопированы со значений по умолчанию из статьи DCGAN.После множества экспериментов автор обнаружил, что эти параметры могут быстрее обучать хорошую модель.

После того, как мы скачаем данные, нам нужно поместить все картинки в папку, а затем переместить папку в каталог данных (что гарантирует отсутствие других папок под данными). Этот метод обработки позволяет напрямую использовать папку ImageFolder, поставляемую с torchvision, для чтения изображения без необходимости самостоятельно записывать набор данных. Код для чтения и загрузки данных выглядит следующим образом:

  # 数据
    transforms = tv.transforms.Compose([
        tv.transforms.Resize(opt.image_size),
        tv.transforms.CenterCrop(opt.image_size),
        tv.transforms.ToTensor(),
        tv.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ])

    dataset = tv.datasets.ImageFolder(opt.data_path, transform=transforms)
    dataloader = t.utils.data.DataLoader(dataset,
                                         batch_size=opt.batch_size,
                                         shuffle=True,
                                         num_workers=opt.num_workers,
                                         drop_last=True
                                         )


Видно, что очень удобно использовать ImageFolder с DataLoader для загрузки картинок.

Перед обучением нам также необходимо определить несколько переменных: модель, оптимизатор, шум и т.д. 

 # 网络
    netg, netd = NetG(opt), NetD(opt)
    map_location = lambda storage, loc: storage
    if opt.netd_path:
        netd.load_state_dict(t.load(opt.netd_path, map_location=map_location))
    if opt.netg_path:
        netg.load_state_dict(t.load(opt.netg_path, map_location=map_location))
    netd.to(device)
    netg.to(device)


    # 定义优化器和损失
    optimizer_g = t.optim.Adam(netg.parameters(), opt.lr1, betas=(opt.beta1, 0.999))
    optimizer_d = t.optim.Adam(netd.parameters(), opt.lr2, betas=(opt.beta1, 0.999))
    criterion = t.nn.BCELoss().to(device)

    # 真图片label为1,假图片label为0
    # noises为生成网络的输入
    true_labels = t.ones(opt.batch_size).to(device)
    fake_labels = t.zeros(opt.batch_size).to(device)
    fix_noises = t.randn(opt.batch_size, opt.nz, 1, 1).to(device)
    noises = t.randn(opt.batch_size, opt.nz, 1, 1).to(device)

    errord_meter = AverageValueMeter()
    errorg_meter = AverageValueMeter()


При загрузке предварительно обученной модели лучше указать map_location. Потому что если до этого программа запускалась на GPU, то модель будет храниться как torch.cuda.Tensor, поэтому при загрузке данные по умолчанию будут загружаться в видеопамять. Если в компьютере, на котором запущена программа, нет графического процессора, то при загрузке будет выдано сообщение об ошибке, поэтому тензор загружается в память по умолчанию, указав map_location, а затем при необходимости перемещается в видеопамять.

Приступим к обучению сети.Этапы обучения следующие.

(1) Обучение дискриминатора

Фиксированный генератор
Для реальных изображений выходное значение вероятности дискриминатора максимально близко к 1
Для поддельных изображений, сгенерированных генератором, дискриминатор выводит 0, насколько это возможно.
(2) Обучить генератор

Фиксированный дискриминатор
Генератор генерирует изображения, а дискриминатор максимально выдает 1
(3) Вернитесь к первому шагу, чередуйте циклы тренировок.

  epochs = range(opt.max_epoch)
    for epoch in iter(epochs):
        for ii, (img, _) in tqdm.tqdm(enumerate(dataloader)):
            real_img = img.to(device)

            if ii % opt.d_every == 0:
                # 训练判别器
                optimizer_d.zero_grad()
                ## 尽可能的把真图片判别为正确
                output = netd(real_img)
                error_d_real = criterion(output, true_labels)
                error_d_real.backward()

                ## 尽可能把假图片判别为错误
                noises.data.copy_(t.randn(opt.batch_size, opt.nz, 1, 1))
                fake_img = netg(noises).detach()  # 根据噪声生成假图
                output = netd(fake_img)
                error_d_fake = criterion(output, fake_labels)
                error_d_fake.backward()
                optimizer_d.step()

                error_d = error_d_fake + error_d_real

                errord_meter.add(error_d.item())

            if ii % opt.g_every == 0:
                # 训练生成器
                optimizer_g.zero_grad()
                noises.data.copy_(t.randn(opt.batch_size, opt.nz, 1, 1))
                fake_img = netg(noises)
                output = netd(fake_img)
                error_g = criterion(output, true_labels)
                error_g.backward()
                optimizer_g.step()
                errorg_meter.add(error_g.item())

            if opt.vis and ii % opt.plot_every == opt.plot_every - 1:
                ## 可视化
                if os.path.exists(opt.debug_file):
                    ipdb.set_trace()
                fix_fake_imgs = netg(fix_noises)
                vis.images(fix_fake_imgs.detach().cpu().numpy()[:64] * 0.5 + 0.5, win='fixfake')
                vis.images(real_img.data.cpu().numpy()[:64] * 0.5 + 0.5, win='real')
                vis.plot('errord', errord_meter.value()[0])
                vis.plot('errorg', errorg_meter.value()[0])

        if (epoch+1) % opt.save_every == 0:
            # 保存模型、图片
            tv.utils.save_image(fix_fake_imgs.data[:64], '%s/%s.png' % (opt.save_path, epoch), normalize=True,
                                range=(-1, 1))
            t.save(netd.state_dict(), 'checkpoints/netd_%s.pth' % epoch)
            t.save(netg.state_dict(), 'checkpoints/netg_%s.pth' % epoch)
            errord_meter.reset()
            errorg_meter.reset()



Здесь следует отметить следующие моменты.

При обучении генератора нет необходимости настраивать параметры дискриминатора, при обучении дискриминатора нет необходимости настраивать параметры генератора.
При обучении дискриминатора необходимо использовать операцию отсоединения, чтобы обрезать граф расчета изображения, сгенерированного генератором, чтобы избежать обратного распространения и передать градиент в генератор. Поскольку нам не нужно обучать генератор при обучении дискриминатора, нам не нужен градиент генератора.
При обучении дискриминатора необходимо выполнить обратное распространение дважды: один раз, чтобы оценить реальное изображение как 1, и один раз, чтобы оценить фальшивое изображение как 0. Вы также можете поместить данные двух в пакет и выполнить прямое распространение и обратное распространение. Но было обнаружено, что лучше всего включать в пакет только настоящие изображения или только поддельные изображения.
Для поддельных изображений при обучении дискриминатора мы хотим, чтобы он выдавал 0, а при обучении генератора мы хотим, чтобы он выдавал 1. Таким образом, вы видите пару, казалось бы, противоречивых кодов error_d_fake = критерий (выход, fake_labels) и error_g = критерий (выход, true_labels). На самом деле это тоже очень понятно.Дискриминатор надеется отличить поддельные изображения как fake_labels, а генератор надеется отличить их как true_labels.Дискриминатор и генератор борются друг с другом за улучшение.
Далее идет визуальный код. Шум, используемый для каждой визуализации, — это fixed_noises, потому что это позволяет нам сравнивать, как шаг за шагом улучшаются сгенерированные генератором изображения для одних и тех же входных данных. Кроме того, поскольку мы нормализовали входное изображение (-1~1), нам нужно восстановить его в исходном масштабе (0~1) во время визуализации.

 fix_fake_imgs = netg(fix_noises)
 vis.images(fix_fake_imgs.detach().cpu().numpy()[:64] * 0.5 + 0.5, win='fixfake')


В дополнение к этому предусмотрена функция, которая может загружать предварительно обученную модель и случайным образом генерировать изображения с использованием шума.

@t.no_grad()
def generate(**kwargs):
    """
    随机生成动漫头像,并根据netd的分数选择较好的
    """
    for k_, v_ in kwargs.items():
        setattr(opt, k_, v_)
    
    device=t.device('cuda') if opt.gpu else t.device('cpu')

    netg, netd = NetG(opt).eval(), NetD(opt).eval()
    noises = t.randn(opt.gen_search_num, opt.nz, 1, 1).normal_(opt.gen_mean, opt.gen_std)
    noises = noises.to(device)

    map_location = lambda storage, loc: storage
    netd.load_state_dict(t.load(opt.netd_path, map_location=map_location))
    netg.load_state_dict(t.load(opt.netg_path, map_location=map_location))
    netd.to(device)
    netg.to(device)


    # 生成图片,并计算图片在判别器的分数
    fake_img = netg(noises)
    scores = netd(fake_img).detach()

    # 挑选最好的某几张
    indexs = scores.topk(opt.gen_num)[1]
    result = []
    for ii in indexs:
        result.append(fake_img.data[ii])
    # 保存图片
    tv.utils.save_image(t.stack(result), opt.gen_img, normalize=True, range=(-1, 1))


Для получения полного кода обратитесь к прилагаемой главе примера кода/AnimeGAN этой книги. Следуйте инструкциям в README.MD, чтобы настроить среду, подготовить данные и начать обучение с помощью следующей команды:

python main.py train --gpu=True    # 使用GPU
                     --vis=True    # 使用visdom
                     --batch-size=512    # batch size
                     --max-epoch=500    # 训练200个epoch


Если вы используете visdom, вы можете увидеть сгенерированное изображение, открыв в это время http://localhost:8097.

После завершения обучения мы можем использовать генеративную сеть для случайной генерации аниме-изображений, введя следующие команды:

python main.py generate  --gen-img='result.png'
                         --gen-search-num=15000

7.3 Анализ экспериментальных результатов


Экспериментальные результаты показаны на рисунке ниже, которые представляют собой анимационные аватары, сгенерированные нейронной сетью после обучения 1, 10, 20, 30, 40 и 200 эпох (все сгенерированные изображения находятся в папке imgs). Следует отметить, что входной шум генератора каждый раз одинаков, поэтому мы можем сравнить, как постепенно улучшается качество сгенерированного изображения при одном и том же входном сигнале.

Изображения в начале обучения относительно размыты (1 эпоха), но видно, что на изображениях уже есть контуры лица.

После продолжения обучения в течение 10 эпох сгенерированная карта имеет много подробной информации, включая волосы, цвет и т. д., но общая картина все еще размыта.

После обучения в течение 20 эпох детали продолжают улучшаться, в том числе текстура волос, детали глаз и т. д., но следов смазывания все еще много.

При обучении на 40 эпох видны явные контуры и детали лица, но все равно есть размытость, а некоторые детали непонятны, например глаза большие и маленькие, а контуры лица сильно искажены.

После тренировки на 200 эпохальных сессиях детали картинок доведены до совершенства, линии стали ровнее, а очертания четче.Хотя еще есть необоснованные моменты, уже много картинок, которые можно подделать.

Аналогичные проекты по созданию аниме-аватаров включают «Создание HD-аниме-аватаров с помощью DRGAN», эффект показан на рисунке ниже. К сожалению, поскольку данные, использованные в статье, связаны с вопросами авторского права, они не могут быть раскрыты. Основные улучшения в этой статье включают использование изображений более высокого качества и более глубоких и сложных моделей.

Примеры программ, описанные в этой главе, также можно применять к различным сценариям создания изображений, если обучающие изображения заменяются изображениями других типов, такими как набор изображений арендатора LSUN, набор данных рукописного ввода MNIST или набор данных CIFAR10. На самом деле, в приведенной выше модели еще есть много возможностей для улучшения. Здесь полностью сверточная сеть, которую мы используем, имеет только четыре слоя, а модель относительно неглубокая.После публикации статьи ResNet многие исследователи пытались ввести структуру Residual Block в структуру сети GAN и добились хороших визуальных эффектов. Заинтересованные читатели могут попробовать изменить однослойную свертку в примере кода на Residual Block, и я верю, что можно добиться хороших результатов.

В этом году главный прорыв GAN заключается в теоретических исследованиях. В документе «На пути к принципиальным методам обучения генеративно-состязательных сетей» анализируется, почему GAN трудно обучать с теоретической точки зрения, а затем автор предлагает лучшее решение в другой статье «Wasserstein GAN». Однако реализация некоторых технических деталей в этой статье слишком произвольна, поэтому кто-то другой предложил целенаправленно «Улучшенное обучение GAN Вассерштейна» для лучшего обучения WGAN. Последние две статьи реализованы в PyTorch и TensorFlow соответственно, а код можно найти на GitHub. Автор также попытался реализовать Wasserstein GAN с помощью примерно 100 строк кода, и читатели, интересующиеся этим, могут узнать об этом.

С постепенным развитием исследований GAN люди также пытаются использовать GAN в практических промышленных задачах.Среди многих связанных статей наиболее впечатляющей является «Преобразование непарного изображения в изображение с использованием циклически согласованных состязательных сетей».Новая структура GAN называется В статье предлагается CycleGAN. CycleGAN использует GAN для передачи стиля, раскрашивания черно-белых изображений и взаимного преобразования лошадей и зебр Эффект очень выдающийся. Автор статьи использует PyTorch для реализации всего кода и открывает его исходный код на GitHub, а заинтересованные читатели могут проверить его самостоятельно.

Эта глава в основном знакомит читателей с основными принципами GAN и знакомит читателей с использованием GAN для создания аниме-аватаров. Существует много вариантов GAN, и на GitHub есть много GAN, реализованных с помощью PyTorch, и заинтересованные читатели могут обратиться к ним.

Отлаженный код, модель, канал передачи данных:download.CSDN.net/download/Хе-хе…