PyTorch 一维 CNN 问题

PyTorch 1D CNN Problems

我在 PyTorch 中实现 1D CNN 时遇到了很多麻烦。这个想法是我们使用 xTrainVar 来预测 yTrainVar,并使用 xTestVar 来预测 yTestVar。时间序列。

这一行:

pred = prod_outputs(train_loader, model)

在这里创建一个问题:

_, predictions = torch.max(scores, 1)

导致此错误:

IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)

通常我不会转储完整的代码库,但我就是看不到我的错误,所以这里是:

#################################
# Load the libraries
#################################
import torch
import torchvision
import torch.nn.functional as F
import torchvision.datasets as datasets
import torchvision.transforms as transforms
from torch import optim
from torch import nn
from torch.utils.data import DataLoader 
from tqdm import tqdm 

from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
import numpy as np
import torch.utils.data as data_utils


#################################
# Prepare the data
#################################
xTrainVar = [[8.1,4.1,4.1,4.3], [3.9, 3.8, 3.9, 3.7], [3.8, 3.7, 3.8, 3.8], [3.9, 3.8, 4.1, 4.4]]
yTrainVar = [3.9, 3.8, 3.9, 4.4]
xTestVar = [[8.1,4.1,4.1,4.3], [3.9, 3.8, 3.9, 3.7], [3.8, 3.7, 3.8, 3.8], [3.9, 3.8, 4.1, 4.4],[3.9, 3.8, 4.1, 4.4]]
yTestVar = [3.9, 3.8, 3.9, 4.4, 4.4]

# Convert to Tensors
# Prepare training data
train_data = torch.tensor(np.array(xTrainVar, dtype=np.float32))
train_target = torch.tensor(np.array(yTrainVar, dtype=np.float32))

train_data = train_data.unsqueeze(1)  # try to get the right shape [4,1,4]

# Reshape the data to be in line with the other shape
new_shape = (len(yTrainVar), 1, 1) # There used to be another ,1 here
train_target = train_target.view(new_shape)
                                     
train_tensor = data_utils.TensorDataset(train_data, train_target)
train_loader = data_utils.DataLoader(dataset=train_tensor, batch_size=32,shuffle=False)

# Prepare test data
test_data = torch.tensor(np.array(xTestVar, dtype=np.float32))
test_target = torch.tensor(np.array(yTestVar, dtype=np.float32))

test_data = test_data.unsqueeze(1) # try to get the right shape [5,1,4]

# Reshape the data to be in line with the other shape
new_shape = (len(yTestVar), 1,1)
test_target = test_target.view(new_shape)

test_tensor = data_utils.TensorDataset(test_data, test_target)
test_loader = data_utils.DataLoader(dataset=test_tensor, batch_size=32)

class NN(nn.Module):
    def __init__(self, input_size, num_classes):
        super(NN, self).__init__()
        self.conv1d = nn.Conv1d(in_channels=1, out_channels=4, kernel_size=4, stride=1, padding=0)
        self.relu = nn.ReLU(inplace=True)
        self.fc1 = nn.Linear(16,50)
        self.fc2 = nn.Linear(50,1).

    def forward(self, x): 
        x = self.conv1d(x)
        x = self.relu(x)
        x = x.view(-1)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x


# Set the hyperparameters
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
input_size = 1*4
num_classes = 1
learning_rate = 0.001
batch_size = 64
num_epochs = 1

model = NN(input_size=input_size, num_classes=num_classes).to(device)

criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)


#################################
# Train model using training data
#################################
for epoch in range(num_epochs):
    # Fit the model to the training data
    for batch_idx, (data, targets) in enumerate(tqdm(train_loader)):
        # Get data to cuda if possible
        data = data.to(device=device)
        targets = targets.to(device=device)
        
        # forward
        scores = model(data)
        loss = criterion(scores, targets)

        # backward
        optimizer.zero_grad()
        loss.backward()

        # gradient descent or adam step
        optimizer.step()


def prod_outputs(loader, model):
    model.eval() # Place the model into evaluation mode.

    with torch.no_grad():
        for x, y in loader:
            x = x.to(device=device)
            y = y.to(device=device)
            scores = model(x)
            _, predictions = scores.max(1)
            print(predictions)
    model.train() # Return the model to training mode once we are done.
    return scores # This used to be predictions


#################################
# Evaluate the model
#################################
# This is where I am up to with the work.
pred = prod_outputs(train_loader, model) # Use train dependent variable (x) to generate predictions of independent variable (y)
pred = pred.numpy()

你需要退一步审视形势:

  • 您有一个 (bs, c, w) 形如 (4, 1, 4) 的输入。因此,单个通道的批量大小为 4,长度为 4。通过卷积层,这变成 (bs, 4, 1) 因为内核大小是 (4,),每个通道基本上只有一个值。

  • 在应用使整个张量变平的重塑之后,这通常不是一个好主意。因为您实际上是将批处理元素压平在一起。相反,您应该 将它们分开。您可以为此使用 nn.Flatten。例如,在 __init__ 中设置 self.flatten = nn.Flatten(),然后在正向定义中使用 x = self.flatten(x) 而不是 x = x.view(-1)

  • 这就是说,除第一个轴(批次轴)外的扁平化将导致形状为 (4, 4) 的张量。所以,最终你的第一个密集层应该有相应数量的神经元, 4。类似于 self.fc1 = nn.Linear(4, 50).

不要认为这是理所当然的,我是在解释你的代码中有什么问题,而不是给你一个可以坚持的架构。我为您提供的修改将 运行,不保证它会 train... 这是另一天的问题!