Treine seu primeiro modelo GAN do zero usando o PyTorch

Tanay Agrawal Blocked Desbloquear Seguir Seguindo 26 de março

GANs, o que é o hype?

Fonte: Laboratório de Arte e Inteligência Artificial, Universidade Rutgers

Veja, é isso!
Sim, este é o trabalho de uma das redes mais básicas da Rede Generativa Adversarial (GAN).

Vamos começar com a forma como podemos fazer algo assim em algumas linhas de código.

Estou assumindo que você está familiarizado com o funcionamento das redes neurais.
Assim, um modelo simples de Redes Adversariais Generativas funciona em duas redes neurais. Um Discriminador e uma Rede Geradora, ambos são treinados um por um por várias épocas.

Gerador:

A rede do gerador recebe ruído aleatório como entrada e gera os resultados finais, por exemplo, se você está treinando sua rede para gerar o estilo de Van Gogh com tamanho de saída 1024 x 512, a rede do gerador terá 524288 neurônios de saída e determinado número de neurônios de entrada dar ruído como entrada.

Discriminador:

Discriminador é como um detetive, é um classificador binário simples, nós o treinamos em turnos, primeiro pegamos os dados originais e treinamos com um rótulo positivo. Então, vamos passar o trabalho original de Van Gogh com o rótulo 1. E passar gerou Van Gogh por gerador com o rótulo 0.
Então, nosso discriminador é treinado sobre qual é falso e qual é real.

Gerador de Treinamento e Discriminador:

Primeiro nós treinamos o discriminador para certas etapas, para treinar o discriminador, passamos os dados gerados pelo gerador, e damos o rótulo de alvo como 0 ao discriminador e novamente na mesma etapa, damos a ele uma verdadeira pintura de Van Gogh, calculamos a perda para ambos e back-propogate, e é assim que treinamos nosso discriminador para ser um bom detetive.

Agora o objetivo do nosso gerador é gerar imagens tão reais quanto, de modo a enganar o detetive e assim novamente, nós passamos o ruído aleatório para o gerador, a saída do gerador é passada para o discriminador e o discriminador é então dado um rótulo alvo 1, porque o gerador deveria estar gerando imagens que o discriminador deveria classificar de real (já que estávamos tentando enganar o discriminador). Agora, a perda calculada é propagada de volta para treinar a rede de geradores.

Para este artigo, vamos trabalhar no conjunto de dados MNIST, de forma clichê, mas, um dos melhores conjuntos de dados para começar.

Implementação de Código:

Vamos primeiro fazer as importações necessárias, você só precisa, NumPy (você não pode viver sem numpy, você simplesmente não pode), MatplotLib para plotar as imagens de número gerado, é claro PyTorch e torchvision para carregar nosso dataset MNIST.

 import numpy como np 
import matplotlib.pyplot como plt
tocha de importação
import tocha.nn como nn
importar torch.optim como optim
da variável de importação torch.autograd
dos dados de importação do torch.utils como t_data
importar torchvision.datasets como conjuntos de dados
das transformações de importação da torchvision

Agora carregue o conjunto de dados e, ao carregá-lo, também aplique a normalização.

 data_transforms = transforms.Compose ([transforms.ToTensor ()]) 
 mnist_trainset = datasets.MNIST (root = '. / data', train = True, 
download = True, transform = data_transforms)
 batch_size = 4 
 dataloader_mnist_train = t_data.DataLoader (mnist_trainset, 
batch_size = batch_size,
shuffle = True
)

Aplique alguma operação básica, para carregar o conjunto de dados mnist, dataloader_mnist_train é um objeto da tocha, que usaremos enquanto treinamos nossa rede de GANs.

E como precisamos fornecer à rede do gerador algum ruído aleatório,

 def make_some_noise (): 
return torch.rand (batch_size, 100)

Vamos agora fazer as redes de gerador e discriminador, é realmente simples de fazer uma rede neural no PyTorch, você pode usar nn.Modules e é isso.

 # definindo a classe do gerador 

gerador de classe (nn.Module):

def __init __ (self, inp, out):

super (gerador, próprio) .__ init __ ()

self.net = nn.Sequential (
nn.Linear (inp, 300),
nn.ReLU (inplace = True),
nn.Linear (300,1000),
nn.ReLU (inplace = True),
nn.Linear (1000.800),
nn.ReLU (inplace = True),
nn.Linear (800, out)
)

def forward (self, x):
x = self.net (x)
return x

E agora a rede discriminadora,

 # definindo classe discriminadora 

discriminador de classe (nn.Module):

def __init __ (self, inp, out):

super (discriminador, self) .__ init __ ()

self.net = nn.Sequential (
nn.Linear (inp, 300),
nn.ReLU (inplace = True),
nn.Linear (300,300),
nn.ReLU (inplace = True),
nn.Linear (300.200),
nn.ReLU (inplace = True),
nn.Linear (200, out)
nn.Sigmoid ()
)

def forward (self, x):
x = self.net (x)
return x

Além disso, precisaríamos de algo para plotar nossos resultados gerados e é por isso que importamos o MatplotLib

 def plot_img (matriz, número = Nenhum): 
array = array.detach ()
array = array.reshape (28,28)

plt.imshow (array, cmap = 'binary')
plt.xticks ([])
plt.yticks ([])
se número:
plt.xlabel (number, fontsize = 'x-large')
plt.show ()

