ChatGPT 入门案例|商务智能对话客服(四)
本篇介绍了序列-序列机制和张量流的基本概念,基于中文语料库说明基于循环神经网络的语言翻译的实战应用。
01、序列-序列机制
序列-序列机制概述
序列-序列(Sequence To Sequence,Seq2Seq)是一个编码器-解码器 (Encoder-Decoder Mechanism)结构的神经网络,输入是序列(Sequence),输出也是序列(Sequence)。编码器(Encoder)将可变长度的序列转变为固定长度的向量表达,而解码器(Decoder)则将这个固定长度的向量转换为可变长度的目标信号序列,如图 1 所示,图中 EOS 是序列的结束标识符。
■ 图 1 序列-序列机制
序列-序列的基本模型包含三个部分,即编码器、解码器以及连接两者的中间状态向量语义编码(C)。编码器通过学习输入,将其编码成固定大小的状态向量,继而将语义编码传给解码器,解码器再通过对状态向量语义编码的学习输出对应的序列。
图 2 表示了序列-序列模型的基本工作流程。
■ 图 2 序列-序列模型
注意力机制
注意力机制(Attention Mechanism)与编码器-
注意力机制
注意力机制(Attention Mechanism)与编码器-解码器模型的区别在于不再要求编码器将所有输入信息都编码成固定长度的向量,而是编码成向量的序列,如图 10-3 所示,解码时选择性地从序列 Ci(i=1,2,…,n)中选取子集进行处理。
■ 图 3 注意力机制
02、集束搜索概述
集束搜索(Beam Search)是一种基于序列-序列的搜索算法,通常用在解空间比较大的情况下,为了减少搜索所占用的空间和时间,在每一步深度扩展的时候,裁剪掉部分质量比较差的结点,保留下质量较高的结点,这样就减少了空间消耗,并提高了时间效率,其缺点是潜在的最佳方案有可能被丢弃。
集束搜索一般用于解析空间较大的系统,常用的场景如机器翻译和语音识别等,当系统的数据集比较大,计算资源受限,而且没有唯一最优解时,该算法能够较快地找到接近最正确的解。集束搜索的超参数束宽(Beam Size),假定其值为 i。计算的基本步骤是:第一个时间步长选取当前条件概率最大的 i 个词,视为候选输出序列的第一个词,之后各时序步长基于上步长的输出序列筛选出所有组合中条件概率最大的 i 个结果,作为该时序下的候选输出序列,这样始终保持 i 个结果,最后从 i 中求解最优值。
03、智能客服开发流程
智能聊天客服程序开发过程中,首先需要明确需求,确定客服程序需要满足的主要功能。
智能客服的主要功能
智能客服系统的主要功能根据应用场景不同而变化,通常包括会话管理、任务管理、模型管理和权限管理等功能。
● 会话管理: 包含会话分类、问题查询以及问题更新等功能。
● 任务管理: 包括任务配置、任务更新、模型配置等。
● 模型管理: 包括模型更新、数据更新以及访问接口等。
● 权限管理: 包括权限控制、角色匹配以及业务对接等。
智能客服设计
客服程序设计中最重要的是自然语言理解问题,主要涉及实体识别、意图识别、情感识别、指代消解、省略恢复和拒绝判断等处理。实体识别即命名实体识别,主要涉及人名、地名和专有名词。意图识别主要包括显式意图识别和隐式意图识别,显式意图一般通过用户的输入信息明确表达,而隐式意图因为其含义潜藏在字面表述之外,因此通常判断比较困难。情感识别同样存在这个问题。指代消解和省略恢复是指在前文已经表述的前提下,后文提到同一个事物时使用指代词来表述,因此客服程序需要根据上下文进行正确指代匹配。拒绝判断是涉及服务超限时程序可以自动识别问题。
04、张量流商务智能实战
下面介绍基于张量流的序列-序列框架的中英翻译实例,该应用可以部署在有语言翻译场景的智能客服中。假定用户输入源语言文本(如中文),智能客服应用基于用户输入自动输出近似语义的目标语言文本(如英文)。本实例使用循环神经网络方法。本节首先介绍涉及的张量流相关基础知识,然后说明序列-序列的实现概要。
张量流概念简介
1. 张量
张量流(TensorFlow)的中文含义是张量和流(Tensor Flow),张量(Tensor)是张量流中基础但又重要的概念。张量是具有统一数据类型的数组,可以是一维、二维或者多维。张量可以来源自输入数据或计算结果,具有三种属性:名称、维度和数据类型。在张量流中,张量是维度特征向量(即数组,Array)的集合。例如,如果有一个 2 行 4 列的矩阵,表示为:
在张量流中以行特征向量为基准,表达式更新为:
2. 张量基本操作
张量的常用基本操作包括四种:Variable、constant、placeholder 和 sparseTensor,下面给出其在 TensorFlow Core V2.6.0 API 中的各自定义。使用张量流前一般需要先使用命令 pip install tensorflow 安装库文件,然后使用 import tensorflow 导入张量流的库文件。
1) constant()
constant()函数可以从给定对象中创建张量,其语法定义为:
主要参数说明如下。
value:张量值。
dtype:张量值的数据类型,可以指定 string、float32、float64、int16 和 int32 等类型。
shape:张量维度;二维情况下代表矩阵,即行和列信息。
name:张量名字。
【实例 1】如果张量值是数值,则称为标量,比如基于给定值 200 生成张量,输入命令如下,其中,>>> 代表命令输入提示符。
输入命令:
输出结果:
【实例 2】基于给定列表生成向量。
输入命令为:
输出结果为:
如果没有指定向量维度信息,则张量流默认按照行向量优先处理。
【实例 3】基于列表生成指定维度张量。
输入命令为:
输出结果为:
在指定向量具体维度的前提下,张量流按照预先指定的维度信息生成向量。
【实例 4】生成三行四列矩阵张量。
输入命令为:
输出结果为:
【实例 5】生成二行三列矩阵张量。
输入命令为:
输出结果为:
2) Variable()
当张量元素值发生变化时,可以使用 Variable()更新,语法定义为:
主要参数说明如下。
initial_value:代表初始值。
name:变量名字。
dtype:变量数据类型。
shape:变量的维度,如果设置为 None,则使用 initial_value 的维度值。
【实例 6】创建张量,然后更新张量。
输入命令:
输出结果:
3) placeholder()
对变量还可以执行占位符操作,即先占位后赋值,其命令格式为:
3) placeholder()
对变量还可以执行占位符操作,即先占位后赋值,其命令格式为:
主要参数说明如下。
dtype:张量元素的类型。
shape:张量的维度。
name:操作别名。
【实例 7】占位操作与 eager execution 不兼容,因此需要先关闭 eager execution 功能。
输入命令:
输出结果:
4) 张量维度
在程序中,有时需要使用张量的维度信息,对于二维矩阵而言,即是行信息和列信息。下面举例说明。
【实例 8】检查二维矩阵张量的行信息和列信息。
上述例子中,二维矩阵张量的维度信息存储于元组中,元组第一个元素代表行信息,元组第二个元素代表列信息,对于二维矩阵而言,没有第三个维度,因此访问元组的第三个元素时,会提示下标超界错误。
【实例 9】生成以值零填充的张量。
或者执行下面的命令可以得到相同的结果。
【实例 10】生成以值 1 填充的二维矩阵张量,并获取维度信息。
5) 张量流组件简介
张量流包含三个主要的组件:图形(Graph)、张量(Tensor)和任务(Session)。张量表示在操作之间传递的数据,常量张量值不变,而变量的初始值可能随着时间的推移而改变;图形是张量流的基础,运算和操作都在图形内部执行;会话操作从图形中执行,要在图形中使用张量值,需要事先创建并打开会话。
【实例 11】
升级到 2.x,对于部分使用旧版本编写的代码,仍然可以在 TensorFlow 2.x 中运行 1.x 代码,未经修改(contrib 除外),通常使用的兼容性方法是用 compat.v1 关键字指定,如下。
优化算法
TensorFlow 的 keras.optimizers 库中定义了模型的优化算法,下面介绍几种主要代表性算法。本节实例使用了其中的一种算法。
(1) Adam 算法: 基于一阶或二阶动量(Moments)的随机梯度下降算法,动量是非负超参数,主要作用是调整方向梯度下降并抑制波动。此算法适用于数据量和参数规模较大的场合。
(2) SGD 算法: 动量梯度下降算法。
(3) Adagrad 算法:学习率与参数更新频率相关。
(4) Adamax 算法:Adam 算法的扩展型,词嵌入运算有时优于 Adam 算法。
(5) Ftrl 算法:谷歌发明的算法,适用于大稀疏特征空间的场合。
(6) Nadam 算法: 基于 Adam 算法,使用 Nesterov 动量。
(7) RMSprop 算法:基于梯度平方均值。
(8) Adadelta 算法:使用随机梯度下降算法和自适应学习率,避免训练过程中学习率持续劣化以及手动设定问题。
损失计算
TensorFlow 的 keras.losses 库中定义了各种损失值的运算类,下面重点介绍常用的几种。
(1) CategoricalCrossentropy 类: 计算标签和预测值之间的交叉熵损失(Crossentropy Loss)。
(2) SparseCategoricalCrossentropy 类: 原理与 CategoricalCrossentropy 类似。比较适用于有两个及以上标签类别的场景,如果运算基于独热表示标签,更适合使用 CategoricalCrossentropy 损失。
(3) BinaryCrossentropy 类: 类似 CategoricalCrossentropy,适用于 0 或者 1 二分类的场合。
(4) MeanSquaredError 类: 计算标签和预测值之间的误差平方均值。
(5) MeanAbsoluteError 类:计算标签和预测值之间的绝对误差均值。
(6) Hinge 类:计算真实值和预测值之间的铰链损失。
模型评估
TensorFlow 的 keras.metrics 库中定义了模型评估指标,下面介绍几种代表性指标。
(1) AUC 类:代表 Area Under The Curve,计算 ROC 的曲线下面积。
(2) MeanSquaredError 类: 计算预测值和真实值的误差平方均值。
(3) MeanAbsoluteError 类:计算标签值和预测值的误差绝对均值。
(4) Accuracy 类: 计算标签值和预测值相同的频率。
(5) CategoricalCrossentropy 类: 计算标签和预测值之间的交叉熵。
(6) SparseCategoricalCrossentropy 类: 原理与 CategoricalCrossentropy 类似,比较适用于有两个及以上标签类别的场景。
向量嵌入
机器学习模型将向量作为输入,因此在将字符串输入模型之前需要将字符串转换为数值向量,也称为词嵌入。词嵌入提供了一种高效表示的方法,其中相似的词具有相似的编码。在处理大型数据集时,通常会看到多维的词嵌入处理,高维度嵌入可以体现词间的细粒度关系,但需要更多的数据来学习。在张量流中,这可以通过 TensorFlow 库中 Keras.Layers 的 Embedding 类实现,其具体定义如下。
主要参数说明如下。
input_dim:词语大小。
output_dim:嵌入维度。
embeddings_initializer:嵌入矩阵初始值。
embeddings_regularizer:嵌入矩阵调整函数。
embeddings_constraint:嵌入矩阵限定函数。
mask_zero:布尔值,判断是否零作为填充。
input_length:输入序列长度。
神经网络
门控机制基于循环神经网络,由 Kyunghyun Cho 等人于 2014 年提出。门控循环单元网络(Gated Recurrent Units,GRU)类似于附带遗忘门的长短期记忆网络 (LSTM),但参数比后者少。门控循环单元网络在自然语言处理的部分性能与长短期记忆网络相似,在较小数据集上的分析效果比较突出,具体语法定义如下。
主要参数说明如下。
units:输出空间维度。
Activation:激活函数。
recurrent_activation:重复激活函数。
use_bias:偏置量标识。
kernel_initializer:权重矩阵初始化。
dropout:输入的丢弃率,介于 0~1。
go_backwards:逆向处理输入序列。
中文语料处理
本实例使用中文语料,涉及中文语料的分词,使用结巴分词,下面是实例代码,可以查看分词后的结果,如图 4 所示。
■ 图 4 中文结巴分词
如果要对中文语料分词后的结果进行词频统计,可以使用如下方法。
输出结果参见图 5。
实现步骤
本实例基于 TensorFlow 库和循环神经网络(编码器-解码器),下面说明主要的操作步骤。
1. 导入库文件
首先需要导入程序执行所需的库文件,因为语料同时包含简体中文和繁体中文,因此参数设定同时支持简体和繁体,导入的主要库信息如下。
确认中文字体下载正常,如图 6 所示。
■ 图 6 文件下载进度
2. 下载语料
TensorFlow 提供了基于英语-西班牙语的翻译项,本实例是在其基础上针对中文-英语翻译的功能拓展,使用的中英文语料可以从网址http://www.manythings.org/anki/下载到本地,也可以在代码中加入链接地址由代码自动下载,主要实现代码如下。
执行命令确认语料的保存路径信息。
输出结果如下。
3. 语料预处理
中英文本语料,首先按照行将文本信息切分,如果是英文,则将文本变为小写,然后去掉开始和结尾的空白符并各自加上起始标识符和结束标识符,如果是中文文本,则去掉开始和结尾的空白符后直接添加起始和结束标识符,主要实现代码如下。
列举中英文句子查看处理效果,输入语句为:
输出结果参见图 7。
■ 图 7 文本预处理效果
按照行读取语料文本,一行内部中文和英文之间用 Tab 键区分,区分后第一个元素是英文,第二个元素是中文,中文语料执行中文结巴分词后通过空格连接,形成与英文文本相同的显示效果,主要实现代码如下。
输出部分样本,比较结巴分词后的中文文本和对应英文文本的处理效果,参见图 8。
■ 图 8 中英文处理结果
通过将文本映射为索引张量信息,输出部分样本,对比中英文词嵌入处理结果,参见图 9。
■ 图 9 中英文词嵌入处理
4. 编码器定义
接着定义编码器,词嵌入初始化矩阵基于均匀分布,使用双曲正切激活函数,循环激活函数使用 Sigmoid,使用偏置量并设定初始值为 0,模型丢弃率和重复丢弃率都设置为 0.1。
5. 解码器定义
接着定义解码器,词嵌入初始化矩阵基于均匀分布,使用双曲正切激活函数,重复激活函数使用 Sigmoid,使用偏置量并设定初始值为零,模型丢弃率和重复丢弃率都设置为 0.1。
6. 训练模型
基于参数配置,训练模型,设置训练轮数为 10 轮,参见图 10-10 和图 10-11。模型训练初期,损失值为 1.99,第 1 轮整体训练损失值为 1.146,之后随着训练轮数增加,损失值逐渐降低,第 4 轮结束时损失值减少为 0.572。
■ 图 10 模型训练初期
■ 图 11 模型训练后期
模型训练后期,损失值进一步下降,第 6 轮结束时训练损失值为 0.330,到第 10 轮整体训练结束时损失值则变为 0.096,模型的训练效果较好。
7. 测试结果
模型训练结束后,输入中文获得英文翻译结果,部分结果参见图 10-12~图 10-15。翻译结果可能会随着训练轮数和训练样本数量发生一定变化。
【实例 12】translate(u'感谢 你 的 帮助'),混淆矩阵输出结果参见图 12。
输入文本: <start> 感谢 你 的 帮助 <end>
翻译结果: thanks for your help <end>
■ 图 12 测试结果
【实例 13】translate(u'我 想 打 电话'),参见图 13。
输入文本: <start> 我 想 打 电话 <end>
翻译结果: i want to call <end>
■ 图 13 测试结果
【实例 14】translate(u'他 不幸 找 不到 工作'),参见图 14。
输入文本: <start> 他 不幸 找 不到 工作 <end>
翻译结果: he had no luck in finding work <end>
■ 图 14 测试结果
【实例 15】translate(u'我 相信 你 的 判断'),参见图 15。
输入文本: <start> 我 相信 你 的 判断 <end>
翻译结果: i believe your judgment <end>
■ 图 15 测试结果
版权声明: 本文为 InfoQ 作者【TiAmo】的原创文章。
原文链接:【http://xie.infoq.cn/article/163d69eeb2341db3e052a9bf6】。文章转载请联系作者。
评论