快捷搜索:  汽车  科技

pytorch 打包自己的数据集(在Pytorch中实现变分自动编码器)

pytorch 打包自己的数据集(在Pytorch中实现变分自动编码器)from torch import optimimport torch.nn as nn我们将使用深度神经网络来学习Q(z|X)和P(X|z)。我们考虑训练数据来估计z的参数(在我们的例子中是均值和标准差),从z中抽取样本,然后用它生成X*。首先导入依赖库 Python代码如下:import torch

这篇文章的目的是实现一个变分自动编码器(VAE)训练词,然后产生新的词。注意,要得到有意义的结果,你必须训练大量的词汇。对少量单词的训练导致产生垃圾词。另请注意,该实现使用1层GRU进行编码和解码,因此使用更有意义的体系结构可以显着提高结果。本文目的是了解VAE如何工作,而不是获得可能的最佳结果。

VAE是什么?

有大量的博客,视频讲座来解释VAE是非常详细的。在这里我只给出一个简单的草图。VAE现在是最流行的生成模型之一(另一个是GAN),和其他生成模型一样,它试图对数据进行建模。例如,VAEs可以在一组图像(数据)上进行训练,然后使用它们生成更多类似的图像。如果X是给定的数据,我们想估计P(X)这是X的真实分布,我们认为X依赖于某个潜变量z,一个数据点X从P(X|z)采样。通常情况下 我们想学习什么是z的好的价值观 这样我们就可以用它来产生更多的数据点像x。所以推理问题是估计P(z | x)或换句话说我们可以估计的参数生成x提供的数据。根据贝叶斯规则-

P(z|X) = P(X|z).P(z)/p(X)

现在P(X)=∫P(X | z)P(z)dz,在许多情况下是难以处理的。解决方法是考虑一个分布Q(z|X)来估计P(z|X)并通过使用KL散度来测量近似的好坏。我们认为Q来自gaussian family,因此每个数据点都依赖于均值和标准差。我们看看我们通常有一个编码器Q(z|X)和一个解码器P(X|z),X*是生成的数据。

pytorch 打包自己的数据集(在Pytorch中实现变分自动编码器)(1)

我们将使用深度神经网络来学习Q(z|X)和P(X|z)。我们考虑训练数据来估计z的参数(在我们的例子中是均值和标准差),从z中抽取样本,然后用它生成X*。

Python实现

首先导入依赖库 Python代码如下:

import torch

import torch.nn as nn

from torch import optim

import torch.nn.functional as F

import string

import random

我们考虑一组评论并提取出来。这个想法是生成类似的单词。每个单词都转换为张量,每个字母由唯一的整数表示。Python代码如下:

def obtainWords(fname): # parse files to obtain words removing punctuation marks

translator = str.maketrans('' '' string.punctuation)

all_words = []

with open(fname) as fs:

for line in fs:

words = line.translate(translator).strip().split()

for w in words:

all_words.append(w)

return all_words

def encodeWord(word all_letters n_letters):

w = [all_letters.find(l) for l in word]

w.append(n_letters)

input_tensor = torch.zeros((len(w) 1 n_letters 1))

for i v in enumerate(w):

input_tensor[i][0][v] = 1

return torch.tensor(w) input_tensor

现在每个单词都映射到张量(例如,[1 3 4 23])。现在让我们考虑编码器模块 -

class Encoder(nn.Module):

def __init__(self input_size hidden_size output_size):

super(Encoder self).__init__()

self.input_size = input_size

self.hidden_size = hidden_size

self.output_size = output_size

self.embedding = nn.Embedding(input_size hidden_size)

self.gru = nn.GRU(hidden_size hidden_size)

self.mean = nn.Linear(hidden_size output_size)

self.std = nn.Linear(hidden_size output_size)

def forward(self input hidden):

for ei in range(input.size(0)):

embedded = self.embedding(input[ei]).view(1 1 -1) # view is same as reshape

output = embedded

output hidden = self.gru(output hidden)

output_mean = self.mean(output)

output_std = self.std(output)

return output_mean output_std

def initHidden(self):