Agora, temos tanto a rede de geradores e a rede discriminadora, quanto o dataloader para fornecer dados, também temos uma função de plotagem e até mesmo uma função para make_some_noise ?. Então, vamos fazer algum barulho treinando nossas redes.

Mas antes de iniciar o treinamento, vamos definir certas variáveis, como número de épocas, função de perda, otimizador, d_steps e g_steps, que decidirão depois de como as redes de gerador e discriminador serão treinadas.

 d_steps = 100 
g_steps = 100

criteriond1 = nn.BCELoss ()
optimizerd1 = optim.SGD (dis.parameters (), lr = 0.001, momentum = 0.9)

criteriond2 = nn.BCELoss ()
optimizerd2 = optim.SGD (gen.parameters (), lr = 0.001, momentum = 0.9)

printing_steps = 200

épocas = 50

E finalmente treinando:

 para época no intervalo (épocas): 

época de impressão

# discriminador de treinamento
para d_step no intervalo (d_steps):
dis.zero_grad ()

# discriminador de treinamento em dados reais
para inp_real, _ em dataloader_mnist_train:
inp_real_x = inp_real
pausa

inp_real_x = inp_real_x.reshape (batch_size, 784)
dis_real_out = dis (inp_real_x)
dis_real_loss = criteriond1 (dis_real_out,
Variável (torch.ones (batch_size, 1)))
dis_real_loss.backward ()

# discriminador de treinamento em dados produzidos pelo gerador
inp_fake_x_gen = make_some_noise ()
 # saída do gerador é gerada 
dis_inp_fake_x = gen (inp_fake_x_gen) .detach ()
dis_fake_out = dis (dis_inp_fake_x)
dis_fake_loss = criteriond1 (dis_fake_out,
Variável (torch.zeros (batch_size, 1)))
dis_fake_loss.backward ()

optimizerd1.step ()



# gerador de treinamento
para g_step no intervalo (g_steps):
gen.zero_grad ()

#gerando dados para entrada do gerador
gen_inp = make_some_noise ()

gen_out = gen (gen_inp)
dis_out_gen_training = dis (gen_out)
gen_loss = criteriond2 (dis_out_gen_training,
Variável (torch.ones (batch_size, 1)))
gen_loss.backward ()

optimizerd2.step ()

if epoch% printing_steps == 0:
plot_img (gen_out [0])
plot_img (gen_out [1])
plot_img (gen_out [2])
plot_img (gen_out [3])
print (" n n ")

Estes são os resultados com apenas algumas épocas, você provavelmente pode ver, um 5 ou 8, um 3 e um 9!

Agora vamos percorrer o código de treinamento linha por linha:

  • Primeiro nós executamos o loop por épocas.
  • Agora, nós treinamos a rede discriminadora primeiro, e estamos fazendo aprendizado não supervisionado, então não precisamos de rótulos. Então, como nós já tínhamos dataloader_mnist_train para amostras de treinamento, nós apenas retiramos as amostras de treinamento em inp_real_x.
  • Remodele-o, já que estamos usando apenas camadas lineares.
  • Faça um feed-forward de nossa rede discriminadora e calcule a perda na entrada real, usando o critério d1 que definimos acima. Como estamos fornecendo dados reais ao discriminador, também o rotularemos como 1 ( torch.ones (batch_size, 1) ). Agora, volte a propagar a rede discriminadora.
  • Agora, vamos treinar a rede discriminadora nos dados falsos, supostamente vindos da rede geradora. E nosso gerador recebe entrada de ruído aleatório, e o discriminador deve diferenciar entre dados do gerador e os dados reais, então agora fazemos algum ruído, passamos para o gerador, a saída do gerador será passada para o discriminador, e já que isso está chegando do gerador, vamos rotulá-lo como saída falsa e compará-lo com o rótulo 0 ( torch.zeros (batch_size, 1) ) e voltar a propagação da rede discriminador agora.
  • Agora, vamos treinar a rede do gerador, usaremos o make_some_noise e passaremos o ruído para a rede do gerador.
  • Em seguida, passaremos a saída do gerador para o discriminador e veremos o que o discriminador tem a dizer sobre isso. Se o discriminador predizer 1 para nossos dados gerados, bem e bem, o gerador está funcionando bem, e se o discriminador predizer 0, o gerador precisa aprender ainda.
  • E calculando a perda, propagamos de volta a rede do gerador, treinando-a.

A última das linhas está plotando a saída do gerador enquanto treinamos nossa rede de GANs ainda mais. Você poderá ver como gradualmente nossa rede de geradores começa a produzir números.

Agora que o nosso gerador está treinado, você pode usar o código abaixo para produzir números manuscritos gerados pelo AI

 plot_img (gen (make_some_noise ())) 

E foi assim que treinamos nosso primeiro modelo de GANs. E aqui nós estávamos usando apenas camadas densas, podemos obter resultados muito melhores usando camadas de convolução, tente você mesmo.

E tente experimentar um pouco, como talvez adicionar uma ativação Sigmoid no final da rede do gerador, imagens muito claras, hein? 😉

Aqui está o link para o meu repositório github, se você quiser verificar o código e ver como é fácil treinar uma GAN simples:
https://github.com/tanayag/gans

Dúvidas? Pergunte nos comentários. E se você gosta do artigo, não se esqueça de compartilhar e dar algumas palmas 🙂

Tanay Agrawal
tanay_agrawal@hotmail.com
Estagiário de aprendizado de máquina / aprendizado profundo
MateLabs