如何在Pytorch中实现压缩自动编码器?

里卡

我正在尝试contractive autoencoder在Pytorch中创建一个我找到了这个线程,并据此进行了尝试。
这是我根据提到的线程编写的代码段:

import datetime
import numpy as np 
import torch
import torchvision
from torchvision import datasets, transforms
from torchvision.utils import save_image, make_grid
import torch.nn as nn 
import torch.nn.functional as F 
import torch.optim as optim
import matplotlib.pyplot as plt 
%matplotlib inline

dataset_train = datasets.MNIST(root='MNIST',
                               train=True,
                               transform = transforms.ToTensor(),
                               download=True)
dataset_test  = datasets.MNIST(root='MNIST', 
                               train=False, 
                               transform = transforms.ToTensor(),
                               download=True)
batch_size = 128
num_workers = 2
dataloader_train = torch.utils.data.DataLoader(dataset_train,
                                               batch_size = batch_size,
                                               shuffle=True,
                                               num_workers = num_workers, 
                                               pin_memory=True)

dataloader_test = torch.utils.data.DataLoader(dataset_test,
                                               batch_size = batch_size,
                                               num_workers = num_workers,
                                               pin_memory=True)

def view_images(imgs, labels, rows = 4, cols =11):
    imgs = imgs.detach().cpu().numpy().transpose(0,2,3,1)
    fig = plt.figure(figsize=(8,4))
    for i in range(imgs.shape[0]):
        ax = fig.add_subplot(rows, cols, i+1, xticks=[], yticks=[])
        ax.imshow(imgs[i].squeeze(), cmap='Greys_r')
        ax.set_title(labels[i].item())


# now lets view some 
imgs, labels = next(iter(dataloader_train))
view_images(imgs, labels,13,10)

class Contractive_AutoEncoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = nn.Linear(784, 512)
        self.decoder = nn.Linear(512, 784)

    def forward(self, input):
        # flatten the input
        shape = input.shape
        input = input.view(input.size(0), -1)
        output_e = F.relu(self.encoder(input))
        output = F.sigmoid(self.decoder(output_e))
        output = output.view(*shape)
        return output_e, output

def loss_function(output_e, outputs, imgs, device):
    output_e.backward(torch.ones(output_e.size()).to(device), retain_graph=True)
    criterion = nn.MSELoss()
    assert outputs.shape == imgs.shape ,f'outputs.shape : {outputs.shape} != imgs.shape : {imgs.shape}'

    imgs.grad.requires_grad = True 
    loss1 = criterion(outputs, imgs)
    print(imgs.grad)
    loss2 = torch.mean(pow(imgs.grad,2))
    loss = loss1 + loss2 
    return loss 

epochs = 50 
interval = 2000
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = Contractive_AutoEncoder().to(device)
optimizer = optim.Adam(model.parameters(), lr =0.001)

for e in range(epochs):
    for i, (imgs, labels) in enumerate(dataloader_train):
        imgs = imgs.to(device)
        labels = labels.to(device)

        outputs_e, outputs = model(imgs)
        loss = loss_function(outputs_e, outputs, imgs,device)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i%interval: 
            print('')

    print(f'epoch/epoechs: {e}/{epochs} loss : {loss.item():.4f} ')

为了简洁起见,我只对编码器和解码器使用了一层。显然,无论其中任何一个层有多少层,它都可以工作!
但是这里的问题是,除了我不知道这是否是正确的方法(计算相对于输入的梯度)之外,我还遇到了一个错误,这使以前的解决方案错误/不适用。
也就是说,imgs.grad.requires_grad = True产生错误:

AttributeError:“ NoneType”对象没有属性“ requires_grad”

我还尝试了该线程中建议的第二种方法,如下所示:

class Contractive_Encoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = nn.Linear(784, 512)

    def forward(self, input):
        # flatten the input
        input = input.view(input.size(0), -1)
        output_e = F.relu(self.encoder(input))
        return output_e

class Contractive_Decoder(nn.Module):
    def __init__(self):
        super().__init__()
        self.decoder = nn.Linear(512, 784)

    def forward(self, input):
        # flatten the input
        output = F.sigmoid(self.decoder(input))
        output = output.view(-1,1,28,28)
        return output


epochs = 50 
interval = 2000
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

model_enc = Contractive_Encoder().to(device)
model_dec = Contractive_Decoder().to(device)

optimizer = optim.Adam([{"params":model_enc.parameters()},
                        {"params":model_dec.parameters()}], lr =0.001)

optimizer_cond = optim.Adam(model_enc.parameters(), lr = 0.001)

criterion = nn.MSELoss()

