【问题标题】:Can auto-encoder encode new vector without re-training afresh?自动编码器可以在不重新训练的情况下编码新向量吗?
【发布时间】:2020-07-30 07:08:22
【问题描述】:

这是一个简单的自动编码器,用于将 3 个维度为 1x3 的向量:[1,2,3],[1,2,3],[100,200,500] 编码为 1x1:

epochs = 1000
from pylab import plt
plt.style.use('seaborn')
import torch.utils.data as data_utils
import torch
import torchvision
import torch.nn as nn
from torch.autograd import Variable

cuda = torch.cuda.is_available()
FloatTensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor
import numpy as np
import pandas as pd
import datetime as dt


features = torch.tensor(np.array([ [1,2,3],[1,2,3],[100,200,500] ]))

print(features)

batch = 1
data_loader = torch.utils.data.DataLoader(features, batch_size=2, shuffle=False)

encoder = nn.Sequential(nn.Linear(3,batch), nn.Sigmoid())
decoder = nn.Sequential(nn.Linear(batch,3), nn.Sigmoid())
autoencoder = nn.Sequential(encoder, decoder)

optimizer = torch.optim.Adam(params=autoencoder.parameters(), lr=0.001)

encoded_images = []
for i in range(epochs):
    for j, images in enumerate(data_loader):
    #     images = images.view(images.size(0), -1) 
        images = Variable(images).type(FloatTensor)
        optimizer.zero_grad()
        reconstructions = autoencoder(images)
        loss = torch.dist(images, reconstructions)
        loss.backward()
        optimizer.step()

#     encoded_images.append(encoder(images))

# print(decoder(torch.tensor(np.array([1,2,3])).type(FloatTensor)))

encoded_images = []
for j, images in enumerate(data_loader):
    images = images.view(images.size(0), -1) 
    images = Variable(images).type(FloatTensor)

    encoded_images.append(encoder(images))

变量encoded_images 是一个大小为3 的数组,其中每个数组条目代表feature 数组的降维:

[tensor([[0.9972],
         [0.9972]], grad_fn=<SigmoidBackward>),
 tensor([[1.]], grad_fn=<SigmoidBackward>)]

为了确定新特征的相似性,例如[1,1,1] 是否需要重新训练网络,或者是否可以“引导”现有训练的网络配置/权重,以便无需对新向量进行编码重新训练网络?

