💻
QMMMS的笔记
博客
  • QMMMS的笔记
  • agent
    • MCP的背景、原理和开发
    • Agent 历史与背景
    • Agentic Workflows
    • 环境检查与基础工具
    • Tool Call
    • 工具与运行时的值
    • temp
    • 处理 Tool Call error
    • trick
  • algorithm
    • 线性结构
    • 二叉树
    • 图
    • 查找
    • 排序
    • 动态规划
    • 优化方法
    • 数学
    • 迁移至Java
  • computer_composition
    • 系统总线
    • 存储器
    • 输入输出系统
    • 计算机的运算方法
    • 指令系统
    • 补充
  • computer_network
    • 引入
    • 应用层
    • 传输层
    • 网络层(数据平面)
    • 网络层(控制平面)
    • 链路层
    • 常见问答
    • 实验
  • database
    • SQL实战
    • 关系代数
    • 数据库设计
    • 规范化
    • 数据库基本概念
    • 查询原理
    • 数据库恢复技术
    • 并发控制
  • dev_tools
    • Git
    • Nginx
    • Spring
    • LangChain
    • PyTorch Cheat Sheet
    • MyBatis
    • MySQL Cheat Sheet
    • MySQL 补充
    • Redis
    • Docker
    • RocketMQ
    • Chrome
  • linux
    • Linux基础命令与使用
    • 文件与权限
    • 文件与目录操作
    • 权限属性高级
    • 命令与文件的查找
    • 文件压缩和打包
    • vim编辑器
    • shell变量
    • 命令补充
    • 数据流重定向
    • 管道命令
    • shell脚本
    • 用户管理
    • 用户间交流
    • 计划任务
    • 进程管理
    • 软件管理
    • 认识系统服务
    • 运维常用命令
    • 常用命令
  • llm
    • 大规模语言模型概述
    • 分布式训练概述
    • 有监督微调概述
    • 强化学习与LLM
    • LLM评估概述
    • 大模型应用
    • 理解大模型
    • 量化
    • 预训练
    • 上下文学习
  • machine_learning
    • 引入
    • 大致正确学习
    • 一致收敛
    • 偏差还是过拟合?
    • 可学习的充要条件
    • 非均匀可学习性
    • 计算复杂性
  • mathematics
    • 概率与统计基础
    • 线性代数基础
  • operating_system
    • 操作系统基本概念
    • 进程和线程
    • 同步,互斥与死锁
    • 内存管理
    • 文件系统
    • I/O系统
    • 保护与安全
    • 《现代操作系统》
  • statistical_learning
    • 统计学习引入
    • 线性回归
    • 分类
    • 重抽样方法
    • 线性模型选择与正则化
    • 非线性模型
    • 基于树的方法
    • 支持向量机
    • 无指导学习
    • 马尔科夫链和蒙托卡罗方法简明理解
    • R语言速查
  • deep_learning
    • basic_concepts
      • 逻辑回归与损失函数
      • 神经网络
      • 正则化、预处理、权重初始化
      • 优化算法
      • 机器学习策略
      • 复习:从计算机视觉的角度
      • 卷积神经网络
      • 深度卷积网络示例
      • 计算机视觉任务
      • 循环神经网络
      • 自然语言处理任务
      • 注意力
      • Transformers 家族
      • 显卡扫盲
      • 强化学习概述
    • semi-supervise
      • 半监督学习简介
      • Consistency Regularization
      • Proxy-label Methods
      • Holistic Methods
      • Generative Models
      • Graph-Based SSL
      • Self-Supervision for SSL
      • Other SSL methods
  • programming
    • cpp
      • STL
      • C++基础
      • 内存管理
      • 面向对象
    • java
      • 环境和介绍
      • 注释
      • String
      • 面向对象思想
      • Object
      • 包
      • 访问权限修饰符
      • 初始化块
      • 接口
      • 内部类
      • 注解
      • 枚举
      • 集合框架
      • List
      • Map
      • 泛型
      • 迭代
      • IO与流
      • 序列化
      • 异常
      • Lambda
      • Stream流
      • Socket
      • 缓冲
      • 命名规范
      • 拆箱装箱
      • 值传递
      • 深拷贝
      • 反射
      • JVM
      • 并发编程基础
    • python
      • 并发编程
      • 环境管理
  • software_engineering
    • basic_concepts
      • 系统分析与设计概述
      • 规划
      • 需求分析与原型设计
      • 项目管理
      • 建模
      • 数据库设计
      • 架构
      • 配置管理
      • 测试管理
      • 安全
      • 编码原则
      • 微服务
      • 补充内容
    • software_testing
      • CMMI基础
      • PPQA与SQA
      • 软件测试基础
      • 黑盒测试
      • 白盒测试
      • 集成测试
      • 系统测试
      • 测开面试补充
