diff --git "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/C-\344\270\223\351\242\230-\344\274\230\345\214\226\347\256\227\346\263\225.md" "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/C-\344\270\223\351\242\230-\344\274\230\345\214\226\347\256\227\346\263\225.md" index 390e81aa..60609d84 100644 --- "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/C-\344\270\223\351\242\230-\344\274\230\345\214\226\347\256\227\346\263\225.md" +++ "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/C-\344\270\223\351\242\230-\344\274\230\345\214\226\347\256\227\346\263\225.md" @@ -38,7 +38,7 @@ Index ## 梯度下降 -> 数学/[梯度下降法](../数学/深度学习的核心.md#梯度下降法) +> ../数学/[梯度下降法](../C-数学/B-深度学习的核心#梯度下降法) - 梯度下降是一种**优化算法**,通过**迭代**的方式寻找模型的**最优参数**; - 所谓最优参数指的是使**目标函数**达到最小值时的参数; @@ -60,7 +60,7 @@ Index ### 小批量随机梯度下降 - 为了降低随机梯度的**方差**,使模型迭代更加稳定,实践中会使用**一批**随机数据的损失来近似平均损失。 - > ./机器学习基础/[偏差与方差](./ML-机器学习基础.md#偏差与方差) + > ../机器学习基础/[偏差与方差](../A-机器学习/A-机器学习基础#偏差与方差) - 使用批训练的另一个主要目的,是为了利用高度优化的**矩阵运算**以及**并行计算框架**。 ### 小批量 SGD 的更新过程 @@ -156,7 +156,7 @@ Index > Hinton, 2012 - RMSProp 主要是为了解决 AdaGrad 方法中**学习率过度衰减**的问题—— AdaGrad 根据平方梯度的**整个历史**来收缩学习率,可能使得学习率在达到局部最小值之前就变得太小而难以继续训练; - RMSProp 使用**指数衰减平均**(递归定义)以丢弃遥远的历史,使其能够在找到某个“凸”结构后快速收敛;此外,RMSProp 还加入了一个超参数 `ρ` 用于控制衰减速率。 - > ./术语表/[指数衰减平均](./Base-A-术语表.md#指数加权平均指数衰减平均) + > ./术语表/[指数衰减平均](./备忘-术语表#指数加权平均指数衰减平均) - 具体来说(对比 AdaGrad 的算法描述),即修改 `r` 为
记 @@ -226,7 +226,7 @@ Index - 梯度下降使用的梯度信息实际上是**一阶导数** - 牛顿法除了一阶导数外,还会使用**二阶导数**的信息 - 根据导数的定义,一阶导描述的是函数值的变化率,即**斜率**;二阶导描述的则是斜率的变化率,即曲线的弯曲程度——**曲率** - > 数学/[泰勒级数](../数学/微积分的本质.md#泰勒级数) + > 数学/[泰勒级数](../C-数学/B-微积分的本质#泰勒级数) **牛顿法更新过程** TODO > 《统计学习方法》 附录 B diff --git "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/D-\344\270\223\351\242\230-\345\272\217\345\210\227\345\273\272\346\250\241.md" "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/D-\344\270\223\351\242\230-\345\272\217\345\210\227\345\273\272\346\250\241.md" index 9515a95b..18b299b6 100644 --- "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/D-\344\270\223\351\242\230-\345\272\217\345\210\227\345\273\272\346\250\241.md" +++ "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/D-\344\270\223\351\242\230-\345\272\217\345\210\227\345\273\272\346\250\241.md" @@ -2,8 +2,8 @@ === **相关专题** -- [专题-RNN](./DL-B-专题-RNN.md) -- [专题-DNN](./DL-B-专题-DNN.md) +- [专题-RNN](./B-专题-RNN.md) +- [专题-RNN](./B-专题-RNN.md) Index --- @@ -11,21 +11,21 @@ Index - [序列建模简述](#序列建模简述) - [Seq2Seq](#seq2seq) - - [解码方法(贪心、Beam Search、维特比算法)](#解码方法贪心beam-search维特比算法) - - [Beam Search(集束搜索)](#beam-search集束搜索) - - [维特比(Viterbi)算法 TODO](#维特比viterbi算法-todo) - - [其他最短路径算法](#其他最短路径算法) - - [构建 Seq2Seq 一般做法](#构建-seq2seq-一般做法) + - [解码方法(贪心、Beam Search、维特比算法)](#解码方法贪心beam-search维特比算法) + - [Beam Search(集束搜索)](#beam-search集束搜索) + - [维特比(Viterbi)算法 TODO](#维特比viterbi算法-todo) + - [其他最短路径算法](#其他最短路径算法) + - [构建 Seq2Seq 一般做法](#构建-seq2seq-一般做法) - [序列的表示学习](#序列的表示学习) - - [学习任务无关的 Sentence Embedding](#学习任务无关的-sentence-embedding) + - [学习任务无关的 Sentence Embedding](#学习任务无关的-sentence-embedding) - [CNN 与序列建模](#cnn-与序列建模) - - [一维卷积](#一维卷积) + - [一维卷积](#一维卷积) - [时间卷积网络(TCN)](#时间卷积网络tcn) - - [WaveNet](#wavenet) - - [因果卷积](#因果卷积) - - [空洞卷积](#空洞卷积) - - [Highway 网络](#highway-网络) - - [残差模块](#残差模块) + - [WaveNet](#wavenet) + - [因果卷积](#因果卷积) + - [空洞卷积](#空洞卷积) + - [Highway 网络](#highway-网络) + - [残差模块](#残差模块) - [Reference](#reference) @@ -33,51 +33,51 @@ Index ## 序列建模简述 > [从循环到卷积,探索序列建模的奥秘](https://mp.weixin.qq.com/s/f0sv7c-H5o5L_wy2sUonUQ) - 机器之心 - 序列建模就是将一个**输入/观测**序列映射到一个**输出/标记**序列 - > 《统计学习方法》中称之为标注问题 + > 《统计学习方法》中称之为标注问题 - 在**传统机器学习**方法中,常用的模型有:隐马尔可夫模型(HMM),条件随机场(CRF)等 - > 机器学习专题 TODO + > 机器学习专题 TODO - 在**深度学习领域**的很长一段时间里,RNN/LSTM 都是序列建模的首选。 - > 《深度学习》 10 序列建模:循环和递归网络 + > 《深度学习》 10 序列建模:循环和递归网络 - 最近,CNN 开始在序列建模领域流行,一个**关键想法**是——在一维时间序列上使用**一维卷积运算** -
+
- > [CNN for Sentence Classification](https://arxiv.org/abs/1408.5882) (Kim, 2014) + > [CNN for Sentence Classification](https://arxiv.org/abs/1408.5882) (Kim, 2014) ## Seq2Seq - Seq2Seq 的核心思想是把一个输出序列,通过**编码**(Encode)和**解码**(Decode)两个过程映射到一个新的输出序列。 -
- - > [Translation with a Sequence to Sequence Network and Attention](https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html) — PyTorch +
+ + > [Translation with a Sequence to Sequence Network and Attention](https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html) — PyTorch - 经典的 Seq2Seq 模型中,**编码器**(Encoder)和**解码器**(Decoder)都使用 **RNN** 进行建模 - -
- - > 上图是一次**机器翻译**的过程,输入是一个源语言的一个句子 "A B C",Encoder 一次读入每个单词直到结束符 ``(End of Sequence);
- > 在解码的第一步,Decoder 先读取 **Encoder 的最终状态**,生成目标语言的第一个词 'W',接着 Decoder 读取第一步的输出 'W' 作为第二步的输入,进而生成第二个词 'X',如此直到生成 `` 或达到指定**最大长度**。 - >> Decoder 生成每个词还要结合当前时间步的隐状态(如果是 LSTM 还有 记忆状态),更深入的细节暂时略过。 + +
+ + > 上图是一次**机器翻译**的过程,输入是一个源语言的一个句子 "A B C",Encoder 一次读入每个单词直到结束符 ``(End of Sequence);
+ > 在解码的第一步,Decoder 先读取 **Encoder 的最终状态**,生成目标语言的第一个词 'W',接着 Decoder 读取第一步的输出 'W' 作为第二步的输入,进而生成第二个词 'X',如此直到生成 `` 或达到指定**最大长度**。 + >> Decoder 生成每个词还要结合当前时间步的隐状态(如果是 LSTM 还有 记忆状态),更深入的细节暂时略过。 - Seq2Seq 之所以流行,是因为它为不同的问题提供了一套**端到端**(End to End)的解决方案,免去了繁琐的中间步骤,从输入直接得到结果. - 根据任务的输入输出差异,编码器和解码器的设计也不尽相同,但是“Encoder-Decoder”的结构都是一致的。 - - **机器翻译**:输入源语言的一个句子,输出目标语言的句子; - - **机器问答**:输入问题/查询,输出答案; - - **文本摘要**:输入一个长句或段落,输出一个摘要短句; - - **语音识别**:输入是音频序列信号,输出为识别出的文本; - - **图像描述**:输入是图像经过视觉网络的特征,输出是图像的描述文本。 - - ... + - **机器翻译**:输入源语言的一个句子,输出目标语言的句子; + - **机器问答**:输入问题/查询,输出答案; + - **文本摘要**:输入一个长句或段落,输出一个摘要短句; + - **语音识别**:输入是音频序列信号,输出为识别出的文本; + - **图像描述**:输入是图像经过视觉网络的特征,输出是图像的描述文本。 + - ... ### 解码方法(贪心、Beam Search、维特比算法) - Seq2Seq 中的解码方法主要有三种:**贪心**、**Beam Search**、**维特比算法**(动态规划) - 这三种方法的思想本质上是一致的,假设选取相同的评价标准(比如概率最大、路径最短等) - - **贪心**每到达一个节点,只选择当前状态的**最优结果**,其他都忽略,直到最后一个节点;贪心法只能得到某个局部最优解; - - **Beam Search** 会在每个节点保存当前**最优的 k 个结果**(排序后),其他结果将被“剪枝”,因为每次都有 k 个分支进入下一个状态。Beam Search 也不能保证全局最优,但能以较大的概率得到全局最优解。 - - **维特比算法**利用**动态规划**的方法可以保证得到全局最优解,但是当候选状态极大时,需要消耗大量的时间和空间搜索和保存状态,因此维特比算法只适合状态集比较小的情况。 + - **贪心**每到达一个节点,只选择当前状态的**最优结果**,其他都忽略,直到最后一个节点;贪心法只能得到某个局部最优解; + - **Beam Search** 会在每个节点保存当前**最优的 k 个结果**(排序后),其他结果将被“剪枝”,因为每次都有 k 个分支进入下一个状态。Beam Search 也不能保证全局最优,但能以较大的概率得到全局最优解。 + - **维特比算法**利用**动态规划**的方法可以保证得到全局最优解,但是当候选状态极大时,需要消耗大量的时间和空间搜索和保存状态,因此维特比算法只适合状态集比较小的情况。 #### Beam Search(集束搜索) - Beam Search 是一种启发式算法 - 该方法会保存前 `beam_size` 个最佳状态,每次解码时会根据所有保存的状态进行下一步**扩展**和**排序**,依然只保留前 `beam_size` 个最佳状态;循环迭代至最后一步,保存最佳选择。 - Beam Search 图示 -
+
- 当 `beam_size = 1` 时,Beam Search 即退化为贪心搜索 - 一般为了计算资源和性能的平衡,`beam_size` 会选择一个适中的范围;通常 `beam_size` 取 `8~12` 即可(机器翻译、文本摘要) @@ -89,22 +89,22 @@ Index #### 其他最短路径算法 - Dijkstra 算法(迪杰斯特拉算法) - - 基于贪心 - - 用于求解某个顶点到其他所有顶点之间的最短路径 - - 时间复杂度 `O(N^2)` - - Dijkstra 算法的使用范围比 Viterbi 算法更广,可用于求解大部分图结构中的最短路径。 + - 基于贪心 + - 用于求解某个顶点到其他所有顶点之间的最短路径 + - 时间复杂度 `O(N^2)` + - Dijkstra 算法的使用范围比 Viterbi 算法更广,可用于求解大部分图结构中的最短路径。 - Floyd 算法(弗洛伊德算法) - - 求解的是每一对顶点之间的最短路径 - - 时间复杂度 `O(N^3)` + - 求解的是每一对顶点之间的最短路径 + - 时间复杂度 `O(N^3)` ### 构建 Seq2Seq 一般做法 - 堆叠 RNN/CNN - > [CNN 与序列建模](#cnn-与序列建模) + > [CNN 与序列建模](#cnn-与序列建模) - Dropout 机制 - **残差**连接 - **Attention 机制** - > [Attention 专题](./DL-C-专题-Attention.md) + ## 序列的表示学习 @@ -122,21 +122,21 @@ Index ## CNN 与序列建模 - 一般认为 CNN 擅长处理**网格结构的数据**,比如图像(二维像素网络) - - 卷积层试图将神经网络中的每一小块进行更加深入的分析,从而得出抽象程度更高的特征。 - - 一般来说通过卷积层处理的神经元结点矩阵会变得更深,即神经元的组织在第三个维度上会增加。 + - 卷积层试图将神经网络中的每一小块进行更加深入的分析,从而得出抽象程度更高的特征。 + - 一般来说通过卷积层处理的神经元结点矩阵会变得更深,即神经元的组织在第三个维度上会增加。 - **时序数据**同样可以认为是在时间轴上有规律地采样而形成的一维网格 -
+
- > [CNN for Sentence Classification](https://arxiv.org/abs/1408.5882) (Kim, 2014) + > [CNN for Sentence Classification](https://arxiv.org/abs/1408.5882) (Kim, 2014) ### 一维卷积 - 适用于序列建模的卷积网络一般就是采用的是一维卷积 -
+
- - 最下层的 `x_i` 可视为句子的输入序列 - - 最上层的 `g_j` 即输出序列 - - 流行的网络中一般使用 **embedding** 作为输入,也就说每个 `x_i` 其实是一个多维向量 `v(x_i)` - > [NLP-词向量](./NLP-词向量.md) + - 最下层的 `x_i` 可视为句子的输入序列 + - 最上层的 `g_j` 即输出序列 + - 流行的网络中一般使用 **embedding** 作为输入,也就说每个 `x_i` 其实是一个多维向量 `v(x_i)` + > ../自然语言处理/[词向量](../B-自然语言处理/B-专题-词向量.md) ## 时间卷积网络(TCN) diff --git "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/\345\244\207\345\277\230-\346\234\257\350\257\255\350\241\250.md" "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/\345\244\207\345\277\230-\346\234\257\350\257\255\350\241\250.md" index f8851210..9299ed92 100644 --- "a/A-\346\267\261\345\272\246\345\255\246\344\271\240/\345\244\207\345\277\230-\346\234\257\350\257\255\350\241\250.md" +++ "b/A-\346\267\261\345\272\246\345\255\246\344\271\240/\345\244\207\345\277\230-\346\234\257\350\257\255\350\241\250.md" @@ -6,36 +6,36 @@ Index - [指数加权平均(指数衰减平均)](#指数加权平均指数衰减平均) - - [偏差修正](#偏差修正) + - [偏差修正](#偏差修正) ## 指数加权平均(指数衰减平均) > [什么是指数加权平均、偏差修正? - 郭耀华](http://www.cnblogs.com/guoyaohua/p/8544835.html) - 博客园 - **加权平均** - - 假设 `θi` 的权重分别为 `ρi`,则 `θi` 的加权平均为: -
+ - 假设 `θi` 的权重分别为 `ρi`,则 `θi` 的加权平均为: +
- **指数加权平均** -
+
- > 注意到越久前的记录其权重呈**指数衰减**,因此指数加权平均也称**指数衰减平均** + > 注意到越久前的记录其权重呈**指数衰减**,因此指数加权平均也称**指数衰减平均** - **示例**:设 `ρ=0.9, v0=0` -
- - > 其中 `v_t` 可以**近似**认为是最近 `1/1-ρ` 个值的滑动平均(`ρ=0.9`时,`0.1 * 0.9^9 ≈ 0.038`),更久前的记录其权重已近似为 0。 +
+ + > 其中 `v_t` 可以**近似**认为是最近 `1/1-ρ` 个值的滑动平均(`ρ=0.9`时,`0.1 * 0.9^9 ≈ 0.038`),更久前的记录其权重已近似为 0。 ### 偏差修正 - 指数加权平均在前期会存在较大的**误差** -
- - - 注意到只有当 `t -> ∞` 时,所有权重的和才接近 1,当 `t` 比较小时,并不是标准的加权平均 +
+ + - 注意到只有当 `t -> ∞` 时,所有权重的和才接近 1,当 `t` 比较小时,并不是标准的加权平均 - **示例**:设 `ρ=0.9, v0=0` -
+
- - 当 `t` 较小时,与希望的加权平均结果差距较大 + - 当 `t` 较小时,与希望的加权平均结果差距较大 - **引入偏差修正** -
+
- - 偏差修正只对**前期**的有修正效果,**后期**当 `t` 逐渐增大时 `1-ρ^t -> 1`,将不再影响 `v_t`,与期望相符 \ No newline at end of file + - 偏差修正只对**前期**的有修正效果,**后期**当 `t` 逐渐增大时 `1-ρ^t -> 1`,将不再影响 `v_t`,与期望相符 \ No newline at end of file diff --git "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\237\272\347\241\200.md" "b/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\237\272\347\241\200.md" index f5e4f0c9..006dd497 100644 --- "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\237\272\347\241\200.md" +++ "b/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\237\272\347\241\200.md" @@ -6,28 +6,28 @@ Index - [NLP 概述](#nlp-概述) - - [解决 NLP 问题的一般思路](#解决-nlp-问题的一般思路) - - [NLP 的历史进程](#nlp-的历史进程) - - [Seq2Seq 模型](#seq2seq-模型) - - [评价机制](#评价机制) - - [困惑度 (Perplexity, PPX)](#困惑度-perplexity-ppx) - - [BLEU](#bleu) - - [ROUGE](#rouge) + - [解决 NLP 问题的一般思路](#解决-nlp-问题的一般思路) + - [NLP 的历史进程](#nlp-的历史进程) + - [Seq2Seq 模型](#seq2seq-模型) + - [评价机制](#评价机制) + - [困惑度 (Perplexity, PPX)](#困惑度-perplexity-ppx) + - [BLEU](#bleu) + - [ROUGE](#rouge) - [语言模型](#语言模型) - - [XX 模型的含义](#xx-模型的含义) - - [概率/统计语言模型 (PLM, SLM)](#概率统计语言模型-plm-slm) - - [参数的规模](#参数的规模) - - [可用的概率模型](#可用的概率模型) - - [N-gram 语言模型](#n-gram-语言模型) - - [可靠性与可区别性](#可靠性与可区别性) - - [OOV 问题](#oov-问题) - - [平滑处理 TODO](#平滑处理-todo) - - [神经概率语言模型 (NPLM)](#神经概率语言模型-nplm) - - [N-gram 神经语言模型](#n-gram-神经语言模型) - - [N-gram 神经语言模型的网络结构](#n-gram-神经语言模型的网络结构) - - [模型参数的规模与运算量](#模型参数的规模与运算量) - - [相比 N-gram 模型,NPLM 的优势](#相比-n-gram-模型nplm-的优势) - - [NPLM 中的 OOV 问题](#nplm-中的-oov-问题) + - [XX 模型的含义](#xx-模型的含义) + - [概率/统计语言模型 (PLM, SLM)](#概率统计语言模型-plm-slm) + - [参数的规模](#参数的规模) + - [可用的概率模型](#可用的概率模型) + - [N-gram 语言模型](#n-gram-语言模型) + - [可靠性与可区别性](#可靠性与可区别性) + - [OOV 问题](#oov-问题) + - [平滑处理 TODO](#平滑处理-todo) + - [神经概率语言模型 (NPLM)](#神经概率语言模型-nplm) + - [N-gram 神经语言模型](#n-gram-神经语言模型) + - [N-gram 神经语言模型的网络结构](#n-gram-神经语言模型的网络结构) + - [模型参数的规模与运算量](#模型参数的规模与运算量) + - [相比 N-gram 模型,NPLM 的优势](#相比-n-gram-模型nplm-的优势) + - [NPLM 中的 OOV 问题](#nplm-中的-oov-问题) @@ -42,88 +42,87 @@ Index ## NLP 的历史进程 - **规则系统** - - 正则表达式/自动机 - - 规则是固定的 - - **搜索引擎** - ```tex - “豆瓣酱用英语怎么说?” - 规则:“xx用英语怎么说?” => translate(XX, English) - - “我饿了” - 规则:“我饿(死)了” => recommend(饭店,地点) - ``` + - 正则表达式/自动机 + - 规则是固定的 + - **搜索引擎** + ```tex + “豆瓣酱用英语怎么说?” + 规则:“xx用英语怎么说?” => translate(XX, English) + + “我饿了” + 规则:“我饿(死)了” => recommend(饭店,地点) + ``` - **概率系统** - - 规则从数据中**抽取** - - 规则是有**概率**的 - - 概率系统的一般**工作方式** - ```tex - 流程设计 - 收集训练数据 - 预处理 - 特征工程 - 分类器(机器学习算法) - 预测 - 评价 - ``` -
- - - 最重要的部分:数据收集、预处理、特征工程 - - 示例 - ```tex - 任务: - “豆瓣酱用英语怎么说” => translate(豆瓣酱,Eng) - - 流程设计(序列标注): - 子任务1: 找出目标语言 “豆瓣酱用 **英语** 怎么说” - 子任务2: 找出翻译目标 “ **豆瓣酱** 用英语怎么说” - - 收集训练数据: - (子任务1) - “豆瓣酱用英语怎么说” - “茄子用英语怎么说” - “黄瓜怎么翻译成英语” - - 预处理: - 分词:“豆瓣酱 用 英语 怎么说” - - 抽取特征: - (前后各一个词) - 0 茄子: < _ 用 - 0 用: 豆瓣酱 _ 英语 - 1 英语: 用 _ 怎么说 - 0 怎么说: 英语 _ > - - 分类器: - SVM/CRF/HMM/RNN - - 预测: - 0.1 茄子: < _ 用 - 0.1 用: 豆瓣酱 _ 英语 - 0.7 英语: 用 _ 怎么说 - 0.1 怎么说: 英语 _ > - - 评价: - 准确率 - ``` + - 规则从数据中**抽取** + - 规则是有**概率**的 + - 概率系统的一般**工作方式** + ```tex + 流程设计 + 收集训练数据 + 预处理 + 特征工程 + 分类器(机器学习算法) + 预测 + 评价 + ``` +
+ + - 最重要的部分:数据收集、预处理、特征工程 + - 示例 + ```tex + 任务: + “豆瓣酱用英语怎么说” => translate(豆瓣酱,Eng) + + 流程设计(序列标注): + 子任务1: 找出目标语言 “豆瓣酱用 **英语** 怎么说” + 子任务2: 找出翻译目标 “ **豆瓣酱** 用英语怎么说” + + 收集训练数据: + (子任务1) + “豆瓣酱用英语怎么说” + “茄子用英语怎么说” + “黄瓜怎么翻译成英语” + + 预处理: + 分词:“豆瓣酱 用 英语 怎么说” + + 抽取特征: + (前后各一个词) + 0 茄子: < _ 用 + 0 用: 豆瓣酱 _ 英语 + 1 英语: 用 _ 怎么说 + 0 怎么说: 英语 _ > + + 分类器: + SVM/CRF/HMM/RNN + + 预测: + 0.1 茄子: < _ 用 + 0.1 用: 豆瓣酱 _ 英语 + 0.7 英语: 用 _ 怎么说 + 0.1 怎么说: 英语 _ > + + 评价: + 准确率 + ``` - 概率系统的优/缺点 - - `+` 规则更加贴近于真实事件中的规则,因而效果往往比较好 - - `-` 特征是由专家/人指定的; - - `-` 流程是由专家/人设计的; - - `-` 存在独立的**子任务** + - `+` 规则更加贴近于真实事件中的规则,因而效果往往比较好 + - `-` 特征是由专家/人指定的; + - `-` 流程是由专家/人设计的; + - `-` 存在独立的**子任务** - **深度学习** - - 深度学习相对概率模型的优势 - - 特征是由专家指定的 `->` 特征是由深度学习自己提取的 - - 流程是由专家设计的 `->` 模型结构是由专家设计的 - - 存在独立的子任务 `->` End-to-End Training + - 深度学习相对概率模型的优势 + - 特征是由专家指定的 `->` 特征是由深度学习自己提取的 + - 流程是由专家设计的 `->` 模型结构是由专家设计的 + - 存在独立的子任务 `->` End-to-End Training ## Seq2Seq 模型 -> [NLP-序列建模](./NLP-序列建模.md) - 大部分自然语言问题都可以使用 Seq2Seq 模型解决 -
+
- **“万物”皆 Seq2Seq** -
+
## 评价机制 @@ -131,28 +130,28 @@ Index ### 困惑度 (Perplexity, PPX) > [Perplexity](https://en.wikipedia.org/wiki/Perplexity) - Wikipedia - 在信息论中,perplexity 用于度量一个**概率分布**或**概率模型**预测样本的好坏程度 - > 机器学习/[信息论](../机器学习/README.md#信息论) + > ../机器学习/[信息论](../A-机器学习/A-机器学习基础#信息论)

基本公式

- **概率分布**(离散)的困惑度 -
- - > 其中 `H(p)` 即**信息熵** +
+ + > 其中 `H(p)` 即**信息熵** - **概率模型**的困惑度 -
+
- > 通常 `b=2` + > 通常 `b=2` - **指数部分**也可以是**交叉熵**的形式,此时困惑度相当于交叉熵的指数形式 -
+
- > 其中 `p~` 为**测试集**中的经验分布——`p~(x) = n/N`,其中 `n` 为 x 的出现次数,N 为测试集的大小 + > 其中 `p~` 为**测试集**中的经验分布——`p~(x) = n/N`,其中 `n` 为 x 的出现次数,N 为测试集的大小 **语言模型中的 PPX** - 在 **NLP** 中,困惑度常作为**语言模型**的评价指标 -
+
- 直观来说,就是下一个**候选词数目**的期望值—— @@ -162,19 +161,19 @@ Index > [一种机器翻译的评价准则——BLEU](https://blog.csdn.net/qq_21190081/article/details/53115580) - CSDN博客 - 机器翻译评价准则 - 计算公式 -
+
其中 -
-
- +
+
+ - > `c` 为生成句子的长度;`r` 为参考句子的长度——目的是**惩罚**长度过短的候选句子 + > `c` 为生成句子的长度;`r` 为参考句子的长度——目的是**惩罚**长度过短的候选句子 - 为了计算方便,会加一层 `log` -
- - > 通常 `N=4, w_n=1/4` +
+ + > 通常 `N=4, w_n=1/4` ### ROUGE > [自动文摘评测方法:Rouge-1、Rouge-2、Rouge-L、Rouge-S](https://blog.csdn.net/qq_25222361/article/details/78694617) - CSDN博客 @@ -187,25 +186,25 @@ Index ## XX 模型的含义 - 如果能使用某个方法对 XX **打分**(Score),那么就可以把这个方法称为 “**XX 模型**” - - **篮球明星模型**: `Score(库里)`、`Score(詹姆斯)` - - **话题模型**——对一段话是否在谈论某一话题的打分 - ``` - Score( NLP | "什么 是 语言 模型?" ) --> 0.8 - Score( ACM | "什么 是 语言 模型?" ) --> 0.05 - ``` + - **篮球明星模型**: `Score(库里)`、`Score(詹姆斯)` + - **话题模型**——对一段话是否在谈论某一话题的打分 + ``` + Score( NLP | "什么 是 语言 模型?" ) --> 0.8 + Score( ACM | "什么 是 语言 模型?" ) --> 0.05 + ``` ## 概率/统计语言模型 (PLM, SLM) - **语言模型**是一种对语言打分的方法;而**概率语言模型**把语言的“得分”通过**概率**来体现 - 具体来说,概率语言模型计算的是**一个序列**作为一句话可能的概率 - ``` - Score("什么 是 语言 模型") --> 0.05 # 比较常见的说法,得分比较高 - Score("什么 有 语言 模型") --> 0.01 # 不太常见的说法,得分比较低 - ``` + ``` + Score("什么 是 语言 模型") --> 0.05 # 比较常见的说法,得分比较高 + Score("什么 有 语言 模型") --> 0.01 # 不太常见的说法,得分比较低 + ``` - 以上过程可以形式化为: -
+
根据贝叶斯公式,有 -
+
- 其中每个条件概率就是**模型的参数**;如果这个参数都是已知的,那么就能得到整个序列的概率了 @@ -221,16 +220,16 @@ Index ## N-gram 语言模型 - 马尔可夫(Markov)假设——未来的事件,只取决于有限的历史 - 基于马尔可夫假设,N-gram 语言模型认为一个词出现的概率只与它前面的 n-1 个词相关 -
+
- 根据**条件概率公式**与**大数定律**,当语料的规模足够大时,有 -
+
- 以 `n=2` 即 bi-gram 为例,有 -
+
- 假设词表的规模 `N=200000`(汉语的词汇量),模型参数与 `n· 的关系表 -
+
### 可靠性与可区别性 - 假设没有计算和存储限制,`n` 是不是越大越好? @@ -242,96 +241,96 @@ Index - OOV 即 Out Of Vocabulary,也就是序列中出现了词表外词,或称为**未登录词** - 或者说在测试集和验证集上出现了训练集中没有过的词 - 一般**解决方案**: - - 设置一个词频阈值,只有高于该阈值的词才会加入词表 - - 所有低于阈值的词替换为 UNK(一个特殊符号) + - 设置一个词频阈值,只有高于该阈值的词才会加入词表 + - 所有低于阈值的词替换为 UNK(一个特殊符号) - 无论是统计语言模型还是神经语言模型都是类似的处理方式 - > [NPLM 中的 OOV 问题](#nplm-中的-oov-问题) + > [NPLM 中的 OOV 问题](#nplm-中的-oov-问题) ### 平滑处理 TODO - `count(W) = 0` 是怎么办? - 平滑方法(层层递进): - - Add-one Smoothing (Laplace) - - Add-k Smoothing (k<1) - - Back-off (回退) - - Interpolation (插值法) - - Absolute Discounting (绝对折扣法) - - Kneser-Ney Smoothing (KN) - - Modified Kneser-Ney - > [自然语言处理中N-Gram模型的Smoothing算法](https://blog.csdn.net/baimafujinji/article/details/51297802) - CSDN博客 + - Add-one Smoothing (Laplace) + - Add-k Smoothing (k<1) + - Back-off (回退) + - Interpolation (插值法) + - Absolute Discounting (绝对折扣法) + - Kneser-Ney Smoothing (KN) + - Modified Kneser-Ney + > [自然语言处理中N-Gram模型的Smoothing算法](https://blog.csdn.net/baimafujinji/article/details/51297802) - CSDN博客 ## 神经概率语言模型 (NPLM) -> [专题-词向量](./专题-词向量.md) +> [专题-词向量](./B-专题-词向量) - 神经概率语言模型依然是一个概率语言模型,它通过**神经网络**来计算概率语言模型中每个参数 -
+
- - 其中 `g` 表示神经网络,`i_w` 为 `w` 在词表中的序号,`context(w)` 为 `w` 的上下文,`V_context` 为上下文构成的特征向量。 - - `V_context` 由上下文的**词向量**进一步组合而成 + - 其中 `g` 表示神经网络,`i_w` 为 `w` 在词表中的序号,`context(w)` 为 `w` 的上下文,`V_context` 为上下文构成的特征向量。 + - `V_context` 由上下文的**词向量**进一步组合而成 ### N-gram 神经语言模型 > [A Neural Probabilistic Language Model](http://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf) (Bengio, et al., 2003) - 这是一个经典的神经概率语言模型,它沿用了 N-gram 模型中的思路,将 `w` 的前 `n-1` 个词作为 `w` 的上下文 `context(w)`,而 `V_context` 由这 `n-1` 个词的词向量拼接而成,即 -
+
- - 其中 `c(w)` 表示 `w` 的词向量 - - 不同的神经语言模型中 `context(w)` 可能不同,比如 Word2Vec 中的 CBOW 模型 + - 其中 `c(w)` 表示 `w` 的词向量 + - 不同的神经语言模型中 `context(w)` 可能不同,比如 Word2Vec 中的 CBOW 模型 - 每个训练样本是形如 `(context(w), w)` 的二元对,其中 `context(w)` 取 w 的前 `n-1` 个词;当不足 `n-1`,用特殊符号填充 - - 同一个网络只能训练特定的 `n`,不同的 `n` 需要训练不同的神经网络 + - 同一个网络只能训练特定的 `n`,不同的 `n` 需要训练不同的神经网络 #### N-gram 神经语言模型的网络结构 - - 【**输入层**】首先,将 `context(w)` 中的每个词映射为一个长为 `m` 的词向量,**词向量在训练开始时是随机的**,并**参与训练**; - - 【**投影层**】将所有上下文词向量**拼接**为一个长向量,作为 `w` 的特征向量,该向量的维度为 `m(n-1)` - - 【**隐藏层**】拼接后的向量会经过一个规模为 `h` 隐藏层,该隐层使用的激活函数为 `tanh` - - 【**输出层**】最后会经过一个规模为 `N` 的 Softmax 输出层,从而得到词表中每个词作为下一个词的概率分布 - > 其中 `m, n, h` 为超参数,`N` 为词表大小,视训练集规模而定,也可以人为设置阈值 - - 训练时,使用**交叉熵**作为损失函数 - - **当训练完成时**,就得到了 N-gram 神经语言模型,以及副产品**词向量** - - 整个模型可以概括为如下公式: +- 【**输入层**】首先,将 `context(w)` 中的每个词映射为一个长为 `m` 的词向量,**词向量在训练开始时是随机的**,并**参与训练**; +- 【**投影层**】将所有上下文词向量**拼接**为一个长向量,作为 `w` 的特征向量,该向量的维度为 `m(n-1)` +- 【**隐藏层**】拼接后的向量会经过一个规模为 `h` 隐藏层,该隐层使用的激活函数为 `tanh` +- 【**输出层**】最后会经过一个规模为 `N` 的 Softmax 输出层,从而得到词表中每个词作为下一个词的概率分布 +> 其中 `m, n, h` 为超参数,`N` 为词表大小,视训练集规模而定,也可以人为设置阈值 +- 训练时,使用**交叉熵**作为损失函数 +- **当训练完成时**,就得到了 N-gram 神经语言模型,以及副产品**词向量** +- 整个模型可以概括为如下公式:

- > 原文的模型还考虑了投影层与输出层有有边相连的情形,因而会多一个权重矩阵,但本质上是一致的: - >>

- >>
+ > 原文的模型还考虑了投影层与输出层有有边相连的情形,因而会多一个权重矩阵,但本质上是一致的: + >>

+ >>
### 模型参数的规模与运算量 - 模型的超参数:`m, n, h, N` - - `m` 为词向量的维度,通常在 `10^1 ~ 10^2` - - `n` 为 n-gram 的规模,一般小于 5 - - `h` 为隐藏的单元数,一般在 `10^2` - - `N` 位词表的数量,一般在 `10^4 ~ 10^5`,甚至 `10^6` + - `m` 为词向量的维度,通常在 `10^1 ~ 10^2` + - `n` 为 n-gram 的规模,一般小于 5 + - `h` 为隐藏的单元数,一般在 `10^2` + - `N` 位词表的数量,一般在 `10^4 ~ 10^5`,甚至 `10^6` - 网络参数包括两部分 - - 词向量 `C`: 一个 `N * m` 的矩阵——其中 `N` 为词表大小,`m` 为词向量的维度 - - 网络参数 `W, U, p, q`: - ``` - - W: h * m(n-1) 的矩阵 - - p: h * 1 的矩阵 - - U: N * h 的矩阵 - - q: N * 1 的矩阵 - ``` + - 词向量 `C`: 一个 `N * m` 的矩阵——其中 `N` 为词表大小,`m` 为词向量的维度 + - 网络参数 `W, U, p, q`: + ``` + - W: h * m(n-1) 的矩阵 + - p: h * 1 的矩阵 + - U: N * h 的矩阵 + - q: N * 1 的矩阵 + ``` - 模型的运算量 - - 主要集中在隐藏层和输出层的矩阵运算以及 SoftMax 的归一化计算 - - 此后的相关研究中,主要是针对这一部分进行优化,其中就包括 **Word2Vec** 的工作 + - 主要集中在隐藏层和输出层的矩阵运算以及 SoftMax 的归一化计算 + - 此后的相关研究中,主要是针对这一部分进行优化,其中就包括 **Word2Vec** 的工作 ### 相比 N-gram 模型,NPLM 的优势 - 单词之间的相似性可以通过词向量来体现 - > 相比神经语言模型本身,作为其副产品的词向量反而是更大的惊喜 - > - > [词向量的理解](./专题-词向量.md#词向量的理解) + > 相比神经语言模型本身,作为其副产品的词向量反而是更大的惊喜 + > + > [词向量的理解](./B-专题-词向量#词向量的理解) - 自带平滑处理 ### NPLM 中的 OOV 问题 - 在处理语料阶段,与 N-gram 中的处理方式是一样的——将不满阈值的词全部替换为 UNK **神经网络**中,一般有如下几种处理 UNK 的思路 - 为 UNK 分配一个随机初始化的 embedding,并**参与训练** - > 最终得到的 embedding 会有一定的语义信息,但具体好坏未知 + > 最终得到的 embedding 会有一定的语义信息,但具体好坏未知 - 把 UNK 都初始化成 0 向量,**不参与训练** - > UNK 共享相同的语义信息 + > UNK 共享相同的语义信息 - 每次都把 UNK 初始化成一个新的随机向量,**不参与训练** - > 常用的方法——因为本身每个 UNK 都不同,随机更符合对 UNK 基于最大熵的估计 - >> [How to add new embeddings for unknown words in Tensorflow (training & pre-set for testing)](https://stackoverflow.com/questions/45113130/how-to-add-new-embeddings-for-unknown-words-in-tensorflow-training-pre-set-fo) - Stack Overflow - >> - >> [Initializing Out of Vocabulary (OOV) tokens](https://stackoverflow.com/questions/45495190/initializing-out-of-vocabulary-oov-tokens) - Stack Overflow + > 常用的方法——因为本身每个 UNK 都不同,随机更符合对 UNK 基于最大熵的估计 + >> [How to add new embeddings for unknown words in Tensorflow (training & pre-set for testing)](https://stackoverflow.com/questions/45113130/how-to-add-new-embeddings-for-unknown-words-in-tensorflow-training-pre-set-fo) - Stack Overflow + >> + >> [Initializing Out of Vocabulary (OOV) tokens](https://stackoverflow.com/questions/45495190/initializing-out-of-vocabulary-oov-tokens) - Stack Overflow - 基于 Char-Level 的方法 - > PaperWeekly 第七期 -- [基于Char-level的NMT OOV解决方案](https://zhuanlan.zhihu.com/p/22700538?refer=paperweekly) + > PaperWeekly 第七期 -- [基于Char-level的NMT OOV解决方案](https://zhuanlan.zhihu.com/p/22700538?refer=paperweekly) diff --git "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\256\236\350\267\265.md" "b/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\256\236\350\267\265.md" deleted file mode 100644 index 30ae4a16..00000000 --- "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/A-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206\345\256\236\350\267\265.md" +++ /dev/null @@ -1,26 +0,0 @@ -NLP-自然语言处理实践 -=== - -Index ---- - - -## NLP 怎么做数据增强 -- 数据增强,具体来说就是对原数据集进行一定程度的改动,从而得到 - -### 双向翻译 -- 利用 NMT 做双向翻译——将语言A 翻译到其他语言,再翻译回语言 A
- 这个过程相当于对样本进行了改写,使得训练样本的数量大大增加 -- QANet 中的做法: -
- - - 对材料中每个句子通过翻译引擎得到`k`句法语候选,然后将每句法语转回英语,得到`k^2`个改写的句子,从中随机选择一句作为 - - 改写后答案的位置也可能改变,如何寻找**新答案的位置**?
- 具体到 SQuAD 任务就是 `(d,q,a) -> (d’, q, a’)`,问题不变,对文档 `d` 翻译改写,由于改写后原始答案 `a` 现在可能已经不在改写后的段落 `d’` 里了,所以需要从改写后的段落 `d’` 里抽取新的答案 `a’`,采用的方法是计算 `d’` 里每个单词和原始答案里 start/end words 之间的 **character-level 2-gram score**,分数最高的单词就被选择为新答案 `a’` 的 start/end word。 - > 中文没有里面没有 character-level 2-gram,可以考虑词向量之间的相似度 - -### 同义词替换 TODO -- 图像中对图片进行缩放、平移、旋转等操作不会改变图片本身含义;语音中对语音的声调、语速、噪声稍加改动也不会改变其结果 -- 文本中能做的类似改动比较少,同义词替换算一种 - - 哪些词应当被替换 - - 应该是用哪个同义词来替换 \ No newline at end of file diff --git "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/B-\344\270\223\351\242\230-\345\217\245\345\220\221\351\207\217.md" "b/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/B-\344\270\223\351\242\230-\345\217\245\345\220\221\351\207\217.md" index 5730ebdd..6d5fd341 100644 --- "a/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/B-\344\270\223\351\242\230-\345\217\245\345\220\221\351\207\217.md" +++ "b/B-\350\207\252\347\204\266\350\257\255\350\250\200\345\244\204\347\220\206/B-\344\270\223\351\242\230-\345\217\245\345\220\221\351\207\217.md" @@ -10,25 +10,25 @@ Index - [基线模型](#基线模型) - - [基于统计的词袋模型(BoW)](#基于统计的词袋模型bow) - - [基于词向量的词袋模型](#基于词向量的词袋模型) - - [均值模型](#均值模型) - - [加权模型](#加权模型) - - [基于 RNN(任务相关)](#基于-rnn任务相关) - - [基于 CNN(任务相关)](#基于-cnn任务相关) + - [基于统计的词袋模型(BoW)](#基于统计的词袋模型bow) + - [基于词向量的词袋模型](#基于词向量的词袋模型) + - [均值模型](#均值模型) + - [加权模型](#加权模型) + - [基于 RNN(任务相关)](#基于-rnn任务相关) + - [基于 CNN(任务相关)](#基于-cnn任务相关) - [词袋模型](#词袋模型) - - [[2018] Power Mean 均值模型](#2018-power-mean-均值模型) - - [[2017] SIF 加权模型](#2017-sif-加权模型) + - [[2018] Power Mean 均值模型](#2018-power-mean-均值模型) + - [[2017] SIF 加权模型](#2017-sif-加权模型) - [无监督模型](#无监督模型) - - [[2015] Skip-Thought Vector](#2015-skip-thought-vector) - - [[2018] Quick-Thought Vectors](#2018-quick-thought-vectors) + - [[2015] Skip-Thought Vector](#2015-skip-thought-vector) + - [[2018] Quick-Thought Vectors](#2018-quick-thought-vectors) - [有监督模型](#有监督模型) - - [[2017] InferSent](#2017-infersent) - - [[2017] Self-Attention](#2017-self-attention) - - [[2015] DAN & RecNN](#2015-dan--recnn) + - [[2017] InferSent](#2017-infersent) + - [[2017] Self-Attention](#2017-self-attention) + - [[2015] DAN & RecNN](#2015-dan--recnn) - [多任务学习](#多任务学习) - - [[2018] 基于多任务的 Sentence Embedding(微软)](#2018-基于多任务的-sentence-embedding微软) - - [[2018] Universal Sentence Encoder(谷歌)](#2018-universal-sentence-encoder谷歌) + - [[2018] 基于多任务的 Sentence Embedding(微软)](#2018-基于多任务的-sentence-embedding微软) + - [[2018] Universal Sentence Encoder(谷歌)](#2018-universal-sentence-encoder谷歌) - [参考文献](#参考文献) @@ -44,19 +44,19 @@ Index ### 基于词向量的词袋模型 #### 均值模型 -
+
- > 其中 `v_i` 表示维度为 `d` 的词向量,均值指的是对所有词向量**按位求和**后计算每一维的均值,最后 `s` 的维度与 `v` 相同。 +> 其中 `v_i` 表示维度为 `d` 的词向量,均值指的是对所有词向量**按位求和**后计算每一维的均值,最后 `s` 的维度与 `v` 相同。 #### 加权模型 -
+
- > 其中 `α` 可以有不同的选择,但一般应该遵循这样一个准则:**越常见的词权重越小** - >> [[2017] SIF 加权模型](#2017-sif-加权模型) +> 其中 `α` 可以有不同的选择,但一般应该遵循这样一个准则:**越常见的词权重越小** +>> [[2017] SIF 加权模型](#2017-sif-加权模型) ### 基于 RNN(任务相关) - 以最后一个隐状态作为整个句子的 Embedding -
+
- 基于 RNN 的 Sentence Embedding 往往用于特定的有监督任务中,**缺乏可迁移性**,在新的任务中需要重新训练; - 此外,由于 RNN 难以并行训练的缺陷,导致开销较大。 @@ -66,7 +66,7 @@ Index - 卷积的优势在于提取**局部特征**,利用 CNN 可以提取句子中类似 n-gram 的局部信息; - 通过整合不同大小的 n-gram 特征作为整个句子的表示。 -
+
## 词袋模型 @@ -75,38 +75,38 @@ Index > [4] - 本文是均值模型的一种推广;通过引入“幂均值”(Power Mean)来捕捉序列中的其他信息; - 记句子 `s=(x_1, x_2, ..., x_n)` -
+
- - `x_i` 为每个词的词向量,维度为 `d` - - 普通的均值模型即 `p=1` 时的特例; - - 特别说明,`±∞` 实际上指的是 `max`/`min`,而不是绝对值最大/最小 + - `x_i` 为每个词的词向量,维度为 `d` + - 普通的均值模型即 `p=1` 时的特例; + - 特别说明,`±∞` 实际上指的是 `max`/`min`,而不是绝对值最大/最小 - 本文通过**拼接**的方式来保留不同 `p` 的信息 -
+
- > 此时,Sentence Embedding 的维度应该是 **`K * d`** + > 此时,Sentence Embedding 的维度应该是 **`K * d`** - 进一步的,文本还加入了在**不同词嵌入空间**上的词向量,依然通过**拼接**的方式保留信息 - - 所谓**不同词嵌入空间**,指的就是使用不同算法在不同语料上训练得到的词向量 -
- - > 此时,Sentence Embedding 的维度应该是 **`K * L * d`** - - 本文使用了如下 **4 种词向量**: - - GloVe embeddings (GV) trained on Common Crawl - - Word2Vec trained on GoogleNews (GN) - - Attract-Repel (AR) (Mrksic et al., 2017) - - MorphSpecialized (MS) (Vulic et al., 2017) + - 所谓**不同词嵌入空间**,指的就是使用不同算法在不同语料上训练得到的词向量 +
+ + > 此时,Sentence Embedding 的维度应该是 **`K * L * d`** + - 本文使用了如下 **4 种词向量**: + - GloVe embeddings (GV) trained on Common Crawl + - Word2Vec trained on GoogleNews (GN) + - Attract-Repel (AR) (Mrksic et al., 2017) + - MorphSpecialized (MS) (Vulic et al., 2017) ### [2017] SIF 加权模型 - **文献 [1]** 提出了一个简单但有效的**加权词袋模型 SIF** (**Smooth Inverse Frequency**),其性能超过了简单的 RNN/CNN 模型 - **SIF** 的计算分为两步:
- **1)** 对句子中的每个词向量,乘以一个权重 `a/(a+p_w)`,其中 `a` 是一个常数(原文取 `0.0001`),`p_w` 为该词的词频;对于出现频率越高的词,其权重越小;
- **2)** 计算**句向量矩阵**的第一个主成分 `u`,让每个句向量减去它在 `u` 上的投影(类似 PCA); + **1)** 对句子中的每个词向量,乘以一个权重 `a/(a+p_w)`,其中 `a` 是一个常数(原文取 `0.0001`),`p_w` 为该词的词频;对于出现频率越高的词,其权重越小;
+ **2)** 计算**句向量矩阵**的第一个主成分 `u`,让每个句向量减去它在 `u` 上的投影(类似 PCA); - **完整算法描述** -
+
- [背景知识](#背景知识) - - [神经语言模型](#神经语言模型) - - [什么是词向量/词嵌入](#什么是词向量词嵌入) - - [词向量的理解 TODO](#词向量的理解-todo) + - [神经语言模型](#神经语言模型) + - [什么是词向量/词嵌入](#什么是词向量词嵌入) + - [词向量的理解 TODO](#词向量的理解-todo) - [Word2Vec](#word2vec) - - [基于层次 SoftMax 的 CBOW 模型](#基于层次-softmax-的-cbow-模型) - - [层次 SoftMax 的正向传播](#层次-softmax-的正向传播) - - [为什么层次 SoftMax 能加速](#为什么层次-softmax-能加速) - - [层次 Softmax 的反向传播 TODO](#层次-softmax-的反向传播-todo) - - [基于层次 Softmax 的 Skip-gram 模型](#基于层次-softmax-的-skip-gram-模型) - - [---](#---) - - [基于负采样的 CBOW 和 Skip-gram](#基于负采样的-cbow-和-skip-gram) - - [负采样算法](#负采样算法) - - [Word2Vec 中的做法](#word2vec-中的做法) - - [一些源码细节](#一些源码细节) - - [`σ(x)` 的近似计算](#σx-的近似计算) - - [低频词的处理](#低频词的处理) - - [高频词的处理](#高频词的处理) - - [自适应学习率](#自适应学习率) - - [参数初始化](#参数初始化) + - [基于层次 SoftMax 的 CBOW 模型](#基于层次-softmax-的-cbow-模型) + - [层次 SoftMax 的正向传播](#层次-softmax-的正向传播) + - [为什么层次 SoftMax 能加速](#为什么层次-softmax-能加速) + - [层次 Softmax 的反向传播 TODO](#层次-softmax-的反向传播-todo) + - [基于层次 Softmax 的 Skip-gram 模型](#基于层次-softmax-的-skip-gram-模型) + - [---](#---) + - [基于负采样的 CBOW 和 Skip-gram](#基于负采样的-cbow-和-skip-gram) + - [负采样算法](#负采样算法) + - [Word2Vec 中的做法](#word2vec-中的做法) + - [一些源码细节](#一些源码细节) + - [`σ(x)` 的近似计算](#σx-的近似计算) + - [低频词的处理](#低频词的处理) + - [高频词的处理](#高频词的处理) + - [自适应学习率](#自适应学习率) + - [参数初始化](#参数初始化) - [GloVe](#glove) - - [共现矩阵](#共现矩阵) - - [构架共现矩阵的细节](#构架共现矩阵的细节) - - [GloVe 的基本思想](#glove-的基本思想) - - [GloVe 的目标函数](#glove-的目标函数) - - [GloVe 目标函数的推导过程](#glove-目标函数的推导过程) - - [GloVe 与 Word2Vec 的区别](#glove-与-word2vec-的区别) + - [共现矩阵](#共现矩阵) + - [构架共现矩阵的细节](#构架共现矩阵的细节) + - [GloVe 的基本思想](#glove-的基本思想) + - [GloVe 的目标函数](#glove-的目标函数) + - [GloVe 目标函数的推导过程](#glove-目标函数的推导过程) + - [GloVe 与 Word2Vec 的区别](#glove-与-word2vec-的区别) - [FastText](#fasttext) - - [`gensim.models.FastText` 使用示例](#gensimmodelsfasttext-使用示例) - - [获取单个词的 ngrams 表示](#获取单个词的-ngrams-表示) - - [计算一个未登录词的词向量](#计算一个未登录词的词向量) + - [`gensim.models.FastText` 使用示例](#gensimmodelsfasttext-使用示例) + - [获取单个词的 ngrams 表示](#获取单个词的-ngrams-表示) + - [计算一个未登录词的词向量](#计算一个未登录词的词向量) - [WordRank TODO](#wordrank-todo) - [CharCNN 字向量](#charcnn-字向量) - [其他实践](#其他实践) - - [一般 embedding 维度的选择](#一般-embedding-维度的选择) + - [一般 embedding 维度的选择](#一般-embedding-维度的选择) # 背景知识 ## 神经语言模型 -> [神经语言模型](./README.md#神经概率语言模型-nplm) +> [神经语言模型](./A-自然语言处理基础#神经概率语言模型-nplm) ## 什么是词向量/词嵌入 - 词向量(word embedding)是一个固定长度的实值向量 @@ -63,62 +63,65 @@ Index - 分布式假设 - TODO - 常见的分布式表示方法 - - 潜在语义分析 (Latent Semantic Analysis, LSA) - - SVD 分解 - - 隐含狄利克雷分布 (Latent Dirichlet Allocation, LDA),主题模型 - - 神经网络、深度学习 + - 潜在语义分析 (Latent Semantic Analysis, LSA) + - SVD 分解 + - 隐含狄利克雷分布 (Latent Dirichlet Allocation, LDA),主题模型 + - 神经网络、深度学习 # Word2Vec - Word2Vec 本质上也是一个神经语言模型,但是它的目标并不是语言模型本身,而是词向量;因此,其所作的一系列优化,都是为了更快更好的得到词向量 - Word2Vec 提供了两套模型:**CBOW** 和 **Skip-Gram**(SG) - - CBOW 在已知 `context(w)` 的情况下,预测 `w` - - SG 在已知 `w` 的情况下预测 `context(w)` + - CBOW 在已知 `context(w)` 的情况下,预测 `w` + - SG 在已知 `w` 的情况下预测 `context(w)` + - 从训练集的构建方式可以更好的理解和区别 **CBOW** 和 **SG** 模型 - - 每个训练样本为一个二元组 `(x, y)`,其中 `x`为特征,`y`为标签 + - 每个训练样本为一个二元组 `(x, y)`,其中 `x`为特征,`y`为标签 - 假设上下文窗口的大小 `context_window =5`,即 -
+ 假设上下文窗口的大小 `context_window =5`,即 +
- 或者说 `skip_window = 2`,有 `context_window = skip_window*2 + 1` - - CBOW 的训练样本为: -
+ 或者说 `skip_window = 2`,有 `context_window = skip_window*2 + 1` + + - CBOW 的训练样本为: +
- - SG 的训练样本为: -
+ - SG 的训练样本为: +
- - 一般来说,`skip_window <= 10` + - 一般来说,`skip_window <= 10` + - 除了两套模型,Word2Vec 还提供了两套优化方案,分别基于 Hierarchical Softmax (层次SoftMax) 和 Negative Sampling (负采样) ## 基于层次 SoftMax 的 CBOW 模型 - 【**输入层**】将 `context(w)` 中的词映射为 `m` 维词向量,共 `2c` 个 - 【**投影层**】将输入层的 `2c` 个词向量累加求和,得到新的 `m` 维词向量 - 【**输出层**】输出层对应一棵**哈夫曼树**,以词表中词作为叶子节点,各词的出现频率作为权重——共 `N` 个叶子节点,`N-1` 个非叶子节点 -
+
- 对比 [N-gram 神经语言模型的网络结构](#n-gram-神经语言模型的网络结构) - - 【输入层】前者使用的是 `w` 的前 `n-1` 个词,后者使用 `w` 两边的词 - > 这是后者词向量的性能优于前者的主要原因 - - 【投影层】前者通过拼接,后者通过**累加求和** - - 【隐藏层】后者无隐藏层 - - 【输出层】前者为线性结构,后者为树形结构 + - 【输入层】前者使用的是 `w` 的前 `n-1` 个词,后者使用 `w` 两边的词 + > 这是后者词向量的性能优于前者的主要原因 + - 【投影层】前者通过拼接,后者通过**累加求和** + - 【隐藏层】后者无隐藏层 + - 【输出层】前者为线性结构,后者为树形结构 - 模型改进 - - 从对比中可以看出,CBOW 模型的主要改进都是为了**减少计算量**——取消隐藏层、使用**层Softmax**代替基本Softmax + - 从对比中可以看出,CBOW 模型的主要改进都是为了**减少计算量**——取消隐藏层、使用**层Softmax**代替基本Softmax ### 层次 SoftMax 的正向传播 - 层 Softmax 实际上是把一个超大的多分类问题转化成一系列二分类问题 - 示例:求 `P("足球"|context("足球"))` -
+
- - 从根节点到“足球”所在的叶子节点,需要经过 4 个分支,每次分支相当于一次**二分类**(逻辑斯蒂回归,二元Softmax) -
+ - 从根节点到“足球”所在的叶子节点,需要经过 4 个分支,每次分支相当于一次**二分类**(逻辑斯蒂回归,二元Softmax) +
- > 这里遵从原文,将 0 作为正类,1 作为负类 + > 这里遵从原文,将 0 作为正类,1 作为负类 - - 而 `P("足球"|context("足球"))` 就是每次分类正确的概率之积,即 -
+ - 而 `P("足球"|context("足球"))` 就是每次分类正确的概率之积,即 +
- > 这里每个非叶子都对应一个参数 `θ_i` + > 这里每个非叶子都对应一个参数 `θ_i` #### 为什么层次 SoftMax 能加速 - Softmax 大部分的计算量在于分母部分,它需要求出所有分量的和 @@ -129,7 +132,7 @@ Index ## 基于层次 Softmax 的 Skip-gram 模型 - 这里保留了【投影层】,但实际上只是一个恒等变换 -
+
- 从模型的角度看:CBOW 与 SG 模型的区别仅在于 `x_w` 的构造方式不同,前者是 `context(w)` 的词向量累加;后者就是 `w` 的词向量 - 虽然 SG 模型用中心词做特征,上下文词做类标,但实际上两者的地位是等价的 @@ -139,7 +142,7 @@ Index ## 基于负采样的 CBOW 和 Skip-gram - 层次 Softmax 还不够简单,于是提出了基于负采样的方法进一步提升性能 - 负采样(Negative Sampling)是 NCE(Noise Contrastive Estimation) 的简化版本 - > [噪音对比估计(NCE)](https://blog.csdn.net/littlely_ll/article/details/79252064) - CSDN博客 + > [噪音对比估计(NCE)](https://blog.csdn.net/littlely_ll/article/details/79252064) - CSDN博客 - CBOW 的训练样本是一个 `(context(w), w)` 二元对;对于给定的 `context(w)`,`w` 就是它的正样本,而其他所有词都是负样本。 - 如果不使用**负采样**,即 N-gram 神经语言模型中的做法,就是对整个词表 Softmax 和交叉熵 - 负采样相当于选取所有负例中的一部分作为负样本,从而减少计算量 @@ -148,36 +151,37 @@ Index ## 负采样算法 - 负采样算法,即对给定的 `w` ,生成相应负样本的方法 - 最简单的方法是随机采样,但这会产生一点问题,词表中的词出现频率并不相同 - - 如果不是从词表中采样,而是从语料中采样;显然,那些高频词被选为负样本的概率要大于低频词 - - 在词表中采样时也应该遵循这个 + - 如果不是从词表中采样,而是从语料中采样;显然,那些高频词被选为负样本的概率要大于低频词 + - 在词表中采样时也应该遵循这个 - 因此,负采样算法实际上就是一个**带权采样**过程 -
+
### Word2Vec 中的做法 - 记 -
+
- 以这 `N+1` 个点对区间 `[0,1]` 做非等距切分 - 引入的一个在区间 `[0,1]` 上的 `M` 等距切分,其中 `M >> N` -
- - > 源码中取 `M = 10^8` +
+ + > 源码中取 `M = 10^8` - 然后对两个切分做投影,得到映射关系 -
+
+ +- 采样时,每次生成一个 `[1, M-1]` 之间的整数 `i`,则 `Table(i)` 就对应一个样本;当采样到正例时,跳过(**拒绝采样**)。 -- 采样时,每次生成一个 `[1, M-1]` 之间的整数 `i`,则 `Table(i)` 就对应一个样本;
- 当采样到正例时,跳过 - 特别的,Word2Vec 在计算 `len(w)` 时做了一些改动——为 `count(·)` 加了一个**指数** -
+
## 一些源码细节 ### `σ(x)` 的近似计算 - 类似带权采样的策略,用**查表**来代替计算 -
+
+ - 具体计算公式如下 -
+
- > 因为 `σ(x)` 函数的饱和性,当 `x < -6 || x > 6` 时,函数值基本不变了 + > 因为 `σ(x)` 函数的饱和性,当 `x < -6 || x > 6` 时,函数值基本不变了 ### 低频词的处理 - 对于低频词,会设置阈值(默认 5),对于出现频次低于该阈值的词会直接舍弃,同时训练集中也会被删除 @@ -189,16 +193,16 @@ Index **Sub-sampling 技巧** - 源码中使用 Sub-sampling 技巧来解决高频词的问题,能带来 2~10 倍的训练速度提升,同时提高低频词的词向量精度 - 给定一个词频阈值 `t`,将 `w` 以 `p(w)` 的概率舍弃,`p(w)` 的计算如下 -
+
**Word2Vec 中的Sub-sampling** - 显然,Sub-Sampling 只会针对 出现频次大于 `t` 的词 - 特别的,Word2Vec 使用如下公式计算 `p(w)`,效果是类似的 -
+
### 自适应学习率 - 预先设置一个初始的学习率 `η_0`(默认 0.025),每处理完 `M`(默认 10000)个词,就根据以下公式调整学习率 -
+
- 随着训练的进行,学习率会主键减小,并趋向于 0 - 为了方式学习率过小,Word2Vec 设置了一个阈值 `η_min`(默认 `0.0001 * η_0`);当学习率小于 `η_min`,则固定为 `η_min`。 @@ -212,21 +216,21 @@ Index ## 共现矩阵 - 共现矩阵的实现方式 - - 基于文档 - LSA 模型(SVD分解) - - 基于窗口 - 类似 skip-gram 模型中的方法 -
+ - 基于文档 - LSA 模型(SVD分解) + - 基于窗口 - 类似 skip-gram 模型中的方法 +
- > `skip_window = 1` 的共现矩阵 + > `skip_window = 1` 的共现矩阵 ### 构架共现矩阵的细节 - **功能词的处理** - - 功能词:如 "the", "he", "has", ... - - **法1**)直接忽略 - - 在一些分类问题上可以这么做;如果目标是词向量,则不建议使用这种方法 - - **法2**)设置阈值 `min(x, t)` - - 其中 `x` 为功能词语其他词的共现次数,`t` 为设置的阈值 + - 功能词:如 "the", "he", "has", ... + - **法1**)直接忽略 + - 在一些分类问题上可以这么做;如果目标是词向量,则不建议使用这种方法 + - **法2**)设置阈值 `min(x, t)` + - 其中 `x` 为功能词语其他词的共现次数,`t` 为设置的阈值 - 可以尝试使用一些方法代替单纯的计数,如**皮尔逊相关系数**,负数记为 0 - > 但是似乎没有人这么做 + > 但是似乎没有人这么做 ## GloVe 的基本思想 - GloVe 模型的是基于**共现矩阵**构建的 @@ -238,9 +242,10 @@ Index - **water** related to both - **fashion** relate not to both > 说明 TODO + - GloVe 的基本思想: - - 假设词向量已知,如果这些词向量通过**某个函数**(目标函数)可以**拟合**共现矩阵中的统计信息,那么可以认为这些词向量也拥有了共现矩阵中蕴含的语义 - - 模型的训练过程就是拟合词向量的过程 + - 假设词向量已知,如果这些词向量通过**某个函数**(目标函数)可以**拟合**共现矩阵中的统计信息,那么可以认为这些词向量也拥有了共现矩阵中蕴含的语义 + - 模型的训练过程就是拟合词向量的过程 ## GloVe 的目标函数
@@ -249,186 +254,191 @@ Index - `w_i` 和 `w_j` 为词向量 - `x_ij` 为 `w_i` 和 `w_j` 的共现次数 - `f(x)` 是一个权重函数,为了限制高频词和防止 `x_ij = 0` -
+
- - 当 `x_ij = 0` 时,有 -
+ - 当 `x_ij = 0` 时,有 +
### GloVe 目标函数的推导过程 > 以前整理在 OneNote 上的,有时间在整理 - 目标函数 -
-
-
-
-
+
+
+
+
+
- `w_i` 的权重函数 -
+
## GloVe 与 Word2Vec 的区别 - Word2Vec 本质上是一个神经网络;
Glove 也利用了**反向传播**来更新词向量,但是结构要更简单,所以 GloVe 的速度更快 - Glove 认为 Word2Vec 对高频词的处理还不够,导致速度慢;GloVe 认为共现矩阵可以解决这个问题 - > 实际 Word2Vec 已结有了一些对高频词的措施 > [高频词的处理](#高频词的处理) -- 从效果上看,虽然 GloVe 的训练速度更快,但是**词向量的性能**在通用性上要弱一些:
- 在一些任务上表现优于 Word2Vec,但是在更多的任务上要比 Word2Vec 差 + > 实际 Word2Vec 已结有了一些对高频词的措施 > [高频词的处理](#高频词的处理) +- 从效果上看,虽然 GloVe 的训练速度更快,但是**词向量的性能**在通用性上要弱一些:
在一些任务上表现优于 Word2Vec,但是在更多的任务上要比 Word2Vec 差 # FastText -- FastText 是从 Word2Vec 的 CBOW 模型演化而来的;
- 从网络的角度来看,两者的模型基本一致;**区别仅在于两者的输入和目标函数不同**;
- -
+- FastText 是从 Word2Vec 的 CBOW 模型演化而来的; + + 从网络的角度来看,两者的模型基本一致;**区别仅在于两者的输入和目标函数不同**; - > [基于层次 SoftMax 的 CBOW 模型](#基于层次-softmax-的-cbow-模型) +
+ + > [基于层次 SoftMax 的 CBOW 模型](#基于层次-softmax-的-cbow-模型) - FastText 与 CBOW 的相同点: - - 包含三层:输入层、隐含层、输出层(Hierarchical Softmax) - - 输入都是多个单词的词向量 - - 隐藏层(投影层)都是对多个词向量的叠加平均 - - 输出都是一个特定的 target - - 从网络的角度看,两者基本一致 + - 包含三层:输入层、隐含层、输出层(Hierarchical Softmax) + - 输入都是多个单词的词向量 + - 隐藏层(投影层)都是对多个词向量的叠加平均 + - 输出都是一个特定的 target + - 从网络的角度看,两者基本一致 + - 不同点: - - CBOW 的输入是中心词两侧`skip_window`内的上下文词;FastText 除了上下文词外,还包括这些词的字符级 **N-gram 特征** - - + - CBOW 的输入是中心词两侧`skip_window`内的上下文词;FastText 除了上下文词外,还包括这些词的字符级 **N-gram 特征** + - **注意**,字符级 N-gram 只限制在单个词内,以英文为例 - ```Cpp - // 源码中计算 n-grams 的声明,只计算单个词的字符级 n-gram - compute_ngrams(word, unsigned int min_n, unsigned int max_n); - ``` - ```Python - # > https://github.com/vrasneur/pyfasttext#get-the-subwords - >>> model.args.get('minn'), model.args.get('maxn') - (2, 4) - # 调用源码的 Python 接口,源码上也会添加 '<' 和 '>' - >>> model.get_all_subwords('hello') # word + subwords from 2 to 4 characters - ['hello', '', 'lo', 'lo>', 'o>'] - >>> # model.get_all_subwords('hello world') # warning - ``` -- **值得一提的是**,因为 FastText 使用了字符级的 N-gram 向量作为额外的特征,使其能够对**未登录词**也能输出相应的词向量;
+ ```Cpp + // 源码中计算 n-grams 的声明,只计算单个词的字符级 n-gram + compute_ngrams(word, unsigned int min_n, unsigned int max_n); + ``` + ```Python + # > https://github.com/vrasneur/pyfasttext#get-the-subwords + >>> model.args.get('minn'), model.args.get('maxn') + (2, 4) + # 调用源码的 Python 接口,源码上也会添加 '<' 和 '>' + >>> model.get_all_subwords('hello') # word + subwords from 2 to 4 characters + ['hello', '', 'lo', 'lo>', 'o>'] + >>> # model.get_all_subwords('hello world') # warning + ``` +- **值得一提的是**,因为 FastText 使用了字符级的 N-gram 向量作为额外的特征,使其能够对**未登录词**也能输出相应的词向量; + **具体来说**,**未登录词**的词向量等于其 N-gram 向量的叠加 + ## `gensim.models.FastText` 使用示例 -> code/[FastText](../code/工具库/gensim/FastText.py) +> ../codes/[FastText](../_codes/工具库/gensim/FastText.py) + - 构建 FastText 以及获取词向量 - ```Python - # gensim 示例 - import gensim - import numpy as np - from gensim.test.utils import common_texts - from gensim.models.keyedvectors import FastTextKeyedVectors - from gensim.models._utils_any2vec import compute_ngrams, ft_hash - from gensim.models import FastText - - # 构建 FastText 模型 - sentences = [["Hello", "World", "!"], ["I", "am", "huay", "."]] - min_ngrams, max_ngrams = 2, 4 # ngrams 范围 - model = FastText(sentences, size=5, min_count=1, min_n=min_ngrams, max_n=max_ngrams) - - # 可以通过相同的方式获取每个单词以及任一个 n-gram 的向量 - print(model.wv['hello']) - print(model.wv['', '', ''] - ['', '', ''] - ['', ''] - ['', ''] - ['', '', ''] - ['', '', ''] - ['<.', '.>', '<.>'] - """ - assert sum_ngrams == len(model.wv.vectors_ngrams) - print(sum_ngrams) # 57 - print() - ``` + ```Python + sum_ngrams = 0 + for s in sentences: + for w in s: + w = w.lower() + # from gensim.models._utils_any2vec import compute_ngrams + ret = compute_ngrams(w, min_ngrams, max_ngrams) + print(ret) + sum_ngrams += len(ret) + """ + ['', '', ''] + ['', '', ''] + ['', ''] + ['', ''] + ['', '', ''] + ['', '', ''] + ['<.', '.>', '<.>'] + """ + assert sum_ngrams == len(model.wv.vectors_ngrams) + print(sum_ngrams) # 57 + print() + ``` ### 计算一个未登录词的词向量 - 未登录词实际上是已知 n-grams 向量的叠加平均 - ```Python - # 因为 "a", "aa", "aaa" 中都只含有 " `gensim.models.keyedvectors.FastTextKeyedVectors.word_vec(token)` 的内部实现 - ```Python - word_unk = "aam" - ngrams = compute_ngrams(word_unk, min_ngrams, max_ngrams) # min_ngrams, max_ngrams = 2, 4 - word_vec = np.zeros(model.vector_size, dtype=np.float32) - ngrams_found = 0 - for ngram in ngrams: - ngram_hash = ft_hash(ngram) % model.bucket - if ngram_hash in model.wv.hash2index: - word_vec += model.wv.vectors_ngrams[model.wv.hash2index[ngram_hash]] - ngrams_found += 1 - - if word_vec.any(): # - word_vec = word_vec / max(1, ngrams_found) - else: # 如果一个 ngram 都没找到,gensim 会报错;个人认为把 0 向量传出来也可以 - raise KeyError('all ngrams for word %s absent from model' % word_unk) - - print(word_vec) - print(model.wv["aam"]) - """ - [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] - [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] - """ - - # 如果一个 ngram 都没找到,gensim 会报错 - # 其实可以返回一个 0 向量的,它内部实际上是从一个 0 向量开始累加的; - # 但返回时做了一个判断——如果依然是 0 向量,则报错 - # print(model.wv['z']) - r""" - Traceback (most recent call last): - File "D:/OneDrive/workspace/github/DL-Notes-for-Interview/code/工具库/gensim/FastText.py", line 53, in - print(model.wv['z']) - File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 336, in __getitem__ - return self.get_vector(entities) - File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 454, in get_vector - return self.word_vec(word) - File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 1989, in word_vec - raise KeyError('all ngrams for word %s absent from model' % word) - KeyError: 'all ngrams for word z absent from model' - """ - ``` + > `gensim.models.keyedvectors.FastTextKeyedVectors.word_vec(token)` 的内部实现 + ```Python + word_unk = "aam" + ngrams = compute_ngrams(word_unk, min_ngrams, max_ngrams) # min_ngrams, max_ngrams = 2, 4 + word_vec = np.zeros(model.vector_size, dtype=np.float32) + ngrams_found = 0 + for ngram in ngrams: + ngram_hash = ft_hash(ngram) % model.bucket + if ngram_hash in model.wv.hash2index: + word_vec += model.wv.vectors_ngrams[model.wv.hash2index[ngram_hash]] + ngrams_found += 1 + + if word_vec.any(): # + word_vec = word_vec / max(1, ngrams_found) + else: # 如果一个 ngram 都没找到,gensim 会报错;个人认为把 0 向量传出来也可以 + raise KeyError('all ngrams for word %s absent from model' % word_unk) + + print(word_vec) + print(model.wv["aam"]) + """ + [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] + [ 0.02210762 -0.10488641 0.05512805 0.09150169 0.00725085] + """ + + # 如果一个 ngram 都没找到,gensim 会报错 + # 其实可以返回一个 0 向量的,它内部实际上是从一个 0 向量开始累加的; + # 但返回时做了一个判断——如果依然是 0 向量,则报错 + # print(model.wv['z']) + """ + Traceback (most recent call last): + File "D:/OneDrive/workspace/github/DL-Notes-for-Interview/code/工具库 /gensim/FastText.py", line 53, in + print(model.wv['z']) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 336, in __getitem__ + return self.get_vector(entities) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 454, in get_vector + return self.word_vec(word) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models \keyedvectors.py", line 1989, in word_vec + raise KeyError('all ngrams for word %s absent from model' % word) + KeyError: 'all ngrams for word z absent from model' + """ + ``` # WordRank TODO @@ -440,11 +450,10 @@ Glove 也利用了**反向传播**来更新词向量,但是结构要更简单 - # 其他实践 ## 一般 embedding 维度的选择 > [Feature Columns](https://www.tensorflow.org/versions/master/guide/feature_columns#indicator_and_embedding_columns)  |  TensorFlow - 经验公式 `embedding_size = n_categories ** 0.25` - 在大型语料上训练的词向量维度通常会设置的更大一些,比如 `100~300` - > 如果根据经验公式,是不需要这么大的,比如 200W 词表的词向量维度只需要 `200W ** 0.25 ≈ 37` + > 如果根据经验公式,是不需要这么大的,比如 200W 词表的词向量维度只需要 `200W ** 0.25 ≈ 37` diff --git "a/_codes/\345\267\245\345\205\267\345\272\223/gensim/FastText.py" "b/_codes/\345\267\245\345\205\267\345\272\223/gensim/FastText.py" new file mode 100644 index 00000000..028e4f3e --- /dev/null +++ "b/_codes/\345\267\245\345\205\267\345\272\223/gensim/FastText.py" @@ -0,0 +1,109 @@ +""" +`gensim.models.FastText` 使用示例 +""" +# gensim 示例 +import gensim +import numpy as np +from gensim.test.utils import common_texts +from gensim.models.keyedvectors import FastTextKeyedVectors +from gensim.models._utils_any2vec import compute_ngrams, ft_hash +from gensim.models import FastText + +# 构建 FastText 模型 +sentences = [["Hello", "World", "!"], ["I", "am", "huay", "."]] +min_ngrams, max_ngrams = 2, 4 # ngrams 范围 +model = FastText(sentences, size=5, min_count=1, min_n=min_ngrams, max_n=max_ngrams) + +# 可以通过相同的方式获取每个单词以及任一个 n-gram 的向量 +print(model.wv['hello']) +print(model.wv['', '', ''] +['', '', ''] +['', ''] +['', ''] +['', '', ''] +['', '', ''] +['<.', '.>', '<.>'] +""" +assert sum_ngrams == len(model.wv.vectors_ngrams) +print(sum_ngrams) # 57 +print() + +# 因为 "a", "aa", "aaa" 中都只含有 " + print(model.wv['z']) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 336, in __getitem__ + return self.get_vector(entities) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 454, in get_vector + return self.word_vec(word) + File "D:\program\work\Python\Anaconda3\envs\tf\lib\site-packages\gensim\models\keyedvectors.py", line 1989, in word_vec + raise KeyError('all ngrams for word %s absent from model' % word) +KeyError: 'all ngrams for word z absent from model' +""" +