for e in range(epochs):
    for i, (imgs, labels) in enumerate(dataloader_train):
        imgs = imgs.to(device)
        labels = labels.to(device)

        outputs_e = model_enc(imgs)
        outputs = model_dec(outputs_e)
        loss_rec = criterion(outputs, imgs)
        optimizer.zero_grad()
        loss_rec.backward()
        optimizer.step()

        imgs.requires_grad_(True)
        y = model_enc(imgs)
        optimizer_cond.zero_grad()
        y.backward(torch.ones(imgs.view(-1,28*28).size()))

        imgs.grad.requires_grad = True
        loss = torch.mean([pow(imgs.grad,2)])
        optimizer_cond.zero_grad()
        loss.backward()
        optimizer_cond.step()

        if i%interval: 
            print('')

    print(f'epoch/epoechs: {e}/{epochs} loss : {loss.item():.4f} ')

但我遇到了错误:

RuntimeError: invalid gradient at index 0 - got [128, 784] but expected shape compatible with [128, 512]

我应该如何在Pytorch中进行此操作?

里卡

概要

我写的合同损失的最终实现如下:

def loss_function(output_e, outputs, imgs, lamda = 1e-4, device=torch.device('cuda')):

    criterion = nn.MSELoss()
    assert outputs.shape == imgs.shape ,f'outputs.shape : {outputs.shape} != imgs.shape : {imgs.shape}'
    loss1 = criterion(outputs, imgs)

    output_e.backward(torch.ones(outputs_e.size()).to(device), retain_graph=True)    
    # Frobenious norm, the square root of sum of all elements (square value)
    # in a jacobian matrix 
    loss2 = torch.sqrt(torch.sum(torch.pow(imgs.grad,2)))
    imgs.grad.data.zero_()
    loss = loss1 + (lamda*loss2) 
    return loss 

在内部训练循环中,您需要执行以下操作:

for e in range(epochs):
    for i, (imgs, labels) in enumerate(dataloader_train):
        imgs = imgs.to(device)
        labels = labels.to(device)

        imgs.retain_grad()
        imgs.requires_grad_(True)

        outputs_e, outputs = model(imgs)
        loss = loss_function(outputs_e, outputs, imgs, lam,device)

        imgs.requires_grad_(False)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f'epoch/epochs: {e}/{epochs} loss: {loss.item():.4f}')

完整说明

事实证明,@ akshayk07在评论中正确指出,在Pytorch论坛中找到的实现在多个地方都是错误的。值得注意的是,它并没有实现收缩自动编码器中引入的实际收缩损失:特征提取期间的显式不变而且除此之外,由于显而易见的原因,该实现根本无法正常工作,稍后将对此进行解释。

这些变化是显而易见的,所以我尝试解释这里发生了什么。首先请注意,imgs它不是叶节点,因此渐变将不会保留在image.grad属性中。

为了保留非叶节点的渐变,应使用retain_graph()grad仅填充叶张量。imgs.retain_grad()应该做之前被调用forward(),因为它会指示autograd存储毕业生到非叶节点。

更新资料

感谢@Michael指出Frobenius范数的正确计算实际上是(来自ScienceDirect):

所有矩阵项平方和的平方根

不是

的总和的平方根的绝对值所解释的所有矩阵条目的这里

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在 pytorch 中对自动编码器进行上采样

来自分类Dev

如何在Keras的LSTM自动编码器中获得Middel层的输出

来自分类Dev

我如何在 TensorFlow 中开发深度稀疏自动编码器成本函数?

来自分类Dev

如何获得自动编码器生成的压缩表示形式?

来自分类Dev

LSTM自动编码器的这些实现之间的区别?

来自分类Dev

Keras中的变体自动编码器:在训练和预测时如何实现Keras层的不同输出?

来自分类Dev

如何评估用于降维的自动编码器

来自分类Dev

自动编码器中的捆绑权重

来自分类Dev

Theano中的反卷积自动编码器

来自分类Dev

什么是caffe自动编码器中的稀疏字段?

来自分类Dev

Keras 中的有状态自动编码器

来自分类Dev

Keras-组合模型如何在自动编码器上仅提取部分

来自分类Dev

从Encog中的自动编码器抓取编码器/解码器

来自分类Dev

如何强制自动编码器中的瓶颈产生二进制值?

来自分类Dev

减少自动编码器的损耗

来自分类Dev

LSTM自动编码器问题

来自分类Dev

自动编码器形状

来自分类Dev

使用自动编码器实现成对的文本相似性

来自分类Dev

在变分自动编码器中从解码器输入到编码器输出的反向传播

来自分类Dev

从LSTM自动编码器输入分类器数据

来自分类Dev

keras 中的级联模型(自动编码器 + 分类器)

来自分类Dev

使用RBM的深度自动编码器

来自分类Dev

Keras自动编码器的精度/损耗不变

来自分类Dev

keras变分自动编码器损失函数

来自分类Dev

用相同的图像训练自动编码器

来自分类Dev

转换自动编码器层级数

来自分类Dev

可视化自动编码器输出

来自分类Dev

LSTM自动编码器输出层

来自分类Dev

使用自动编码器的 1 的不兼容形状

Related 相关文章

热门标签

归档