gpt4 book ai didi

python-3.x - RuntimeError : Given groups=3, 大小为 12 64 3 768 的权重,预期输入 [32, 12, 30, 768] 有 192 个 channel ,但得到了 12 个 channel

转载 作者:行者123 更新时间:2023-12-04 09:46:10 25 4
gpt4 key购买 nike

我最近开始使用 Pytorch,所以我对它的理解不是很强烈。我以前有一个 1 层 CNN,但想将其扩展到 2 层,但输入和输出 channel 一直在抛出我似乎可以破译的错误。为什么它需要 192 个 channel ?有人可以给我一个指针来帮助我更好地理解这一点吗?我在这里看到了几个相关的问题,但我也不理解这些解决方案。

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from transformers import BertConfig, BertModel, BertTokenizer
import math
from transformers import AdamW, get_linear_schedule_with_warmup


def pad_sents(sents, pad_token): # Pad list of sentences according to the longest sentence in the batch.
sents_padded = []
max_len = max(len(s) for s in sents)
for s in sents:
padded = [pad_token] * max_len
padded[:len(s)] = s
sents_padded.append(padded)
return sents_padded


def sents_to_tensor(tokenizer, sents, device):
tokens_list = [tokenizer.tokenize(str(sent)) for sent in sents]
sents_lengths = [len(tokens) for tokens in tokens_list]
tokens_list_padded = pad_sents(tokens_list, '[PAD]')
sents_lengths = torch.tensor(sents_lengths, device=device)
masks = []
for tokens in tokens_list_padded:
mask = [0 if token == '[PAD]' else 1 for token in tokens]
masks.append(mask)
masks_tensor = torch.tensor(masks, dtype=torch.long, device=device)
tokens_id_list = [tokenizer.convert_tokens_to_ids(tokens) for tokens in tokens_list_padded]
sents_tensor = torch.tensor(tokens_id_list, dtype=torch.long, device=device)

return sents_tensor, masks_tensor, sents_lengths


class ConvModel(nn.Module):

def __init__(self, device, dropout_rate, n_class, out_channel=16):
super(ConvModel, self).__init__()
self.bert_config = BertConfig.from_pretrained('bert-base-uncased', output_hidden_states=True)
self.dropout_rate = dropout_rate
self.n_class = n_class
self.out_channel = out_channel
self.bert = BertModel.from_pretrained('bert-base-uncased', config=self.bert_config)
self.out_channels = self.bert.config.num_hidden_layers * self.out_channel
self.tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', config=self.bert_config)
self.conv = nn.Conv2d(in_channels=self.bert.config.num_hidden_layers,
out_channels=self.out_channels,
kernel_size=(3, self.bert.config.hidden_size),
groups=self.bert.config.num_hidden_layers)
self.conv1 = nn.Conv2d(in_channels=self.out_channels,
out_channels=48,
kernel_size=(3, self.bert.config.hidden_size),
groups=self.bert.config.num_hidden_layers)
self.hidden_to_softmax = nn.Linear(self.out_channels, self.n_class, bias=True)
self.dropout = nn.Dropout(p=self.dropout_rate)
self.device = device

def forward(self, sents):
sents_tensor, masks_tensor, sents_lengths = sents_to_tensor(self.tokenizer, sents, self.device)
encoded_layers = self.bert(input_ids=sents_tensor, attention_mask=masks_tensor)
hidden_encoded_layer = encoded_layers[2]
hidden_encoded_layer = hidden_encoded_layer[0]
hidden_encoded_layer = torch.unsqueeze(hidden_encoded_layer, dim=1)
hidden_encoded_layer = hidden_encoded_layer.repeat(1, 12, 1, 1)
conv_out = self.conv(hidden_encoded_layer) # (batch_size, channel_out, some_length, 1)
conv_out = self.conv1(conv_out)
conv_out = torch.squeeze(conv_out, dim=3) # (batch_size, channel_out, some_length)
conv_out, _ = torch.max(conv_out, dim=2) # (batch_size, channel_out)
pre_softmax = self.hidden_to_softmax(conv_out)

return pre_softmax


def batch_iter(data, batch_size, shuffle=False, bert=None):
batch_num = math.ceil(data.shape[0] / batch_size)
index_array = list(range(data.shape[0]))
if shuffle:
data = data.sample(frac=1)
for i in range(batch_num):
indices = index_array[i * batch_size: (i + 1) * batch_size]
examples = data.iloc[indices]
sents = list(examples.train_BERT_tweet)
targets = list(examples.train_label.values)
yield sents, targets # list[list[str]] if not bert else list[str], list[int]


def train():
label_name = ['Yes', 'Maybe', 'No']
device = torch.device("cpu")

df_train = pd.read_csv('trainn.csv') # , index_col=0)
train_label = dict(df_train.train_label.value_counts())
label_max = float(max(train_label.values()))
train_label_weight = torch.tensor([label_max / train_label[i] for i in range(len(train_label))], device=device)
model = ConvModel(device=device, dropout_rate=0.2, n_class=len(label_name))
optimizer = AdamW(model.parameters(), lr=1e-3, correct_bias=False)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=100, num_training_steps=1000) # changed the last 2 arguments to old ones
model = model.to(device)
model.train()
cn_loss = torch.nn.CrossEntropyLoss(weight=train_label_weight, reduction='mean')
train_batch_size = 16

for epoch in range(1):

for sents, targets in batch_iter(df_train, batch_size=train_batch_size, shuffle=True): # for each epoch
optimizer.zero_grad()
pre_softmax = model(sents)
loss = cn_loss(pre_softmax, torch.tensor(targets, dtype=torch.long, device=device))
loss.backward()
optimizer.step()
scheduler.step()
TrainingModel = train()


