一、引言
本教程目的是为了能够让读者从0到1构建一个简易版本的聊天机器人,同时对其中使用的API进行较为详细的介绍,目的是为了能够让读者在搭建完成一个聊天机器人的同时,也能知道其中的各个“零部件”到底是起着什么样的作用?而在本文中,为了叙述的连续性,所以并没有涉及到任何的理论知识,后续将会对理论知识进行整体的梳理。
二、开发环境
2.1. -3.6.4
2.2. jieba-0.39
2.3. -1.8.0
2.3. flask-0.12.2
三、语料准备
未分词处理的小黄鸡语料库:ci.conv(23.3MB)
四、整体流程
五、开发步骤
4.1. 类的初始化工作
首先我们需要做一些类的初始化工作,例如模型超参数的设置工作、隐藏层节点数等等。
4.2. 输入结构的定义
接着我们定义输入数据的结构,假设我们已经有了一个模型,我们知道由两个模块构成,一个是端,一个是端,我需要给这个模型输入数据吧,那么对这两个模块输入的数据结构是怎样的了?
4.3. 读取数据,构建字典表
接着我们需要单独一个方法进行数据的读取,同时建立字符及其索引的字典表以及其倒排表,因为后面的操作需要这个字典表。
4.4. 构建模型
这个步骤是构建聊天机器人过程中最重要的一步,在这个步骤中,我们需要依次完成以下的工作:
(1)对端输入数据的操作
(2)构建端
(3)获取端的输出
(4)对端输入数据的操作
(5)构建端
(6)获取端的输出
最后对端与端进行连接并返回端的输出结果
4.5. 开始训练
当完成了前期的准备工作,也完成了模型定义工作,接着就需要对这个模型进行训练,需要进行如下的工作:
(1)构建训练图
(2)获取Mini-Batch训练数据并喂给训练图
(3)训练完成后保存模型
4.6. 开始预测
在完成模型的训练后,同时保存了训练好的模型,当需要进行预测的时候,即输入一条语句后,我们需要进行如下工作:
(1)构建输入
(2)加载模型
(3)开始预测
六、API介绍
当我们对整体的过程有了较好的了解后,我们再深入到代码里面去瞧瞧框架里面的API细节。
6.1. 相关API
涉及到的方法有如下几个:
tf...
tf.nn.
这个在博客中进行了详细的介绍。
6.2. RNN单元相关API
涉及到的方法有如下几个:
tf..rnn.
tf..rnn.
tf.nn.
我们先介绍tf..rnn.,其原型为:
目前我们只需要了解其中的红框标注的参数,分别为单元个数、权重初始化器、忘记门偏置、状态输出形式以及激励函数,而我们的简易版本只需要设置参数以及。其它的默认就可以了(其中激励函数默认为tanh),假设我们设置 = 2,最后得到的单层LSTM单元如下图所示:
其中上方的图为经典的LSTM结构图,下方的图为2个LSTM节点的单层LSTM,而T表示的是时间序列,如果需要多层,那么就需要用到tf..rnn.方法了,其中原型为:
其中cells就是RNN单元列表。什么意思了?就是说假设开始我构建了2个节点LSTM单元,然后我需要两层,那么就可以传入cells = [, ]。
有了LSTM模型了,那么肯定就会有输入和输出,那么该如何输入数据了,又该如何得到输出,输出的又是什么了?这个时候就需要重要的“角色”上场了,她就是tf.nn.方法,其原型为:
目前我们只需要了解红框里面的参数,一个是传入的RNN单元(单层或者多层),而即为输入,其格式为[, , ],表示的是在时间上展开后的迭代的次数,对于中文而言,假如输入了一条中文:“你在干什么?”,最后通过分词得到词组“你/在/干什么/?”共4个词组,所以单看这一条的话,那么则为4。而这个方法的输出为:
和,这两个参数有什么区别了?目前只需简单了解一下:
记录了每条样本每个词组在模型最后一层各个节点的输出
记录了每条样本最后一个词组在模型各个层各个节点的状态输出(c,h)
具体对这个函数的测试见
6.3. 相关API
涉及到的方法有如下几个:
tf..Dense
tf...
tf...
tf...
tf...r
tf...
tf.train.
其中tf..Dense建立一个全连接层,其原型为:
一个是全连接层的节点数,一个是连接到该层各个节点的权重初始化器。
接着需要tf...控制端的数据的读入,其原型为:
其中为端的输入,格式为:[, , ],而记录了各条样本的序列长度,该方法每次生成下一个时间阶段的输入。接着就是方法,其原型为:
其输出为,即元组(, )
为了能更容易理解和,我们首先观察一下自带的测试文件.py,我们重点看一下的输出,如下所示:
其中h为输出节点数,为LSTM中节点数,
为每次迭代的输出,为类型,其中第一个元素为,第二个元素为,在这里我们需要注意在内部的处理都是以=True的形式进行处理的(虽然这个参数默认为False,但是在程序里面会进行转换)。举个例子:假设输入一个句子“你/真好”,这里的 = 1, = 2, 程序里面是以[, , ]形式进行处理,所以输入=1时的[, ],获得输出,其中形状为(, h),而每个阶段()中的状态变量(c,h)的形状都为(, )。而中的第二个元素,即为中值最大对应的位置。
接着就是方法,其原型为:
在这个方法里面的参数一个是,传入模型,而参数 = True时会忽略掉某个阶段中为零的输入,控制着端迭代的最大次数。而该方法的输出共两个:, ,其中为类型,即(, )元组,而是(c,h)元组,一般我们只需要。这里注意和的形状,可以从.py文件中得到:
用在训练阶段,而r则用在预测阶段,其原型为:
其中为开始标志,其形状为(,),而为结束标志。
接着我们将定义损失函数,见,其原型为:
文档中的说明很清楚,在这我就直接COPY过来了:
其中这里的,我们主要是为了忽略掉那些PAD(因为一个的输入序列的长度不一致,处理时会通过PAD进行补齐)。同时在这里还有几个重要的方法用来自己设置梯度值:
这个方法其实就是的第一个阶段,返回的是(, ),即针对某个变量的梯度值。当重新设置了变量的梯度值后,然后将其应用Adam优化器上,即:
这个方法就是的第二阶段。
PS:通常我们的用法是:.(loss),其实这个过程一共分成了两个阶段,一个阶段是通过计算各个变量的梯度值,另一个阶段是使用该计算得到的梯度值,即。
代码见:
评论(0)