由 GitBook 提供支持
在本页
  • 词汇表征与词嵌入
  • 特性与应用
  • 学习词嵌入
  • CBOW模型
  • Skip-Gram模型
  • 分级的softmax分类器
  • 负采样
  • GloVe 词向量
  • 情感分类
  • 词嵌入除偏
  • 句子嵌入表示模型
  • Bag-of-words
  • Pooling
  • CNN
  • Variations
  • 文档嵌入表示模型
  • 机器翻译
  • 集束搜索
  • 归一化优化
  • 误差分析
  • Bleu 得分
  • 语音识别
在GitHub上编辑
  1. deep_learning
  2. basic_concepts

自然语言处理任务

上一页循环神经网络下一页注意力

最后更新于10个月前

自然语言处理研究实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理技术发展经历了基于规则的方法、基于统计学习的方法和基于深度学习的方法三个阶段。自然语言处理由浅入深的四个层面分别是形式、语义、推理和语用,当前正处于由语义向推理的发展阶段。

词汇表征与词嵌入

词嵌入(word embeddings)是语言表示的一种方式,可以让算法自动的理解一些类似的词,比如男人对女人,比如国王对王后。词嵌入可以帮助构建NLP应用,特别是对于一些相对较小的模型标记训练集。

举个例子,假如你的学习算法已经学到了“I want a glass of orange juice”这样一个很可能的句子,如果看到“I want a glass of apple __”,如果算法知道apple和orange的关系很接近,那么就能更容易预测到下一个单词为**“juice”**

换一种表示方式会更好,如果我们不用one-hot表示,而是用特征化的表示来表示词典里的任何一个单词,我们学习这些词的特征或者数值。

举个例子,对于这些词,比如我们想知道这些词与Gender(性别)的关系。假定男性的性别为-1,女性的性别为+1,那么man的性别值可能就是-1,而woman就是-1。最终根据经验king就是-0.95,queen是+0.97,apple和orange没有性别可言。

有很多的其他特征,从Size(尺寸大小),Cost(花费多少),这个东西是不是alive(活的),是不是一个Action(动作),或者是不是Noun(名词)或者是不是Verb(动词),还是其他的等等。我们假设有300个不同的特征,这样就组成了一个300维的向量来表示man这个词,或者说这个词是300维空间的一个点。

然而我们很难想象300维空间,常用的可视化算法是t-SNE算法,把300维的数据嵌入到一个二维空间里,类似的词相距较近。

词嵌入能够达到理解词的关系,其中一个原因是学习词嵌入的算法会考察非常大的文本集,可以是1亿个单词,甚至达到100亿也都是合理的,大量的无标签的文本的训练集。通过考察大量的无标签文本,你可以发现orange(橙子)和durian(榴莲)相近,farmer(农民)和cultivator(培育家)相近。因此学习这种嵌入表达,把它们都聚集在一块。

在深度学习的词嵌入中,对齐通常指的是将来自不同语言或不同领域的词嵌入空间映射到一个共享的、统一的空间中,以便实现跨语言或跨领域的语义对齐,从而使得相似意义的词在这个统一的空间中具有相近的表示。

一个例子是多语言词嵌入对齐。通过将不同语言的词嵌入空间对齐到一个共享的空间,可以实现跨语言之间的词语之间的语义相似性。比如,将英语中的 "cat" 和法语中的 "chat" 在对齐后的空间中具有接近的表示,这样就实现了跨语言的词语对齐,使得模型可以更好地处理多语言任务。

特性与应用

接下来你可以把这个词嵌入应用到你的命名实体识别任务当中,尽管你只有一个很小的训练集,你可以使用迁移学习,把你从互联网上免费获得的大量的无标签文本中学习到的知识,能够分辨orange(橙子)、apple(苹果)和durian(榴莲)都是水果的知识,然后把这些知识迁移到一个任务中。

