无法获得正确的尺寸 - 用于文本分类的 CNN

Can't get dimensions right - CNN for text classification

这是我的 CNN class:

class CNN(nn.Module):
    def __init__(
        self,
        vocab_size,
        emb_dim,
        out_channels,
        kernel_sizes,
        dropout,
    ):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, emb_dim)
        self.conv_0 = nn.Conv2d(in_channels=1, out_channels=out_channels, kernel_size=(kernel_sizes[0], emb_dim), 2)
        
        self.conv_1 = nn.Conv2d(in_channels=1, out_channels=out_channels, kernel_size=(kernel_sizes[1], emb_dim), 2)
        
        self.conv_2 = nn.Conv2d(in_channels=1, out_channels=out_channels, kernel_size=(kernel_sizes[2], emb_dim), 2)
        
        self.fc = nn.Linear(len(kernel_sizes) * out_channels, 1)
        
        self.dropout = nn.Dropout(dropout)

        
        
    def forward(self, text):
        
        embedded = self.embedding(text)
        print('embedded', embedded.shape)
        embedded = embedded.unsqueeze(1)  # may be reshape here
        print('embedded', embedded.shape)

        conved_0 = F.relu(self.conv_0(embedded)).squeeze(3)  # may be reshape here
        print('conved_0', conved_0.shape)
        conved_1 = F.relu(self.conv_1(embedded)).squeeze(3)  # may be reshape here
        print('conved_1', conved_1.shape)
        conved_2 = F.relu(self.conv_2(embedded)).squeeze(3)  # may be reshape here
        print('conved_2', conved_2.shape)
        
        pooled_0 = F.max_pool1d(conved_0, conved_0.shape[2]).squeeze(2)
        print('pooled_0', pooled_0.shape)
        pooled_1 = F.max_pool1d(conved_1, conved_1.shape[2]).squeeze(2)
        print('pooled_1', pooled_1.shape)
        pooled_2 = F.max_pool1d(conved_2, conved_2.shape[2]).squeeze(2)
        print('pooled_2', pooled_2.shape)
        
        cat = self.dropout(torch.cat((pooled_0, pooled_1, pooled_2), dim=1))
        print('cat', cat.shape)
            
        return self.fc(cat)

变量:

kernel_sizes = [3, 4, 5]
vocab_size = len(TEXT.vocab)
out_channels = 64
dropout = 0.2
dim = 300

model = CNN(vocab_size=vocab_size, emb_dim=dim, out_channels=out_channels,
            kernel_sizes=kernel_sizes, dropout=dropout)

和培训:

import numpy as np

min_loss = np.inf

cur_patience = 0

for epoch in range(1, max_epochs + 1):
    train_loss = 0.0
    model.train()
    pbar = tqdm(enumerate(train_iter), total=len(train_iter), leave=False)
    pbar.set_description(f"Epoch {epoch}")
    for it, batch in pbar: 
        #YOUR CODE GOES HERE
        opt.zero_grad()
        input = batch.text[0].to(device)
        output = model(input)
        train_loss = loss_func(output, batch.label)
        train_loss.backward()
        opt.step()
        

    train_loss /= len(train_iter)
    val_loss = 0.0
    model.eval()
    pbar = tqdm(enumerate(valid_iter), total=len(valid_iter), leave=False)
    pbar.set_description(f"Epoch {epoch}")
    for it, batch in pbar:
        # YOUR CODE GOES HERE
        input = batch.text[0].to(device)
        output = model(input)
        val_loss = loss_fn(output, batch.label)

    val_loss /= len(valid_iter)
    if val_loss < min_loss:
        min_loss = val_loss
        best_model = model.state_dict()
    else:
        cur_patience += 1
        if cur_patience == patience:
            cur_patience = 0
            break
    
    print('Epoch: {}, Training Loss: {}, Validation Loss: {}'.format(epoch, train_loss, val_loss))
model.load_state_dict(best_model)

我收到这个错误:

RuntimeError: Expected 4-dimensional input for 4-dimensional weight [64, 1, 3, 300], but got 3-dimensional input of size [894, 1, 300] instead

在这一行中:

---> 32 conved_0 = F.relu(self.conv_0(embedded)).squeeze(3)

我试过使用 Conv1d,但在尺寸方面仍然存在问题。有人可以解释一下我应该在这里修复什么来训练网络吗?


编辑:

This is my class but with Conv1d:

class CNN(nn.Module):

    def __init__(
        self,
        vocab_size,
        emb_dim,
        out_channels,
        kernel_sizes,
        dropout,
    ):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, emb_dim)
        self.conv_0 = nn.Conv1d(in_channels=1, out_channels=out_channels, kernel_size=kernel_sizes[0])
        
        self.conv_1 = nn.Conv1d(in_channels=1, out_channels=out_channels, kernel_size=kernel_sizes[1])
        
        self.conv_2 = nn.Conv1d(in_channels=1, out_channels=out_channels, kernel_size=kernel_sizes[2])
        
        self.fc = nn.Linear(len(kernel_sizes) * out_channels, 1)
        
        self.dropout = nn.Dropout(dropout)

        
        
    def forward(self, text):
        
        embedded = self.embedding(text)
        print('embedded', embedded.shape)
        embedded = embedded.unsqueeze(1)  # may be reshape here
        print('embedded', embedded.shape)

        conved_0 = F.relu(self.conv_0(embedded))  # may be reshape here
        print('conved_0', conved_0.shape)
        conved_1 = F.relu(self.conv_1(embedded))  # may be reshape here
        print('conved_1', conved_1.shape)
        conved_2 = F.relu(self.conv_2(embedded))  # may be reshape here
        print('conved_2', conved_2.shape)
        
        pooled_0 = F.max_pool1d(conved_0, conved_0.shape[2]).squeeze(2)
        print('pooled_0', pooled_0.shape)
        pooled_1 = F.max_pool1d(conved_1, conved_1.shape[2]).squeeze(2)
        print('pooled_1', pooled_1.shape)
        pooled_2 = F.max_pool1d(conved_2, conved_2.shape[2]).squeeze(2)
        print('pooled_2', pooled_2.shape)
        
        cat = self.dropout(torch.cat((pooled_0, pooled_1, pooled_2), dim=1))
        print('cat', cat.shape)
            
        return self.fc(cat)

维度输出:

embedded torch.Size([1115, 300])
embedded torch.Size([1115, 1, 300])
conved_0 torch.Size([1115, 64, 298])
conved_1 torch.Size([1115, 64, 297])
conved_2 torch.Size([1115, 64, 296])
pooled_0 torch.Size([1115, 64])
pooled_1 torch.Size([1115, 64])
pooled_2 torch.Size([1115, 64])
cat torch.Size([1115, 192])

错误:

ValueError: Target size (torch.Size([128])) must be the same as input size (torch.Size([1115, 1]))

我缺少的是我将 batch_first 参数设置为 True,其中 SWAPED batch_sizeseq_len。将其设置为 False 后,一切正常。