【问题讨论】:

    标签: deep-learning pytorch autoencoder


    【解决方案1】:

    抱歉,您的代码一团糟……如果只是为了展示自动编码器的想法(在这里,您将其命名为 image 时只有 X、Y、Z 坐标),那么它的选择非常糟糕。

    别挡道:如果是图像,您将无法将其编码为单个像素,这需要更复杂一些。

    源代码

    这是一个简单的自动编码器,用于对 3 个维度为 1x3 的向量进行编码: [1,2,3],[1,2,3],[100,200,500] 到 1x1

    这仅在这种情况下是正确的,因为您有一批 3 元素(而您将网络命名为 batch out_features!)。它们的尺寸不是1x3,也只是3。这是带有评论的Minimal Reproducible Example

    import torch
    
    # Rows are batches, there could be 3, there could be a thousand
    data = torch.tensor([[1, 2, 3], [1, 2, 3], [100, 200, 500]]).float()
    
    # 3 input features, columns of data
    encoder = torch.nn.Sequential(torch.nn.Linear(3, 1), torch.nn.Sigmoid())
    decoder = torch.nn.Sequential(torch.nn.Linear(1, 3), torch.nn.Sigmoid())
    
    autoencoder = torch.nn.Sequential(encoder, decoder)
    
    optimizer = torch.optim.Adam(params=autoencoder.parameters(), lr=0.001)
    
    epochs = 10000
    
    for i in range(epochs):
        optimizer.zero_grad()
        reconstructions = autoencoder(data)
        loss = torch.dist(data, reconstructions)
        loss.backward()
        optimizer.step()
        # Print loss every 100 epoochs
        if i % 100 == 0:
            print(loss)
    

    它会起作用吗?

    这个更有趣。原则上,如果您的神经网络经过训练,您不必重新训练它以包含以前没有看到的示例(因为神经网络的目标是学习一些模式来解决任务)。

    在你的情况下不会。

    为什么它不起作用?

    首先,您在decoder 中激活了 sigmoid,它将输出限制在[0, 1] 范围内。您正在尝试预测超出此范围的数据,因此这是不可能的。

    如果不运行,我可以告诉你这个例子的损失是什么(所有权重都是+inf)。所有预测将始终为[1, 1, 1](或尽可能接近),因为该值对网络的惩罚最小,因此您只需计算数据中每个vector[1, 1, 1] 的距离。这里的损失停留在546.2719 附近。在 100000 个 epoch 之后,权重和偏差在 10 左右(这对于 sigmoid 来说是相当大的)。您的值可能会有所不同,但趋势很明显(尽管它会停止,因为当您使用 sigmoid 挤压它时,10 非常接近 1)。

    decoder 中删除 torch.nn.Sigmoid

    如果我们从decoder 中删除torch.nn.Sigmoid() 会怎样?它将学习几乎完美地重构仅您的 3 个示例,损失为“仅”500000 时期之后的0.002

    这是decoder的学习权重:

    tensor([[ 99.0000],
            [198.0000],
            [496.9999]], requires_grad=True)
    

    这里是bias

    tensor([1.0000, 2.0000, 2.9999])
    

    这里是每个示例的encoder 的输出:

    tensor([[2.2822e-13],
            [2.2822e-13],
            [1.0000e+00]])
    

    结果分析

    你的网络学到了你告诉它要学习的东西,即... ma​​gnitude(+聪明的biashackery)。

    [1, 2, 3] 向量

    [1, 2, 3] 为例(重复两次)。它的编码是2e-13并且趋近于零,所以我们假设它是零。

    现在,将0 与所有权重相乘,仍然得到零。添加bias,即[1.0, 2.0, 2.99999],然后你神奇地重建了输入。

    [100, 200, 500] 向量

    您可能会看到它的去向。

    编码值为1.0,当乘以decoder权重我们得到[99.0, 198.0, 497.0]。将bias 添加到其中,瞧,我们得到了[100.0, 200.0, 500.0]

    [1, 1, 1] 向量

    在您的情况下,它显然不起作用,因为 [1, 1, 1] 的幅度非常小,因此它将被编码为 zero 并重新构造为 [1, 2, 3]

    encoder 中删除 torch.nn.Sigmoid

    有点跑题了,但是当您从编码器中删除 sigmoid 时,它将无法“轻松”地学习这种模式。原因是网络必须对权重更加保守(因为这些权重不会被压扁)。您将不得不降低学习率(最好随着训练的进行不断降低它),因为它在某些时候变得不稳定(当试图达到“完美位置”时)。

    学习相似度

    在这种情况下,很难(至少对网络而言)定义“相似”。 [1, 2, 3] 是否类似于 [3, 2, 1]?它没有不同维度的概念,需要将这三个数字压缩成一个值(稍后用于重建)。

    正如演示的那样,它可能会在您的数据中学习一些隐式模式,以便擅长重构“至少某些东西”,但不会找到您正在寻找的一般模式。它仍然取决于您的数据及其属性,但我一般会反对,我认为它的泛化能力很差。

    正如您在上面的分析中所看到的,即使您没有看到这些模式(或者您可能看到了,这就是您所追求的?)或者它们不存在,神经网络也非常擅长发现它们完全没有。

    如果你需要维度相似性(这不仅仅是一个思想实验),你有很多“人造”的东西,比如p-normsome encodings(这些也可以衡量相似性,但以不同的方式)所以最好去那个 IMO。

    【讨论】:

      【解决方案2】:

      您的测试向量/特征 [1,1,1] 与输入的维度相同。因此可以通过神经网络来获得表示/编码。因此,不需要对参数或网络配置进行任何更改。


      它会忠实地工作吗?

      这是一个非常有趣的问题,答案是:“视情况而定”。很难保证仅从三个输入中学习一般相似性函数。

      您可能希望在与训练分布相似的数据上测试您的模型,即训练和测试数据应该非常相似。在上述情况下,虽然您可以使用经过训练的模型,但很难说它可以正常工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-02
        • 2021-04-03
        • 2021-01-29
        • 2021-05-10
        • 2017-09-03
        • 2020-06-01
        • 1970-01-01
        相关资源
        最近更新 更多