词嵌入还有一个迷人的特性就是它还能帮助实现类比推理。假如我提出一个问题,man如果对应woman,那么king应该对应什么?应该都能猜到king应该对应queen。我们寻求一种算法来自动推导出这种关系。

我们用一个四维向量$e_{\text{man}}$来表示man,对woman,king和queen也是用一样的表示方法。这些向量有一个有趣的特性,就是假如你有向量$e_{\text{man}}$和$e_{\text{woman}}$,将它们进行减法运算,即:

eman−ewoman=[−10.010.030.09]−[10.020.020.01]=[−2−0.010.010.08]≈[−2000]e_{\text{man}} - e_{\text{woman}} = \begin{bmatrix} - 1 \\ 0.01 \\ 0.03 \\ 0.09 \\ \end{bmatrix} - \begin{bmatrix} 1 \\ 0.02 \\ 0.02 \\ 0.01 \\ \end{bmatrix} = \begin{bmatrix} - 2 \\ - 0.01 \\ 0.01 \\ 0.08 \\ \end{bmatrix} \approx \begin{bmatrix} - 2 \\ 0 \\ 0 \\ 0 \\ \end{bmatrix}eman​−ewoman​=​−10.010.030.09​​−​10.020.020.01​​=​−2−0.010.010.08​​≈​−2000​​

类似的,假如你用$e_{\text{king}}$减去$e_{\text{queen}}$,最后也会得到一样的结果,即:

eking−equeen=[−0.950.930.700.02]−[0.970.950.690.01]=[−1.92−0.020.010.01]≈[−2000]e_{\text{king}} - e_{\text{queen}} = \begin{bmatrix} - 0.95 \\ 0.93 \\ 0.70 \\ 0.02 \\ \end{bmatrix} - \begin{bmatrix} 0.97 \\ 0.95 \\ 0.69 \\ 0.01 \\ \end{bmatrix} = \begin{bmatrix} - 1.92 \\ - 0.02 \\ 0.01 \\ 0.01 \\ \end{bmatrix} \approx \begin{bmatrix} - 2 \\ 0 \\ 0 \\ 0 \\ \end{bmatrix}eking​−equeen​=​−0.950.930.700.02​​−​0.970.950.690.01​​=​−1.92−0.020.010.01​​≈​−2000​​

所以得出这种类比推理的结论的方法就是,当算法被问及man对woman相当于king对什么时,算法所做的就是找出一个向量,使得:

eman−ewoman≈ eking−e?e_{\text{man}}-e_{\text{woman}}\approx\ e_{\text{king}}- e_{?}eman​−ewoman​≈ eking​−e?​

具体说,找到一个单词w来最大化$e_{w}$与$e_{\text{king}} - e_{\text{man}} + e_{\text{woman}}$的相似度,即:

Find word w:argmax sim(ew,eking−eman+ewoman)\text{Find word w:argmax sim}(e_{w},e_{\text{king}} - e_{\text{man}} + e_{\text{woman}})Find word w:argmax sim(ew​,eking​−eman​+ewoman​)

最常用的相似度函数叫做余弦相似度,其实是$u$和$v$的夹角的余弦值,公式为:

sim(u,v)=uTv∣∣u∣∣2∣∣v∣∣2\text{sim}\left( u,v \right) = \frac{u^{T}v}{\left| \left| u \right| \right|_{2}\left| \left| v \right| \right|_{2}}sim(u,v)=∣∣u∣∣2​∣∣v∣∣2​uTv​

学习词嵌入

当应用算法来学习词嵌入时,实际上是学习一个嵌入矩阵。假设我们的词汇表含有10,000个单词,300个特征,我们要做的就是学习一个嵌入矩阵$E$,它将是一个300×10,000的矩阵。

我们用符号$O_{6527}$表示one-hot向量,这个向量除了第6527个位置上是1,其余各处都为0,是一个10,000维的列向量;用符号$e_{6527}$表示特征的嵌入向量,在这个例子中是一个300维的列向量。我们有:

E⋅O6527=e6527E \cdot O_{6527}= e_{6527}E⋅O6527​=e6527​

并且这个式子可以推广到一般。

现在,我们的目标是随机地初始化矩阵$E$,然后使用梯度下降法来学习这个300×10,000的矩阵中的各个参数。

实践证明,建立一个语言模型是学习词嵌入的好方法。假如你在构建一个语言模型,神经网络能够做到输入:“I want a glass of orange __.”,然后预测这句话的下一个词。

