语言模型的随机采样和相邻采样

自然语言数据可以看成一种特殊的时间序列数据。对于这种时序数据的采样主要有有随机采样和相邻采样两种方式。两者都需要确定一个batch的样本数量batch_size和每个样本的时间步长num_steps。

随机采样

步骤:语料库corpus_indices的长度为 n n n,首先按照时间步长确定可能的样本的起始索引,可能的样本起始索引最后被随机打散。这里注意:采样的单个样本的最后一个单词不可能是序列的最后一个字(否则,就没有输入子序列所对应的输出子序列)

num_examples = (len(corpus_indices) - 1) // num_steps  
#下取整,得到不重叠情况下的样本个数
print("num_examples:"+str(num_examples))
example_indices = [i * num_steps for i in range(num_examples)]  
#每个样本的第一个字符在corpus_indices中的下标
random.shuffle(example_indices)

如图所示:对于一个长度为32序列0,1,2,…,31,时间步长取4,batch大小取3时,有效长度只有28。
在这里插入图片描述
这里的随机化是指单个batch内部的样本是随机抽取的,在一个batch内部如果起始索引相邻则样本可能相邻。值得注意的是,相邻的两个batch在原始序列上不一定相邻。取决于起始索引被随机化的情况

import torch
import random
def data_iter_random(corpus_indices, batch_size, num_steps, device=None):
    # 减1是因为对于长度为n的序列,X最多只有包含其中的前n - 1个字符
    num_examples = (len(corpus_indices) - 1) // num_steps  # 下取整,得到不重叠情况下的样本个数
    print("num_examples:"+str(num_examples))
    example_indices = [i * num_steps for i in range(num_examples)]  # 每个样本的第一个字符在corpus_indices中的下标
    random.shuffle(example_indices)
    print("example_indices"+str(example_indices))
    def _data(i):
        # 返回从i开始的长为num_steps的序列
        return corpus_indices[i: i + num_steps]
    if device is None:
        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    
    for i in range(0, num_examples, batch_size):  #迭代使得采样不重不漏
        # 每次选出batch_size个随机样本
        print(i)
        batch_indices = example_indices[i: i + batch_size]  # 当前batch的各个样本的首字符的下标
        print("batch_indices: "+str(batch_indices))
        X = [_data(j) for j in batch_indices]
        Y = [_data(j + 1) for j in batch_indices]
        yield torch.tensor(X, device=device), torch.tensor(Y, device=device)

相邻采样

在相邻采样中,相邻的两个随机小批量在原始序列上的位置相毗邻。

先确定待采样的有效序列的长度,在按照batch_size对该有效序列进行均分,然后按照时间步长num_step对堆叠的子序列进行逐个采样。

corpus_len = len(corpus_indices) // batch_size * batch_size
corpus_indices = corpus_indices[: corpus_len]  # 仅保留前corpus_len个字符

如图所示,一个框里的就是一个batch里的多个样本:

在这里插入图片描述

完整代码如下:

def data_iter_consecutive(corpus_indices, batch_size, num_steps, device=None):
    if device is None:
        device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    corpus_len = len(corpus_indices) // batch_size * batch_size  # 保留下来的序列的长度
    corpus_indices = corpus_indices[: corpus_len]  # 仅保留前corpus_len个字符
    indices = torch.tensor(corpus_indices, device=device)
    indices = indices.view(batch_size, -1)  # resize成(batch_size, )
    batch_num = (indices.shape[1] - 1) // num_steps
    for i in range(batch_num):
        i = i * num_steps
        X = indices[:, i: i + num_steps]
        Y = indices[:, i + 1: i + num_steps + 1]
        yield X, Y

容易发现,一个batch内部样本是不邻接的,但是相邻batch里对应位置的样本一定是邻接的

相邻采样的样本一个batch一个batch的输入是符合语言的前后依赖这一事实的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值