在一切变好之前,我们总要经历一些不开心的日子。
全文字数:2603字
阅读时间:10分钟
前言
由于在公众号上文本字数太长可能会影响阅读体验,因此过于长的文章,我会使用"[L1]"来进行分段。这个系列将主要借鉴《Tensorflow实战Google学习框架》这本书,主要介绍实现语言模型的一些前期准备,后期会出更详细的文章。
a
什么是 batching?
通常在优化目标函数的时候使用Mini-batch Gradient Descent算法,也就是Mini-batch梯度下降算法,这种梯度更新算法比Stochastic Gradient Descent(随机梯度下降算法,一个样本数据进行一次梯度更新)更加稳定,比Batch Gradient Descent(批量梯度下降法,一整个样本数据进行一个梯度更新)更新快。
虽然Mini-batch Gradient Descent稳定效率高,但是mini-batch给循环神经网络带来的很大的问题。因为在文本数据中,由于每个句子的长度不同,又无法像图像那样去调整到固定维度,而且在前期mini-batch的大小都是事先指定好了的,每一个批次的大小都是一样的。
这个时候就需要在对文本数据的batch操作的时候就需要采取一些特殊的处理了,目前有两种处理方案:
而我们的PTB的数据集就属于上下文之间有关联内容的数据,所以这里使用第二种的batching方法。
b
如何 batching
对于上下文之间有关联样本来说,最理想的当然就是把这些句子拼接起来,形成一个很长的一个句子,然后放在循环神经网络中进行训练,如下图所示:
▲将整个文档前后连接后的示意图
其中"A1A2A3","B1B2","C1C2C3C4"等分别代表一个句子。但是这种方式现实中并不能实现:
不能使用整个序列作为样本,那么很自然就会想着把大的序列长度切割成固定长度的子序列。循环神经网络在处理完一个子序列后,它最终的隐藏状态将复制到下一个序列中作为初始值,这样在前向计算的时,效果等同于一次性顺序地读取了整个文档,而在反向传播的时候,梯度则只在每个子序列内部传播,如下图所示:
▲按长度3切分整个文档
需要注意:
上面只解决了上下文连续的问题,但是我们知道使用Mini-batch进行处理的好处是可以利用计算的并行能力,我们希望每一个计算可以对多个句子进行并行处理。
解决的方案:
这个地方可能不太好理解,下面我用一个简单的numpy数组来说明batching:
import numpy as np
batch_num = 2
batch_size = 3
batch_step = 2
#(3,2*2)
array = np.arange(12).reshape(batch_size,batch_num * batch_step)
array2 = np.split(array,batch_num,axis = 1)
print(array)
print(array2)
▲通过numpy数组理清关系
我们继续来看对PTB数据进行batching的代码:
TRAIN_BATCH = 20
TRAIN_NUM_STEP = 35
#从文件中读取数据,并返回包含单词编号的数组
def read_data(file_path):
with open(file_path,"r") as fin:
#将整个文档读进一个长字符串.
id_string = " ".join([line.strip() for line in fin.readlines()])
#将读取的单词编号转换为整数
id_list = [int(w) for w in id_string.split()]
return id_list
def make_batches(id_list,batch_size,num_step):
#计算总的batch的数量。每个batch包含的单词数量是batch_size * num_step
num_batches = (len(id_list) - 1) // (batch_size * num_step)
#将数据整理成一个维度为[batch_size,num_batches * num_step]的二维数组
data = np.array(id_list[:num_batches * batch_size * num_step])
data = np.reshape(data,[batch_size,num_batches * num_step])
#沿着第二个维度将数据切分成num_batches个batch,存入一个数组
data_batches = np.split(data,num_batches,axis = 1)
#重复上述的操作,但是每个位置向右移动一位,这里得到的是RNN每一步输出所需要
# 预测的下一个单词
label = np.array(id_list[1:num_batches * batch_size * num_step + 1])
label = np.reshape(label,[batch_size,num_batches * num_step])
label_batches = np.split(label,num_batches,axis = 1)
#返回一个长度为num_batcher的数组,其中每一项包括一个data矩阵和一个label矩阵。
return list(zip(data_batches,label_batches))
batching的流程:
我们需要构建的是循环神经网络的语言模型,模型输入和输出的基本单元都是单词,很明显是有监督的模型,所以不仅需要制作data还需要制作标签label。语言模型输入一个词预测输出下一个词的概率,所以在构建训练集的时候只需要将样本往后移动一个单词即可。当然不论是制作data还是label都需要使用batching。
继续用上面那个numpy数组的例子,使用batching制作label:
▲使用batching制作label
有了data和label,就可以构建训练样本了:
▲制作好的训练样本
通过numpy数组简单例子的类比可以很容易理解对文本数据的batching操作。
本文分享自 AI机器学习与深度学习算法 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!