如图,我们将$E$与one-hot向量$O$相乘得到嵌入向量$e$,把它们全部放进神经网络中,经过神经网络以后再通过softmax层,然后softmax分类器会在10,000个可能的输出中预测结尾这个单词。

实际上更常见的是有一个固定的历史窗口,比如只看前4个单词,用一个固定的历史窗口就意味着你可以处理任意长度的句子,因为输入的维度总是固定的。或者把目标词左右各4个词作为上下文,来预测中间的目标词。这用的是一种Skip-Gram模型的思想。

CBOW模型

CBOW模型的输入是某一个特征词的上下文相关的词对应的词向量,而输出是这个特定词的词向量。CBOW之所以叫连续词袋模型,是因为在每个窗口内它也不考虑词序信息,因为它是直接把上下文的词向量相加了,自然就损失了词序信息。CBOW抛弃了词序信息,指的就是在每个窗口内部上下文直接相加而没有考虑词序。

计算过程如下:

  1. 输入特征词上下文相关词的one-hot编码,维度为1*V,其中V是词空间的大小。

  2. 这些词的词向量和共享矩阵W相乘。W的维度为V*N,其中N是自己定义的维度,也是最终word embedding的维度。每个上下文词都会计算得到一个1*N向量。

  3. 将这些向量相加取平均,得到维度为1*N的隐藏层向量。

  4. 将该向量与$W'_{N×V}$相乘,得到输出层的维度为1*V。

  5. 将输出层的向量经过softmax归一化处理得到新的1*V向量,取概率最大的值对应的位置为预测结果。

  6. 将预测的中心词和真实结果计算误差,一般使用交叉熵函数计算误差。

  7. 根据误差进行反向传播。不断更新W和$W'_{N×V}$的值。

  8. 最终得到W矩阵,任何一个单词的one-hot编码乘这个矩阵都将得到自己的词向量。

Skip-Gram模型

CBOW通过上下文来预测当前词(下图左边),Skip-gram通过当前词预测上下文(下图右边):

  • 输入特定词的one-hot编码,维度为1*V,其中V是词空间的大小。

  • 特定词的词向量和共享矩阵W相乘。W的维度为V*N,其中N是自己定义的维度,也是最终word embedding的维度。得到一个1*N的隐藏层向量。

  • 隐藏层向量和维度为N*V的矩阵相乘,得到1*V的输出向量。

  • 将该输出向量经过softmax,选取概率最大的位置为预测结果。

  • Skip-gram通过反向传播算法和梯度下降来学习权重,训练数据的输入一般是一个词$W_I$,上下文窗口为C,它的输出是$W_I$的上下文$W_O$,损失函数是输出词的条件概率:$E=-\log p(W_{O,1},W_{O,2},W_{O,3}...W_{O,C}|W_I)$

  • 训练完成后,得到权重矩阵W。

CBOW/skip-gram模型的输出层使用的softmax函数,时间复杂度为O(|D|),计算代价很大,对大规模的训练语料来说,训练非常耗时。每次计算概率需要对你词汇表中的所有(例如10,000个)词做求和计算,一些解决方案包括分级(hierarchical)的softmax分类器和负采样(Negative Sampling)。

分级的softmax分类器

类似于二分查找的思想,顶层分类器告诉你目标词是在词汇表的前5000个中还是在词汇表的后5000个词中,然后下一层的分类器会告诉你这个词在词汇表的前2500个词中,或者在词汇表的第二组2500个词中,诸如此类。实际上用这样的分类树,计算成本与词汇表大小的对数成正比。

在实践中分级softmax分类器不会使用一棵完美平衡的分类树或者对称树。实际上,常用词大多在顶部,不常用的词会在树的更深处,类似哈夫曼编码的思想。

补充一点,当对上下文$c$进行采样时,那么目标词$t$就会在上下文$c$的正负10个词距内进行采样。但是要如何选择上下文$c$?一种选择是对语料库均匀且随机地采样,如果那么做,一些词像the、of、a、and、to诸如此类是出现得相当频繁的,但它们没什么意义,你想要的是花时间来更新像durian这些更少出现的词的嵌入。实际上词$p(c)$的分布并不是单纯的在训练集语料库上均匀且随机的采样得到的,而是采用了不同的分级来平衡更常见的词和不那么常见的词。

