循环神经网络中的采样问题

在构建循环神经网络时,首先需要处理数据集。接下来需要读取数据,对其进行合理采样,即将数据集划分为若干子序列。采样后的数据进行one-hot编码后,即可输入循环神经网络进行学习。

数据集的采样主要分为两种方法,随机采样和顺序分区,接下来依次进行介绍。(本文基于mxnet框架构建,使用Time Machine数据集)

随机采样

随机采样只有每个批量内部一个时间步长度的值是顺序分布的。为更好的了解采样的代码,我们首先解释用到的各种参数。

参数说明

  • num_steps:时间步,即生成的每个序列连续多少个值。
  • batch_size:批量大小,即生成多少批数据
  • corpus:全体语料
  • num_subseqs:生成子列数量(特征-标签对)

函数说明

  • random.shuffle(),标准类库方法,用于将内容打乱。
def seq_data_iter_random(corpus, batch_size, num_steps):  #@save
    """使用随机抽样生成一个小批量子序列"""
    # 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1
    corpus = corpus[random.randint(0, num_steps - 1):]
    # 减去1,是因为我们需要考虑标签
    num_subseqs = (len(corpus) - 1) // num_steps
    # 长度为num_steps的子序列的起始索引
    initial_indices = list(range(0, num_subseqs * num_steps, num_steps))
    # 在随机抽样的迭代过程中,
    # 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻
    random.shuffle(initial_indices)

    def data(pos):
        # 返回从pos位置开始的长度为num_steps的序列
        return corpus[pos: pos + num_steps]

    num_batches = num_subseqs // batch_size
    for i in range(0, batch_size * num_batches, batch_size):
        # 在这里,initial_indices包含子序列的随机起始索引
        initial_indices_per_batch = initial_indices[i: i + batch_size]
        X = [data(j) for j in initial_indices_per_batch]
        Y = [data(j + 1) for j in initial_indices_per_batch]
        yield np.array(X), np.array(Y)

下面我们生成一个从0到34的序列。 假设批量大小为2,时间步数为5,这意味着可以生成 ⌊(35−1)/5⌋=6个“特征-标签”子序列对。 如果设置小批量大小为2,我们只能得到3个小批量。

my_seq = list(range(35))
for X, Y in seq_data_iter_random(my_seq, batch_size=2, num_steps=5):
    print('X: ', X, '\nY:', Y)

运行结果如下:共生成三个小批量,每个批量有两批数据(X的第一维度大小为2)

X:  [[22. 23. 24. 25. 26.]
 [27. 28. 29. 30. 31.]]
Y: [[23. 24. 25. 26. 27.]
 [28. 29. 30. 31. 32.]]
X:  [[ 7.  8.  9. 10. 11.]
 [12. 13. 14. 15. 16.]]
Y: [[ 8.  9. 10. 11. 12.]
 [13. 14. 15. 16. 17.]]
X:  [[17. 18. 19. 20. 21.]
 [ 2.  3.  4.  5.  6.]]
Y: [[18. 19. 20. 21. 22.]
 [ 3.  4.  5.  6.  7.]]
[07:06:42] ../src/storage/storage.cc:196: Using Pooled (Naive) StorageManager for CPU

顺序分区

顺序分区保证了同一批量的数据是连续的,而不同批的数据之间是无序的。

顺序分区将数据集简单的分割为一个shape(0)=batch_size的多维数组。

def seq_data_iter_sequential(corpus, batch_size, num_steps):  #@save
    """使用顺序分区生成一个小批量子序列"""
    # 从随机偏移量开始划分序列
    offset = random.randint(0, num_steps)
    num_tokens = ((len(corpus) - offset - 1) // batch_size) * batch_size
    Xs = np.array(corpus[offset: offset + num_tokens])
    Ys = np.array(corpus[offset + 1: offset + 1 + num_tokens])
    Xs, Ys = Xs.reshape(batch_size, -1), Ys.reshape(batch_size, -1)
    num_batches = Xs.shape[1] // num_steps
    for i in range(0, num_steps * num_batches, num_steps):
        X = Xs[:, i: i + num_steps]
        Y = Ys[:, i: i + num_steps]
        yield X, Y

测试输出结果: 

for X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):
    print('X: ', X, '\nY:', Y)

输出结果如下:

X:  [[ 0.  1.  2.  3.  4.]
 [17. 18. 19. 20. 21.]]
Y: [[ 1.  2.  3.  4.  5.]
 [18. 19. 20. 21. 22.]]
X:  [[ 5.  6.  7.  8.  9.]
 [22. 23. 24. 25. 26.]]
Y: [[ 6.  7.  8.  9. 10.]
 [23. 24. 25. 26. 27.]]
X:  [[10. 11. 12. 13. 14.]
 [27. 28. 29. 30. 31.]]
Y: [[11. 12. 13. 14. 15.]
 [28. 29. 30. 31. 32.]]

 包装使用

将两种采样包装为统一的类,使用load_data_time_machine()函数来直接对数据集进行采样。

class SeqDataLoader:  #@save
    """加载序列数据的迭代器"""
    def __init__(self, batch_size, num_steps, use_random_iter, max_tokens):
        if use_random_iter:
            self.data_iter_fn = d2l.seq_data_iter_random
        else:
            self.data_iter_fn = d2l.seq_data_iter_sequential
        self.corpus, self.vocab = d2l.load_corpus_time_machine(max_tokens)
        self.batch_size, self.num_steps = batch_size, num_steps

    def __iter__(self):
        return self.data_iter_fn(self.corpus, self.batch_size, self.num_steps)

默认情况下,直接使用顺序分区的方法来划分数据集。 

def load_data_time_machine(batch_size, num_steps,  #@save
                           use_random_iter=False, max_tokens=10000):
    """返回时光机器数据集的迭代器和词表"""
    data_iter = SeqDataLoader(
        batch_size, num_steps, use_random_iter, max_tokens)
    return data_iter, data_iter.vocab

引入本文内容,即可直接使用最后的函数来进行数据集的采样工作,并将输出作为循环神经网络的输入。

  • 27
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值