这是数据片段 https://github.com/Kosisochi/DataSnippet

最佳答案

您在这个问题中的原始代码版本似乎表现不同。你在这里的代码的最终版本给了我一个与你发布的不同的错误,更具体地说 - 这个:

RuntimeError: Calculated padded input size per channel: (20 x 1). Kernel size: (3 x 768). Kernel size can't be greater than actual input size

如果我误解了这种情况,我深表歉意,但在我看来,您对 nn.Conv2d 层的确切功能的理解并不是 100% 清楚,这是您挣扎的主要来源。我将您要求的“Pytorch 中 2 层 CNN 的详细解释”部分解释为详细解释该层的工作原理,我希望在完成此操作后,应用 1 次、2 次或更多次不会有问题.

您可以找到有关图层 here 的所有文档。 ,但让我给你一个回顾,希望能帮助你更多地了解你遇到的错误。
首先 nn.Conv2d输入是形状为 (BatchSize, ChannelsIn, Height, Width) 的 4 维张量输出是形状为 (BatchSize, ChannelsOut, HeightOut, WidthOut) 的 4 维张量.最简单的思考方式 nn.Conv2d适用于像素网格大小为 Height x Width 的二维图像并拥有 ChannelsIn每个像素有不同的颜色或特征。即使您的输入与实际图像无关,图层的行为仍然相同。最简单的情况是当 nn.Conv2d不使用填充(如在您的代码中)。在这种情况下, kernel_size=(kernel_height, kernel_width)参数指定您可以想象扫过的矩形 Height x Width输入的矩形并为每个有效位置生成一个像素。无需填充矩形点的坐标可以是任何一对索引 (x, y) x 介于 0 之间和 Height - kernel_height和 y 之间 0Width - kernel_width .因此,输出看起来像一个大小为 (Height - kernel_height + 1) x (Width - kernel_width + 1) 的二维图像。并且将具有为 nn.Conv2d 指定的尽可能多的输出 channel 构造函数,因此输出张量的形状为 (BatchSize, ChannelsOut, Height - kernel_height + 1, Width - kernel_width + 1) .

参数 groups不影响层如何改变形状 - 它只控制哪些输入 channel 用作输出 channel 的输入( groups=1 表示每个输入 channel 用作每个输出 channel 的输入,否则输入和输出 channel 是分成相应数量的组,只有来自组 i 的输入 channel 用作组 i 的输出 channel 的输入)。

现在,在您当前版本的代码中,您的 BatchSize = 16 并且预训练模型的输出为 (BatchSize, DynamicSize, 768)DynamicSize取决于输入,例如22. 然后使用 unsqueeze 引入附加维度作为轴 1并重复沿该维度的值转换形状张量 (16, 22, 768)进入 (16, 12, 22, 768) .实际上,您将预训练模型的输出用作 12 channel (每个 channel 具有与其他通​​道相同的值)此处大小为 (22, 768) 的二维图像,其中 22 不固定(取决于批次)。然后应用内核大小为 (3, 768) 的 nn.Conv2d - 这意味着宽度没有“摆动空间”,输出的二维图像的大小为 (20, 1)并且由于您的层有 192 个 channel ,因此第一个卷积层的输出最终大小具有形状 (16, 192, 20, 1) .然后你尝试在内核大小 (3, 768) 之上应用第二层卷积。再次,但由于您的二维“图像”现在只是(20 x 1),因此没有适合的有效位置 (3, 768)矩形内的内核矩形 (20 x 1)这会导致错误消息 Kernel size can't be greater than actual input size .

希望这个解释有帮助。现在是你必须避免这个问题的选择:
  • (a) 是以这样一种方式添加填充,即输出的大小与输入相比不会改变(我不会在这里详细介绍,
    因为我认为这不是您需要的)
  • (b) 在第一次和/或第二次卷积上使用较小的内核(例如,如果您不更改第一次卷积,则唯一有效的宽度
    第二个内核是 1 )。
  • (c) 看看你想要做什么,我的猜测是你实际上不想使用 2d 卷积,你想要 1d 卷积(在序列上),每个位置由 768 个值描述。当您使用一个具有 768 宽度内核(和相同的 768 宽度输入)的卷积层时,您实际上与具有 768 个输入 channel 的 1d 卷积完全相同,但是如果您尝试应用第二个,则会遇到问题。您可以将内核宽度指定为 1对于下一层,这对您有用,但更正确的方法是通过切换最后一个维度来转置预训练模型的输出张量 - 获得形状 (16, 768, DynamicSize)来自 (16, DynamicSize, 768)然后应用具有 768 个输入 channel 和任意 ChannelsOut 的 nn.Conv1d 层作为输出 channel 和 1d kernel_size=3 (意味着您查看卷积序列的 3 个连续元素)。如果你这样做而不是不填充 (16, 768, DynamicSize) 的输入形状会变成(16, ChannelsOut, DynamicSize-2) ,并在您应用第二个 Conv1d 之后,例如与第一个相同的设置,您将获得形状张量 (16, ChannelsOut, DynamicSize-4)等(每次一维长度都会缩小 kernel_size-1 )。您也可以随时更改每个后续卷积层的 channel 数/kernel_size。
  • 关于python-3.x - RuntimeError : Given groups=3, 大小为 12 64 3 768 的权重,预期输入 [32, 12, 30, 768] 有 192 个 channel ,但得到了 12 个 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62099558/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com