负采样

负采样与的Skip-Gram模型相似的事情,但是用了一个更加有效的学习算法。在这个算法中要做的是构造一个新的监督学习问题:给定一对单词,比如orange和juice,我们要去预测这是否是一对上下文词-目标词(context-target)。

在这个例子中orange和juice就是个正样本,我们把它标为1;orange和king无关,就是个负样本,我们把它标为0。我们要做的是对于一个上下文$c$,找到一个正样本,再进行$K$次从词典中任意选取的词,并标记0,这些就会成为$K$个负样本。优化目标改为:最大化正样本的概率,同时最小化负样本的概率。如下图。

重述一下,我们使用记号$c$表示上下文词,记号$t$表示可能的目标词,$y$有两个值0和1,表示是否是一对上下文-目标词。我们要做的就是定义一个逻辑回归模型,给定输入的$c$,$t$对的条件下,$y=1$的概率,即:

P(y=1|c,t)=σ(θtTec)P\left( y = 1 \middle| c,t \right) = \sigma(\theta_{t}^{T}e_{c})P(y=1∣c,t)=σ(θtT​ec​)

我们有一个正样本和$K$个负样本,正负样本比例为$\frac{1}{K}$,即每一个正样本你都有$K$个对应的负样本来训练一个类似逻辑回归的模型。小数据集的话,$K$从5到20比较好;对于更大的数据集$K$从2到5比较好。

一个重要的细节就是如何选取负样本,对于给定上下文,词w就是一个正样本,其他词就是负样本。但是负例样本太多了,解决方法是:在语料库中,各个词出现的频率是不一样的,我们采样的时候要求高频词选中的概率较大,而低频词选中的概率较小。这就是一个带权采样的问题,采用以下方式进行采样:

P(wi)=f(wi)34∑j=110,000f(wj)34P\left( w_{i} \right) = \frac{f\left( w_{i} \right)^{\frac{3}{4}}}{\sum_{j = 1}^{10,000}{f\left( w_{j} \right)^{\frac{3}{4}}}}P(wi​)=∑j=110,000​f(wj​)43​f(wi​)43​​

其中$P\left( w_{i} \right)$是选取某个词的概率。$f(w_{i})$是语料库中的某个英文词的词频。

GloVe 词向量

GloVe代表用词表示的全局变量(global vectors for word representation)也是一个计算词嵌入的算法。

假定$X_{{ij}}$是单词$i$在单词$j$上下文中出现的次数,之后遍历训练集,数出单词$i$在不同单词$j$上下文中出现的个数。所以$X_{{ij}}$就是一个能够获取单词$i$和单词$j$出现位置相近时或是彼此接近的频率的计数器。

想要知道的是两个单词之间有多少联系,$i$和$j$之间有多紧密,也就是它们同时出现的频率是多少,这由$X_{{ij}}$影响。

GloVe模型做的就是进行优化,我们将单词之间的差距进行最小化处理:

