【问题标题】:RuntimeError: mat1 and mat2 shapes cannot be multiplied (28x28 and 784x128)RuntimeError:mat1 和 mat2 形状不能相乘(28x28 和 784x128)
【发布时间】:2022-02-14 19:09:59
【问题描述】:

我正在尝试在添加了高斯噪声的 MNIST 数据集上使用自动编码器。我在嘈杂的 MNIST 数据集上使用了 DataLoader。添加噪声后,适用于原始 MNIST 数据集的模型不再适用。

gauss_train_loader = torch.utils.data.DataLoader(train_gauss, batch_size=BATCH_SIZE, shuffle=True, drop_last=DROP_LAST)
gauss_test_loader = torch.utils.data.DataLoader(test_gauss, batch_size=BATCH_SIZE, shuffle=True, drop_last=DROP_LAST)
# length = 150
class Autoencoder(nn.Module):
    def __init__(self):
        super(Autoencoder, self).__init__()
        self.encoder = nn.Sequential(
            nn.Linear(28 * 28, 128),
            nn.ReLU(inplace=True),
            nn.Linear(128, 64),
            nn.ReLU(inplace=True), 
            nn.Linear(64, 12), 
            nn.ReLU(inplace=True), 
            nn.Linear(12, 10))
        self.decoder = nn.Sequential(
            nn.Linear(10, 12),
            nn.ReLU(inplace=True),
            nn.Linear(12, 64),
            nn.ReLU(inplace=True),
            nn.Linear(64, 128),
            nn.ReLU(inplace=True), 
            nn.Linear(128, 28 * 28), 
            nn.Tanh())

    def forward(self, x):
        x = self.encoder(x)
        x = self.decoder(x)
        return x
def train(train_loader, model, criterion, optimizer, num_epochs):
    epoch_losses = []
    for epoch in trange(num_epochs):
        for data in gauss_train_loader:
            img = data[0].to(device) 
            #torch.size of img = [400,784] and of data[0] = [400,1,28,28]
            # We don't utilize the target data[1]
            img = img.view(img.size(0), -1)
            output = model(img)
            loss = criterion(output, img)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        loss_value = loss.item()
        epoch_losses.append(loss_value)
    return epoch_losses

# Train the autoencoder using the mnist train set
epoch_losses = train(gauss_train_loader, model, criterion, optimizer, NUM_EPOCHS)

我无法弄清楚原始数据集和嘈杂数据集之间的区别。或者如何调整自动编码器。

mnist_trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())
mnist_testset = datasets.MNIST(root='./data', train=False, download=True, transform=transforms.ToTensor())

def add_noise(dataset):
  noisy_data = []
  for data in dataset:
      img, _ = data[0], data[1]
      noisy_data += torch.tensor(random_noise(img, mode='gaussian', mean=0, var=0.05, clip=True))
  return noisy_data

train_gauss = add_noise(mnist_trainset)
test_gauss = add_noise(mnist_testset)

【问题讨论】:

  • 请添加Dataset 实现类。更准确地说,变量 train_gausstest_gauss 的创建位置。
  • 唯一有 28 x 28 形状的地方是模型的开头,所以我建议在 output = model(img) 之前打印img.shape。希望这能让您更深入地了解您的问题。
  • @meti 我已经为train_gausstest_gauss 添加了代码
  • @aretor 看来输入是三维的 [400,28,28] 然后在第一个 img [28,28] 之后(第二个之后相同)。它应该是四维的。使用原始数据集,在第一个 img 之后,形状为 [400,1,28,28],第二个为 [400,784]。
  • 我不确定问题是否与您的 random_noise 函数或数据集创建 add_noise 函数有关。我发布了一个针对后者的答案。

标签: python deep-learning neural-network pytorch autoencoder


【解决方案1】:

最简单的方法是扩展MNIST 数据集类。我对您的实现添加了一些微小的更改,并且成功了。

import torch
from torch import nn
from torchvision import datasets
from torchvision import transforms
from torch.optim import Adam
from PIL import Image
from typing import Optional

class Autoencoder(nn.Module):
    def __init__(self):
        super(Autoencoder, self).__init__()
        self.encoder = nn.Sequential(
            nn.Linear(28 * 28, 128),
            nn.ReLU(inplace=True),
            nn.Linear(128, 64),
            nn.ReLU(inplace=True), 
            nn.Linear(64, 12), 
            nn.ReLU(inplace=True), 
            nn.Linear(12, 10))
        self.decoder = nn.Sequential(
            nn.Linear(10, 12),
            nn.ReLU(inplace=True),
            nn.Linear(12, 64),
            nn.ReLU(inplace=True),
            nn.Linear(64, 128),
            nn.ReLU(inplace=True), 
            nn.Linear(128, 28 * 28), 
            nn.Tanh())

    def forward(self, x):
        x = self.encoder(x)
        x = self.decoder(x)
        return x

def train(train_loader, model, criterion, optimizer, num_epochs):
    epoch_losses = []
    for epoch in range(num_epochs):
        for data in train_loader:
            img = data[0].to(device) 
            img = img.view(img.size(0), -1)
            output = model(img)
            loss = criterion(output, img)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        loss_value = loss.item()
        epoch_losses.append(loss_value)
    return epoch_losses

class your_noisy_dataset(datasets.MNIST):
  def __getitem__(self, index: int):
        img, target = self.data[index], int(self.targets[index])
        img = Image.fromarray(img.numpy(), mode='L')
        if self.transform is not None:
            img = self.transform(img)
            img += torch.normal(0, 0.05, size=img.size())            
        if self.target_transform is not None:
            target = self.target_transform(target)
        return img, target

mnist_trainset = your_noisy_dataset(root='./data', train=True, download=True, transform=transforms.ToTensor())
mnist_testset = your_noisy_dataset(root='./data', train=False, download=True, transform=transforms.ToTensor())
model = Autoencoder()
criterion = nn.MSELoss()
optimizer = Adam(model.parameters(), lr=0.05)
device = torch.device("cpu")
epoch_losses = train(mnist_trainset, model, criterion, optimizer, 1)

__getitem__ 方法的主要区别在于它会返回一个图像加噪声掩码,而不是仅返回图像。 (read more about Dataset class)

【讨论】:

    【解决方案2】:

    您可以通过定义自己的RandomNoise transform 在线应用转换,而不是生成新数据集,如下所示:

    class RandomNoise(object):
        def __init__(self, mode="gaussian", mean, var, clip):
            self.mode = mode
            ...
    
       def __call__(self, image):
           image = random_noise(image, self.mode, self.mean, self.var, self.clip)
           return torch.tensor(image)
    

    然后你定义:

        t = transforms.Compose([transforms.ToTensor(), RandomNoise(0, 0.05)])
        train_gauss = datasets.MNIST(root, train=True, download=True, transform=t)
        val_gauss = ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-20
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 2021-09-17
      • 2022-01-19
      • 1970-01-01
      相关资源
      最近更新 更多