pytorchDataLoader中调整数据长度不一致问题(lstm等)

数据长度不一致

用pytorch做rnn的时候,如果输入数据不一样长,可以用两种方式解决。
一种是自定义collate方法,

#自定义collate_fn
dataloader.DataLoader(dataset,4,True,collate_fn=my_collate)

然后里面写数据和标签载入方式即可

def my_collate(batch):
    data = [item[0] for item in batch]
    target = [item[1] for item in batch]
    return [data, target]

第二种方式使用

压缩:nn.utils.rnn.pack_padded_sequence
解压是 这个pad_packed_sequence

核心思想是对padding补充过的数据进行压缩,这种方式可以加速运算在大数据集中效果较好
(原理是把数据中为0的padding给压缩掉,进入RNN计算的时候直接跳过输出0)

当你拿到长短不一致的数据的时候
第一步自然是PADDING,无论什么框架都一样,自己手写一个就行了

def custompad(X,max_len=10):
    X = torch.Tensor(X)
    m=X.shape[0]
    pad = torch.zeros(1,50)
    for i in range(max_len-m):
        X = torch.cat([X,pad],dim=0)
    return X

这样比如我的数据是[a,b,c][d,e] 输出来就是[a,b,c,0…][d,e,0…]
这样保持固定步长序列的数据
这时候可以直接丢rnn跑了
但是如果我的神经网络要求的是输入最后一层的数据,怎么办?
直接进行压缩!

from torch.nn.utils.rnn import pack_padded_sequence as pack, pad_packed_sequence as unpack
## 这里我把压缩写进了collate方法里,这样dataloader取的时候就直接拿压缩数据了
def my_collate(batch):
    data = torch.stack([item[0] for item in batch])
    lens = [item[1] for item in batch]
    ## 重点,压缩! 如果不排序enforce要false
    res = pack(data,lens,batch_first=True,enforce_sorted=False)
    target = [item[2] for item in batch]
    target = torch.LongTensor(target)
    return [res, target]
#我的dataset 可以作为参考
class traindata(Dataset):
    def __init__(self) -> None:
        super().__init__()
        X, self.Y = read_csv('data/train_emoji.csv')
        self.X,self.lens=sentence_to_avg(X,word_to_vec_map)
        
    def __getitem__(self, index):
        return self.X[index],self.lens[index],self.Y[index]

    def __len__(self):
        return self.X.shape[0]

这样写完 我每次拿数据就是取的压缩数据
注意压缩数据是2维的 第二维是lenth(重要**) 因为这个length可以帮我们取最后一层计算数据
举个例子:
我的输入是[a,b],padding完是[a,b,0,0]
压缩后进入lstm,再解压出来
这时候的输出可能是[1,2,0,0]
也就是说,padding为0的地方是没有进入rnn循环的,也就是只循环了2次
所以这里需要拿到最后一个输出的数据2
就要用到上面那个方法了

直接看代码比较快:

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.lstm = nn.LSTM(50,64,1)
        self.dense = nn.Linear(64,256)
        self.fc = nn.Linear(256,5)

    def forward(self,x,h=None,c=None):
        hp=(h,c) if h!=None and c!=None else None
        x,hid = self.lstm(x,hp)
        x = unpack(x,batch_first=True)
        ## 注意看这里 进入全连接层之前 我要取得压缩数据,并且是最后一维的输出
        ##所以要过滤掉0的输出
        seq_len_indices = [length - 1 for length in x[1]]
        batch_indices = [i for i in range(x[0].shape[0])]
        final_output = x[0][batch_indices, seq_len_indices, :]
        x = F.relu(self.dense(final_output))
        return self.fc(x)

你可能感兴趣的:(python,pytorch,深度学习,lstm,pytorch,python)