minimize∑i=110,000∑j=110,000f(Xij)(θiTej+bi+bj′−logXij)2\text{mini}\text{mize}\sum_{i = 1}^{10,000}{\sum_{j = 1}^{10,000}{f\left( X_{{ij}} \right)\left( \theta_{i}^{T}e_{j} + b_{i} + b_{j}^{'} - logX_{{ij}} \right)^{2}}}minimizei=1∑10,000​j=1∑10,000​f(Xij​)(θiT​ej​+bi​+bj′​−logXij​)2

然后,我们要做的是解决参数$\theta$和$e$的问题,用梯度下降来最小化上面的公式,这样输出能够对这两个单词同时出现的频率进行良好的预测。

其中,$f\left(X_{{ij}}\right)$是额外的加权项,作用一是当$X_{{ij}}$是等于0时,$log0$是未定义的,我们会用一个约定即$0log0= 0$。如果$X_{{ij}} =0$,先不要进行求和,所以$log0$就是不相关项。$f\left(X_{{ij}}\right)$的另一个作用是不给不常用词(durion)太小的权值,也不给频繁的词(this,is,of,a)过分的权重。

情感分类

有了词嵌入的帮助,即使只有中等大小的标记的训练集,也能构建一个不错的情感分类器。

上图是一个情感分类问题的一个例子,输入$x$是一段文本,而输出$y$是要预测的情感,在这个例子中是一个餐馆评价的星级。情感分类器要训练一个从$x$到$y$的映射。

对于一个简单的情感分类的模型,假设有一个句子"dessert is excellent",我们取这些词,对于每一个单词,找到相应的one-hot向量$o$,乘以嵌入矩阵$E$,得到$e$。其中$E$是别人在很大的训练集上提前训练好的,对所有的$e$求和或者平均,再把这个特征向量送进softmax分类器,然后输出$\hat y$,包含5个可能结果的概率值,从一星到五星。

上面这个算法有一个问题就是没考虑词序,我们搭建一个更加复杂的模型,用一个RNN来做情感分类。我们取这些词,对于每一个单词,找到相应的one-hot向量$o$,乘以嵌入矩阵$E$,得到$e$,然后把它们送进RNN里,RNN的工作就是在最后一步计算一个特征表示,用来预测$\hat y$。

词嵌入除偏

机器在学习时以人为学习目标,在自然语言处理中以人类创造的文本作为样本,当人类社会存在偏见时,机器,特别是词嵌入,也会有可能学习到这种偏见,包括性别,种族等偏见。

举个例子,一个已经完成学习的词嵌入可能会输出Man:Computer Programmer,和Woman:Homemaker,这个结果包含性别歧视。如果算法输出的是Man:Computer Programmer,同时Woman:Computer Programmer这样子会更合理。

我们尝试减少词嵌入中的偏见问题。这节具体处理性别歧视。

  1. 我们首先确认性别趋势。找到一些带有性别色彩的词,比如$e_{\text{he}}-e_{\text{she}}$和$e_{\text{male}}-e_{\text{female}}$,然后将这些值取平均,这个趋势是性别趋势,或说是我们关注的偏见趋势。在这种情况下,偏见趋势可以将它看做1D子空间,所以无偏见趋势是剩下的299D子空间。

  2. 中和步骤。对于那些定义不确切的词可以将其处理一下,避免偏见。对于像doctor和babysitter这种单词我们就可以将它们在偏见趋势轴上进行处理,来减少或是消除他们的性别歧视趋势的成分,也就是减少他们在距离偏见趋势轴水平方向上的距离。

  1. 均衡步。对于像grandmother和grandfather,或者是girl和boy这些词嵌入,只希望性别是其区别。主要做的就是将grandmother和grandfather这样的词对移至与偏见趋势轴线等距的一对点上。

句子嵌入表示模型

Bag-of-words

仅仅求和,得到的句子向量是定长的,句子向量的长度等于词向量的长度。但是丢失了词汇之间的顺序信息。

Pooling

句子向量长度是词向量的3倍,除了最大、最小和平均,当然也可以追加其他操作继续进行扩展。这里+的符号意思是拼接

CNN

卷积神经网络的思想,分别卷积了大小为2和3的窗口,使用最大池化,是一个有监督学习模型,可以学习到词序信息

Variations

层级CNN,在输入端引入了字符向量。在文本分析的很多任务中,都证明引入字符向量可以提高分析性能

文档嵌入表示模型

机器翻译

我们尝试搭建一个翻译应用,将法语句子翻译成英语句子。和之前一样,我们用$x^{<1>}$ 一直到$x^{< 5>}$来表示输入的句子的单词,然后我们用$y^{<1>}$到$y^{<6>}$来表示输出的句子的单词,那么,如何训练出一个新的网络来输入序列$x$和输出序列$y$呢

我们之前其实提到过。我们先建立一个网络,这个网络叫做编码网络(encoder network),它是一个RNN的结构,每次只向该网络中输入一个法语单词,将输入序列接收完毕后,这个RNN网络会输出一个向量来代表这个输入序列。之后你可以建立一个解码网络,它以编码网络的输出作为输入,被训练为每次输出一个翻译后的单词,一直到它输出序列的结尾或者句子结尾标记,这个解码网络的工作就结束了。这是基本的seq2seq模型。

使用类似的结构,我们可以完成图像描述任务,即给出一张图片,自动地输出该图片的描述。方法如下,我们将图片输入到卷积神经网络中,让其学习图片的编码,这个预训练的结构会给出一个4096维的特征向量,表示的就是这只猫的图片。接着可以把这个向量输入到RNN中,RNN要做的就是生成图像的描述,每次生成一个单词,一直到它输出序列的结尾或者句子结尾标记。这是基本的image to sequence模型。

集束搜索

现在我们来改进用来翻译的seq2seq模型。这个模型的作用可以理解为,对于输入的法语句子,模型输出各种英文翻译所对应的可能性。显然我们不想让它随机地进行输出英文句子并判断可能性,我们也不能穷举所有的句子,我们应该有条理地搜索, 或者说使用集束搜索(Beam Search),步骤如下:

  1. 首先让法语句子经过编码网络生成向量,集束搜索算法与这部分无关。

  2. 现在来评估第一个单词的概率值,我们在英文字典中找到最可能的三个选项并记录它们。如果英文字典包含10,000个词,这一步我们计算了10,000个概率$P(y^{<1>}|x)$并找出三个最大值。

  3. 现在来评估第二个单词的概率值,对于上一步的三个选项,分别对英文字典的所有词计算概率,这一步我们有$3 \times 10000 = 30000$个概率$P(y^{<1>},y^{<2>}|x)$,找出三个最大值并记录它们。

  4. 如上继续计算,直到输出序列的结尾或者句子结尾标记。

其中,我们总是“找三个最可能的选项”。这里“三”是一个参数,叫做集束宽(beam width),用B表示。当B为1时,就是传统的贪心算法,当我们取一个大一点的B时,贪心的本质不变,但会以更大的时间空间代价尝试找到更好的结果。(贪心算法找不到最好的结果)

归一化优化

以上就是集束搜索的基本方式,现在我们尝试优化这个搜索算法。

集束搜索的本质是尝试最大化一个概率$\prod_{i=1}^{T_y}P(y^{} | x,y^{<1>} \cdots y^{} )$,也可以表示为:

P(y<1>∣X)×P(y<2>∣X,y<1>)×P(y<3>∣X,y<1>,y<2>)⋯P(y<Ty>∣X,y<1>,y<2>…y<Ty−1>)P(y^{<1>}|X) \times P(y^{< 2 >}|X,y^{< 1 >}) \times P(y^{< 3 >}|X,y^{< 1 >},y^{< 2>}) \cdots P(y^{< T_{y} >}|X,y^{<1 >},y^{<2 >}\ldots y^{< T_{y} - 1 >})P(y<1>∣X)×P(y<2>∣X,y<1>)×P(y<3>∣X,y<1>,y<2>)⋯P(y<Ty​>∣X,y<1>,y<2>…y<Ty​−1>)

因为概率值都是小于1的,很多小于1的数乘起来,会造成数值下溢。因此在实践中,我们不会最大化这个乘积,而是取$log$值,我们总是记录概率的对数和:

∑t=1TylogP(y<t>∣x,y<1>⋯y<t−1>)\sum_{t=1}^{T_y} log P(y^{<t>} | x,y^{<1>} \cdots y^{<t-1>})t=1∑Ty​​logP(y<t>∣x,y<1>⋯y<t−1>)

因为要考虑长度不同的句子,我们可以把它归一化,减少对输出长的结果的惩罚:

1Tyα∑t=1TylogP(y<t>∣x,y<1>⋯y<t−1>)\frac{1}{{T_y}^\alpha}\sum_{t=1}^{T_y} log P(y^{<t>} | x,y^{<1>} \cdots y^{<t-1>})Ty​α1​t=1∑Ty​​logP(y<t>∣x,y<1>⋯y<t−1>)

我们有时会在$T_{y}$上加上指数$\alpha$,它是另外一个超参数,可以等于0.7。如果$\alpha$等于1,就相当于完全用长度来归一化,如果$\alpha$等于0,就相当于完全没有归一化,我们在完全归一化和没有归一化之间调整大小来得到最好的结果。

误差分析

我们之前分析过集束搜索的贪心核心只是尽量找到更好的结果,没有保证找到最好的结果。同时RNN网络模型出了问题也会造成结果变差,我们尝试区分这两种误差,以便更有针对性地解决问题。

我们用这个例子说明,法语输入为: “Jane visite l'Afrique en septembre”。人工翻译输出$y^*$为 Jane visits Africa in September。翻译模型输出为$\hat y$:Jane visited Africa last September。

注意到翻译模型的输出实际上改变了句子的原意,因此这不是个好翻译。所以理论上$P(\hat y|x)$ 小于 $P(y^*|x)$

第一种情况,RNN模型的输出结果$P(\hat y|x)$ 小于 $P(y^*|x)$,并且集束搜索算法选择了$\hat y$ ,这种情况下是集束搜索算法不够好。

第二种情况,RNN模型的输出结果$P(\hat y|x)$ 大于等于 $P(y^*|x)$,在这种情况下,是RNN模型出了问题,需要在RNN模型上花更多时间。

Bleu 得分

在翻译中,当有多个同样好的答案时,怎样评估一个机器翻译系统呢?BLEU (bilingual evaluation understudy) (双语评估替补)得分做的就是,给定一个机器生成的翻译,它能够自动地计算一个分数来衡量机器翻译的好坏。

我们用一个例子解释:

法语句子:Le chat est sur le tapis

人工翻译1:The cat is on the mat

人工翻译2:There is a cat on the mat

当机器翻译 (MT)的输出是:the the the the the the the。衡量机器翻译输出质量的方法之一是观察输出结果的每一个词看其是否出现在参考中,这被称做是机器翻译的精确度。在参考1中,单词the出现了两次,在参考2中,单词the只出现了一次,所以单词the的得分上限为2。这个输出句子的得分为2/7。

上面我们只是关注单独的单词或者说一元词组(unigrams),在BLEU得分中,也要考虑成对的单词。二元词组(bigrams)表示相邻的两个单词,三元词组(trigrams)表示是三个挨在一起的词。

我们假定机器翻译输出了稍微好一点的翻译:The cat the cat on the mat,可能的二元词组有:

  • the cat出现了两次

  • cat the出现了一次

  • cat on出现了一次

  • on the出现了一次

  • the mat出现了一次

之后我们定义截取计数Count_clip(the clipped count)。上限值为二元词组出现在参考1或2中的最大次数。

  • the cat在每个参考中最多出现一次,所以我将截取它的计数为1

  • cat the并没有出现在参考1和参考2中,所以我将它截取为0

  • cat on 记1分

  • on the记1分

  • the mat记1分

最后,修改后的二元词组的精确度就是count_clip之和。因此是4/6为二元词组改良后的精确度。

现在我们将它公式化,$n$元词组精确度$P_n$为:

Pn=∑ngram∈y^Countclip(ngram)∑ngram∈y^Count(ngram)P_n=\frac{\sum_{ngram \in \hat{y}}Countclip(ngram)}{\sum_{ngram \in \hat{y}}Count(ngram)}Pn​=∑ngram∈y^​​Count(ngram)∑ngram∈y^​​Countclip(ngram)​

如果你计算了$P_1$,$P_2$, $P_3$,$P_4$,按照惯例BLEU得分被定义为:

exp(14∑n=14Pn)exp (\frac{1}{4}\sum\limits_{n=1}^{4}{{{P}_{n}}})exp(41​n=1∑4​Pn​)

语音识别

seq2seq模型也可以应用于音频数据,比如输入音频片段$x$生成文本$y$。这节用CTC(Connectionist Temporal Classification)损失函数来做语音识别。

假设语音片段内容是某人说:"the quick brown fox",我们使用一个简单的单向RNN结构(实际中可以更复杂),输入$x$和输出$y$的数量是一样。

对于输入,举个例子,比如有一段10秒的音频,并且是100赫兹的,所以有1000个输入,但输出没有1000个字符,这时要怎么办呢?

CTC损失函数允许RNN生成空白符,这里用下划线表示,这句话开头的音可表示为th_eee_ _ _(空格)_ _ _ qqq _ _。其中空白符和空格是不一样的。CTC损失函数的一个基本规则是将空白符之间的重复的字符折叠起来。这段输出对应的是"the q"。这样一来神经网络因为有很多这种重复的字符,所以最后我们得到的文本会短很多。

随着语音识别的发展,越来越多的设备可以通过你的声音来唤醒,这有时被叫做触发字检测系统(rigger word detection systems)。

介绍一个基础的算法,模型使用RNN结构。计算出一个音频片段的声谱图特征,得到特征向量$x^{<1>}$, $x^{<2>}$, $x^{<3>}$..,放到RNN中,之后定义目标标签$y$。假如音频片段中的这一点是某人刚刚说完一个触发字,比如"Alexa",或者"小度你好" ,那么在这一点之前,在训练集中把目标标签都设为0,然后在这个点之后的固定一段时间内输出多个1,来提高1与0的比例。