return torch.zeros(1 1 self.hidden_size)

我们使用1层GRU(gated recurrent unit),输入是字的字母序列,然后使用线性层来获得潜在状态分布的均值和标准差。我们现在从这个获得的分布中采样(有一个重新参数化的技巧,以便反向播工作),它作为输入提供给解码器模块 -

class Decoder(nn.Module):

def __init__(self input_size hidden_size output_size):

super(Decoder self).__init__()

self.input_size = input_size

self.hidden_size = hidden_size

self.gru = nn.GRU(input_size hidden_size)

self.out = nn.Linear(hidden_size output_size)

self.softmax = nn.LogSoftmax(dim=1)

def forward(self input hidden):

output = input

output hidden = self.gru(output hidden)

output = self.softmax(self.out(output[0]))

return output hidden

def initHidden(self):

return torch.zeros(1 1 self.hidden_size)

解码器模块再次是1层GRU,并且在输出上执行softmax操作以获得字母。我们可以通过以下方式训练网络 -

def obtainTrainingExample(all_words all_letters n_letters):

word = all_words[random.randint(0 len(all_words)-1)]

return encodeWord(word all_letters n_letters)

def train(encoder decoder normal_sampler all_words all_letters n_letters iterations=5000 learning_rate=0.001):

encoder_optimizer = optim.Adam(encoder.parameters() lr=learning_rate)

decoder_optimizer = optim.Adam(decoder.parameters() lr=learning_rate)

for it in range(iterations):

loss = 0

encoder_optimizer.zero_grad()

decoder_optimizer.zero_grad()

encoder_hidden = encoder.initHidden()

decoder_hidden = decoder.initHidden()

input input_tensor = obtainTrainingExample(all_words all_letters n_letters)

output_mean output_std = encoder(input encoder_hidden)

# sample from standard normal with mean 0 and standard deviation 1

output_std = torch.exp(output_std)

for i in range(input_tensor.size(0)):

norm = normal_sampler.sample(sample_shape=(output_std.size(0) 1)).view(1 -1)

decoder_input = torch.add(output_mean torch.mul(output_std norm))

output decoder_hidden = decoder(decoder_input decoder_hidden)

loss = loss torch.dist(input_tensor[i] output) - (torch.mul(torch.norm(output_mean) torch.norm(output_mean)) torch.mul(torch.norm(output_std) torch.norm(output_std))-torch.sum(output_std)-output_std.size(1))*0.5

loss.backward(retain_graph=True)

encoder_optimizer.step()

decoder_optimizer.step()

return output_mean output_std

为了总结训练过程,我们从训练集中随机选取一个词来获得潜在分布参数的估计,从中得到样本并将其传递给解码器以生成字母。

网络经过训练后,您可以使用以下代码生成新单词 -

def generate(decoder normal_sampler output_mean output_std all_letters MAX_LENGTH=5):

decoder_hidden = decoder.initHidden()

word=''

for i in range(MAX_LENGTH):

norm = normal_sampler.sample(sample_shape=(output_std.size(0) 1)).view(1 -1)

decoder_input = torch.add(output_mean torch.mul(output_std norm))

output decoder_hidden = decoder(decoder_input decoder_hidden)

value index = torch.topk(output 1)

if index.item()==len(all_letters):

break

else:

word =all_letters[index.item()]

print(word)

最后Python主函数示例如下:

if __name__=="__main__":

all_letters = string.ascii_letters '0123456789'

n_letters = len(all_letters)

all_words = obtainWords("sample_review")

normal_sampler = torch.distributions.normal.Normal(torch.tensor([0.0]) torch.tensor([1.0]))

input_size = n_letters 1

enc_hidden_size dec_hidden_size = 20 20

enc_output_size = 10

encoder = Encoder(n_letters 1 enc_hidden_size enc_output_size)

decoder = Decoder(enc_output_size dec_hidden_size n_letters 1)

output_mean output_std = train(encoder decoder normal_sampler all_words all_letters n_letters)

generate(decoder normal_sampler output_mean output_std all_letters)

#print(encodeWord(all_words[8] all_letters n_letters))

猜您喜欢: