使用 pad_sequence

pad_sequence 是用来干嘛的?

首先 pad_sequence 是用来对对tensor做padding 的,先看官方示例:
文档地址https://pytorch.org/docs/stable/generated/torch.nn.utils.rnn.pad_sequence.html?highlight=pad_sequence#torch.nn.utils.rnn.pad_sequence

from torch.nn.utils.rnn import pad_sequence
a = torch.ones(25, 300)
b = torch.ones(22, 300)
c = torch.ones(15, 300)
pad_sequence([a, b, c]).size()
首先说应用场景

也就是说我们有了几个矩阵,除了第一个维度不一样,其他维度是一样的
常见的就是很多个sequence( length * embedding_dimension )
此时我们希望用做神经网络的input,但是input都是定长的,所以我们需要统一处理成定长的,以保证input layer
此时,我们需要将它们处理成各个维度都一样

遇到问题
10月22日

问题描述:

a = [[1,2,3,4,5],[1,1,1,1],[2,2,2]]
pad_sequence(a, batch_first = True, padding_value = 0 )
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_79801/829534548.py in <module>
      1 a = [[1,2,3,4,5],[1,1,1,1],[2,2,2]]
----> 2 pad_sequence(a, batch_first = True, padding_value = 0 )

~/anaconda3/envs/torch/lib/python3.8/site-packages/torch/nn/utils/rnn.py in pad_sequence(sequences, batch_first, padding_value)
    361     # assuming trailing dimensions and type of all the Tensors
    362     # in sequences are same and fetching those from sequences[0]
--> 363     return torch._C._nn.pad_sequence(sequences, batch_first, padding_value)
    364 
    365 

TypeError: expected Tensor as element 0 in argument 0, but got list

原因:我的矩阵是由数字组成的矩阵,也就是基本单元都是数字,但是,再高一层次(既是+2 也是-2 个维度)的数据类型是list,而不是数组。
解决:使用 torch.tensor() 对第二层的数据类型做一个类型转换,不适用list

a = [torch.tensor([1,2,3,4,5]),torch.tensor([1,1,1,1]),torch.tensor([2,2,2])]
pad_sequence(a, batch_first = True, padding_value = 0 )
tensor([[1, 2, 3, 4, 5],
        [1, 1, 1, 1, 0],
        [2, 2, 2, 0, 0]])
11月5日
问题:

使用pad_sequence 时,如果是对一个完整的数据集进行pad,那么操作很简单,但是计算的代价会很大。
比如,100 个sequence 组成的list,当其中只有一个是长度为1000 的,其余都是100,那么多pad的部分就高达99 X 900,
而总的有效部分才 99 X 100 + 1000 ,pad 部分比有效部分还多。

思路:

所以,应当基于一个batch 去做pad_sequence

预备知识

data,dataset,dataloader 的关系

  1. dataloader
    发现,训练使用的dataloader构建时,传入的是class Dataset 的实例,目标是从实例中sample出来一个个小的batch,这些batchs 被dataloader组成了一个list。
    注意,list组成单元类型要一样,但是组成单元的基本单元并不管,因为dataloader只负责给你返回batchs
    但是sample出来一个个小的batch 过程也是一条一条数据的从dataset 中获取的。

  2. class Dataset 作用是什么呢?
    pytorch 的class Dataset 有torch.utils.data.Dataset, torch.utils.data.IterableDataset 等,区别只是取出来一条数据的方式不同
    由于我使用的是torch.utils.data.Dataset,所以以此为例。
    Dataset 数据集嘛,所以其自身的变量里面是有一个大的数据单位。(强调一下,你自己怎么组织无所谓,字典也好,列表也好,数组也好,只要给你一下index 索引,你能够返回一条数据就行)
    看一下官方解释

CLASStorch.utils.data.Dataset(*args, **kwds)[SOURCE]
An abstract class representing a Dataset.
All datasets that represent a map from keys to data samples should subclass it. All subclasses should overwrite getitem(), supporting fetching a data sample for a given key. Subclasses could also optionally overwrite len(), which is expected to return the size of the dataset by many Sampler implementations and the default options of DataLoader.

就是你只要是通过继承torch.utils.data.Dataset构建自己的dataset,那么你一定要实现__getitem__()方法,而这个方法就是输入一个下标,返回一条数据。

  1. 重点部分dataloader 的一个参数 collate_fn

首先看一下说明:

collate_fn (callable, optional) – merges a list of samples to form a mini-batch of Tensor(s). Used when using batched loading from a map-style dataset.

也就是说在你从dataset 获取一个batch 数据后,你准备对这批数据怎么处理
我们基于batch 做pad_sequence其实就是通过这个参数指向的函数实现,所以我们实现一个这样的函数

def collate_func(batch):
    # print(batch)
    x_list = [dic['x'] for dic in batch]
    y_list = [dic['y'] for dic in batch]
    x_padded = pad_sequence(x_list, batch_first = True, padding_value = 0 )
    y_padded = pad_sequence(y_list, batch_first = True, padding_value = structrue_index_dict['X'] )
    # return tuple(x_padded, y_padded)
    return {'x':x_padded, 'y':y_padded}

就是刚才说的,输入的是一个batch ,batch是通过list 组织的,list 的基本单位dataloader 不在乎,只要你自己能够知道怎么取出来用就行了。
所以我返回的时候是一个字典,字典的key ‘x’ 是input 部分,key ‘y’ 对应的是 label。
也就是说,我这一个batch 组成单元是dict,但是dict的基本单元是torch的数组
我处理成一个字典,字典里面两个key,每个key是一个torch数组。
但是x_list 不等长,此处对这一个batch做pad_sequence,目的达到。

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值