[NLP复习笔记] 基于负采样的 Skip-gram 及 SGD 训练公式推导
1. one-hot 向量
我们先了解一下 \(\text{one-hot}\) 向量。\(\text{one-hot}\) 编码是表示分类变量的常见方法,尤其在数据预处理和机器学习的特征工程中。一个 \(\text{one-hot}\) 向量是一个其中只有一个元素是 1,其余为 0 的向量。
假设存在一个单词集合:\(\{\text{marisa, reimu, renko, hearn}\}\),可以将这些单词进行索引映射:
\text{marisa} \rightarrow 0
\\
\text{reimu} \rightarrow 1
\\
\text{renko} \rightarrow 2
\\
\text{hearn} \rightarrow 3
\end{split}
\]
那么,这些单词经过 \(\text{one-hot}\) 编码的向量如下:
& \text{marisa}: [1, 0, 0, 0]
\\
& \text{reimu}: [0, 1, 0, 0]
\\
& \text{renko}: [0, 0, 1, 0]
\\
& \text{hearn}: [0, 0, 0, 1]
\end{split}
\]
显然,每个位置被看作一个特征,这个特征只能是 1(存在)或者 0(不存在)。
但是,对于包含大量唯一词汇的大型语料库而言, \(\text{one-hot}\) 编码会产生 极大的稀疏矩阵,每一个单词对应的词向量都是 \(|V|\) 维的,使得 维度很高,导致计算效率低下。
而且 \(\text{one-hot}\) 编码的词向量之间都是等距的,每个词语的向量与其他词语的向量都是正交的关系,这意味着它们 不携带任何词语间的相似性信息。
\(\text{one-hot}\) 编码现在依然有比较广泛的应用,但在一些自然语言处理问题中,为了避免上述的限制,会采用更加高级的技术,就比如 \(\text{Word2Vec}\)。
2. Word2Vec
2.1 Word2Vec 介绍
\(\text{Word2Vec}\) 模型通过训练神经网络,为每个单词构建一个密集且连续的向量。这些向量被称为 词嵌入(word embeddings),它们捕捉大量关于单词的语义和句法信息。每个单词在多维空间中被表示为一个向量,向量中的每个维度代表词义的不同方面,具体每个维度代表什么并不是人为定义的,而是通过 模型学习得到 的。
例如,经过训练后,单词 \(\text{marisa}\) 最终对应的词向量是 一个 \(d\) 维的向量,有可能是如下的形式:
\begin{bmatrix}
0.1
\\
1.5
\\
\vdots
\\
0.7
\end{bmatrix}
\]
\(vec\) 就是 目标单词的词向量。这里的维度 \(d\) 是 人为设定的一个超参数,表示我们需要将单词映射到一个 \(d\) 维的向量空间,决定了 词向量的特征数量,也就是我们想要 得到的词向量的大小。
通过 \(\text{Word2Vec}\) 得到的词向量 拥有相似上下文的词在空间中的位置,能够捕捉单词之间的语义关系。
从维度上,提取的 \(d\) 个维度特征,可以一定程度上避免维度过高的情况;从语义上,携带上下文信息,可以表示出近义词的相似性。
2.2 Skip-gram 与 CBOW
\(\text{Word2Vec}\) 模型包括输入层、隐藏层和输出层。模型框架根据输入输出的不同,主要包括 \(\text{Skip-gram}\) 和 \(\text{CBOW}\) 两种模型。
\(\text{Skip-gram}\) 模型: 用一个词语作为输入,来预测其上下文。模型的目标是 最大化在给定目标单词的情况下上下文单词出现的概率,也就是 计算其他单词出现在目标单词周围的概率。
\(\text{CBOW}\) 模型: 用一个词语的上下文作为输入,来预测这个词语。模型的目标是最大化上下文单词出现时目标单词的条件概率。
本篇文章将会介绍基于 \(\text{Negative Sampling}\) 的 \(\text{Skip-gram}\) 模型。(\(\text{Negative Sampling}\) 也就是 负采样,是 \(\text{Word2Vec}\) 模型训练的加速策略之一)
3. 基于 Negative Sampling 的 Skip-gram
3.1 Skip-gram 模型
\(\text{Skip-gram}\) 模型输入层 \(x\) 只有一个单词,输出层 \(y\) 为多个单词,其基本结构如下:
下面的 \(d\) 对应图中的 \(N\)。
输入层 \(x\):一个 \(1 \times V\) 的 \(\text{one-hot}\) 向量,\(V\) 为词汇表大小。表示一个单词,也是我们的 目标词。
\(W\) 矩阵:输入层到隐藏层之间 \(V \times d\) 的参数矩阵,包含了模型使用的所有词向量,目的是为了将输入层的 \(\text{one-hot}\) 向量映射到嵌入向量空间,也就是 \(d\) 维空间。
隐藏层 \(h\):一个 \(1 \times d\) 的特征向量,其实也就是当前的 目标词对应的词向量 。
\(W^{'}\) 矩阵:隐藏层到输出层之间的 \(d \times V\) 的参数矩阵,用来将隐藏层的表示转换到输出空间。也表示了所有单词的词向量,将于 目标词词向量做内积。
输出层 \(o\):一个 \(1 \times V\) 的向量。经过 \(h \times W^{'}\) 后(做内积之后)产生一个相似度向量,向量中 每个元素 表示词汇表 每个单词 的 在目标词上下文出现 的 原始概率。最后要经过一个 激活层 得到 真实概率。对于 多分类 问题,常常采用 \(\text{softmax}\) 函数;对于 二分类 问题,则一般采用 \(\text{sigmoid}\) 函数。(注意,这里的输出层并非图中最终的输出,只是一个概率的分布)
PS: 在后面的问题中,将会采用 \(\text{sigmoid}\) 函数。
- 输出单词 \(y\):\(C\) 个单词的 \(\text{one-hot}\) 向量,其中 \(C\) 表示采用的 上下文窗口的大小。根据输出层 \(o\) 的概率分布,选取 前 \(C\) 大概率 的单词作为最终预测的 目标词 \(x\) 的上下文单词 \(y\)。
下图是一个上下文窗口典型示例:
3.2 Negative Sampling
传统的神经语言模型需要在每一步对全词汇表进行运算,而 \(\text{Negative Sampling}\)(负采样)只在更新权重时考虑一个小的负样本集合,也就是随机选择一个负单词集合(也就是若干非上下文的单词组成的一个子集)。这样,目标就转化为 最大化正样本的概率,同时最小化负样本的概率。
由此我们可以得到如下定义:
样本概率
\[P(+ | w, c) = \sigma (c \cdot w)
\]其中 \(w\) 表示 目标词对应的词向量,\(c\) 表示 目标词的上下文对应的词向量。
\(\sigma\) 表示 \(\text{sigmoid}\) 函数,\(c \cdot w\) 是两个词向量的内积。
正样本似然函数
\[\prod P(+ | w, c_{\text{pos}})
\]负样本似然函数
\[\prod P(- | w, c_{\text{neg}})
\]
我们需要最大化正样本的概率,同时最小化负样本的概率,所以,可以转化为最大化下式:
\]
为了计算方便,我们可以取对数,得到对数似然函数:
\]
为了后续方便训练,我们可以变成最小化如下形式 (在前面加一个负号):
\]
由 \(\text{sigmoid}\) 函数 \(f(x) = \frac{1}{1 + e^{-x}}\) 得:
L &= - \text{log}(\prod \sigma (c_{\text{pos}} \cdot w) \prod \sigma(- c_{\text{neg}} \cdot w))
\\\\
&= - \left [ \sum \text{log} \; \sigma(c_{\text{pos}} \cdot w) + \sum \text{log} \; \sigma(- c_{\text{neg}} \cdot w) \right ]
\end{split}
\]
一般情况下使用 \(\text{SGD}\) (随机梯度下降法)来进行学习,故只需要知道对一个正样本 \((w, c_{\text{pos}})\) 的目标函数。假设我们随机选取 \(k\) 个负样本单词作为负采样集合,则有如下形式:
\]
这就是我们最终要 最小化得目标函数 \(L\) 。
3.3 参数求导
我们最终需要得到最优的 \(c_\text{pos}\) 、\(c_{\text{neg}}\) 以及 \(w\) 参数,由 \(\text{SGD}\) 算法(应该没有人不懂这个算法吧),我们要分别对这些参数求导。
目标函数中有 \(\text{sigmoid}\) 函数,故在求导之前,我们先看一下 \(\text{sigmoid}\) 函数的求导,以便后续化简。
\(\text{sigmoid}\) 函数如下:
\]
我们先对其进行变形,得:
\sigma(x) &= \frac{1}{1 + e^{-x}}
\\\\
&= \frac{e^x}{e^x + 1}
\\\\
&= 1 - (e^x + 1)^{-1}
\end{split}
\]
由此可得 \(\text{sigmoid}\) 的导数如下:
\frac{\text{d} \sigma}{\text{d} x} &= (e^x + 1)^{-2} e^x
\\\\
&= [e^x(1 + e^{-x})]^{-2} e^x
\\\\
&= (1 + e^{-x})^{-2} e^{-2x} e^x
\\\\
&= (1 + e^{-x})^{-1} \cdot \frac{e^{-x}}{1 + e^{-x}}
\\\\
&= \sigma(x) \cdot (1 - \sigma(x))
\end{split}
\]
我们可以再看下 \(\sigma(-x)\) 的导数。显然 \(\text{sigmoid}\) 函数满足 \(\sigma(-x) = 1 - \sigma(x)\),所以\(\sigma(-x)\) 的导数就很简单了,就是 \(-\sigma(x) \cdot (1 - \sigma(x))\)
后面再对各个参数求导就比较清晰易懂了,具体过程如下(对数看作取 \(\text{ln}\) 函数):
对 \(c_{\text{pos}}\) 求导
这里使用了 链式求导法则。
\[\begin{split}
\frac{\partial L}{\partial c_{\text{pos}}} &= \frac{\partial}{\partial c_{\text{pos}}}(- \left [ \text{log} \; \sigma(c_{\text{pos}} \cdot w) + \sum_{i=1}^k \text{log} \; \sigma(- c_{\text{neg}_i} \cdot w) \right ])
\\\\
&= - \frac{\partial L}{\partial \sigma(c_{\text{pos}} \cdot w)} \frac{\partial \sigma(c_{\text{pos}} \cdot w)}{\partial c_{\text{pos}}}
\end{split}
\]其中前半部分为:
\[\frac{\partial L}{\partial \sigma(c_{\text{pos}} \cdot w)} = \frac{1}{\sigma(c_{\text{pos}} \cdot w)}
\]后半部分为:
\[\frac{\partial \sigma(c_{\text{pos}} \cdot w)}{\partial c_{\text{pos}}} = \sigma(c_{\text{pos}} \cdot w) \cdot (1 - \sigma(c_{\text{pos}} \cdot w))\;w
\]最后结合起来得到 \(\frac{\partial L}{\partial c_{\text{pos}}}\)(记得最全面有一个负号) :
\[\begin{split}
\frac{\partial L}{\partial c_{\text{pos}}} &= - \frac{1}{\sigma(c_{\text{pos}} \cdot w)} \; \sigma(c_{\text{pos}} \cdot w) \; (1 - \sigma(c_{\text{pos}} \cdot w)) \; w
\\\\
&= \left [ \sigma(c_{\text{pos}} \cdot w) - 1 \right] w
\end{split}
\]对 \(c_{\text{neg}}\) 求导
使用 链式求导法则
\[\begin{split}
\frac{\partial L}{\partial c_{\text{neg}}} &= \frac{\partial}{\partial c_{\text{neg}}}(- \left [ \text{log} \; \sigma(c_{\text{pos}} \cdot w) + \sum_{i=1}^k \text{log} \; \sigma(- c_{\text{neg}_i} \cdot w) \right ])
\\\\
&= - \sum_{i=1}^k \frac{\partial L}{\partial \sigma(- c_{\text{neg}_i} \cdot w)} \frac{\partial \sigma(- c_{\text{neg}_i} \cdot w)}{\partial c_{\text{neg}_i}}
\end{split}
\]前半部分为:
\[\frac{\partial L}{\partial \sigma(- c_{\text{neg}_i} \cdot w)} = \frac{1}{\sigma(- c_{\text{neg}_i} \cdot w)}
\]后半部分为:
\[\begin{split}
\frac{\partial \sigma(- c_{\text{neg}_i} \cdot w)}{\partial c_{\text{neg}_i}} &= -\sigma(c_{\text{neg}_i} \cdot w) \; (1 - \sigma(c_{\text{neg}_i} \cdot w)) \; w
\end{split}
\]由于 \(\sigma(-x) = 1 - \sigma(x)\),我们可以把 \((1 - \sigma(c_{\text{neg}_i} \cdot w))\) 换成 \(\sigma(- c_{\text{neg}_i} \cdot w)\) 便于后续化简:
\[\frac{\partial \sigma(- c_{\text{neg}_i} \cdot w)}{\partial c_{\text{neg}_i}} = - \sigma(c_{\text{neg}_i} \cdot w) \; \sigma(- c_{\text{neg}_i} \cdot w) \; w
\]将两个部分结合起来,得到 \(\frac{\partial L}{\partial c_{\text{neg}}}\)(记得最全面有一个负号):
\[\begin{split}
\frac{\partial L}{\partial c_{\text{neg}}} &= - \sum_{i=1}^k \frac{1}{\sigma(- c_{\text{neg}_i} \cdot w)} \; \left [ - \sigma(c_{\text{neg}_i} \cdot w) \; \sigma(- c_{\text{neg}_i} \cdot w) \; w \right ]
\\\\
&= \sum_{i=1}^k \frac{1}{\sigma(- c_{\text{neg}_i} \cdot w)} \; \left [ \sigma(c_{\text{neg}_i} \cdot w) \; \sigma(- c_{\text{neg}_i} \cdot w) \; w \right ]
\\\\
&= \sum_{i=1}^k \sigma(c_{\text{neg}_i} \cdot w) \; w
\\\\
&= [\sigma(c_{\text{neg}} \cdot w)] \; w
\end{split}
\]对 \(w\) 求导
对前面两个参数进行求导后,对 \(w\) 求导就方便多了。
\[\frac{\partial L}{\partial w} = - \left [ \frac{\partial}{\partial w}(\text{log} \; \sigma(c_{\text{pos}} \cdot w)) + \frac{\partial}{\partial w}(\sum_{i=1}^k \text{log} \; \sigma(- c_{\text{neg}_i} \cdot w)) \right ]
\]对于前半部分,由
\[\frac{\partial}{\partial w} \sigma(c_{\text{pos}} \cdot w) = \sigma(c_{\text{pos}} \cdot w) \; (1 - \sigma(c_{\text{pos}} \cdot w)) \; c_{\text{pos}}
\]可得
\[\begin{split}
\frac{\partial}{\partial w}(\text{log} \; \sigma(c_{\text{pos}} \cdot w)) &= \frac{1}{\sigma(c_{\text{pos}} \cdot w)} \sigma(c_{\text{pos}} \cdot w) \; (1 - \sigma(c_{\text{pos}} \cdot w)) \; c_{\text{pos}}
\\\\
&= [1 - \sigma(c_{\text{pos}} \cdot w)] \; c_{\text{pos}}
\end{split}
\]对于后半部分,由
\[\frac{\partial}{\partial w} \sigma(- c_{\text{neg}_i} \cdot w) = \sigma(- c_{\text{neg}_i} \cdot w) \; (1 - \sigma(- c_{\text{neg}_i} \cdot w) \; (-c_{\text{neg}_i})
\]得
\[\begin{split}
\frac{\partial}{\partial w}(\text{log} \; \sigma(-c_{\text{neg}_i} \cdot w)) &= \frac{1}{\sigma(-c_{\text{neg}_i}\cdot w)} \sigma(- c_{\text{neg}_i} \cdot w) \; (1 - \sigma(- c_{\text{neg}_i} \cdot w) \; (-c_{\text{neg}_i})
\\\\
&= - [1 - \sigma(c_{\text{neg}_i} \cdot w)] \; c_{\text{neg}_i}
\\\\
&= - [\sigma(c_{\text{neg}_i}\cdot w)] \; c_{\text{neg}_i}
\end{split}
\]最后结合起来,得到 \(\frac{\partial L}{\partial w}\)(记得最全面有一个负号):
\[\frac{\partial L}{\partial w} = [ \sigma(c_{\text{pos}} \cdot w) - 1] \; c_{\text{pos}} + \sum_{i=1}^k [\sigma(c_{\text{neg}_i}\cdot w)] \; c_{\text{neg}_i}
\]
以上就是对参数求导的全部推导过程。
3.4 SGD 更新公式
将上面的导数套用到 \(\text{SGD}\) 更新公式就可以了。最后简单写一下更新公式:
\]
\]
\]
经过不断迭代更新后,最后得到最优的 \(c_\text{pos}\) 、\(c_{\text{neg}}\) 以及 \(w\) 参数,也就是最终的 上下文词向量 \(c\) 和 目标词对应的词向量 \(w\) 。
最后,通常会将两个词向量进行相加,来表述单词。例如第 \(i\) 个单词就可以表示为 \(w_i + c_i\) 。
参考
[NLP复习笔记] 基于负采样的 Skip-gram 及 SGD 训练公式推导的更多相关文章
- [DeeplearningAI笔记]序列模型2.7负采样Negative sampling
5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.7 负采样 Negative sampling Mikolov T, Sutskever I, Chen K, et a ...
- 【NLP CS224N笔记】Lecture 3 GloVe: Global Vectors for Word Representation
I. 复习word2vec的核心思路 1. Skip-gram 模型示意图: 2.word vectors的随机梯度 假设语料库中有这样一行句子: I love deep learning and N ...
- (Stanford CS224d) Deep Learning and NLP课程笔记(二):word2vec
本节课将开始学习Deep NLP的基础--词向量模型. 背景 word vector是一种在计算机中表达word meaning的方式.在Webster词典中,关于meaning有三种定义: the ...
- word2vec (CBOW、分层softmax、负采样)
本文介绍 wordvec的概念 语言模型训练的两种模型CBOW+skip gram word2vec 优化的两种方法:层次softmax+负采样 gensim word2vec默认用的模型和方法 未经 ...
- (Stanford CS224d) Deep Learning and NLP课程笔记(三):GloVe与模型的评估
本节课继续讲授word2vec模型的算法细节,并介绍了一种新的基于共现矩阵的词向量模型--GloVe模型.最后,本节课重点介绍了word2vec模型评估的两种方式. Skip-gram模型 上节课,我 ...
- Java基础复习笔记系列 九 网络编程
Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...
- Java基础复习笔记系列 五 常用类
Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...
- Angular复习笔记6-依赖注入
Angular复习笔记6-依赖注入 依赖注入(DependencyInjection)是Angular实现重要功能的一种设计模式.一个大型应用的开发通常会涉及很多组件和服务,这些组件和服务之间有着错综 ...
- Angular复习笔记5-指令
Angular复习笔记5-指令 在Angular中,指令是一个重要的概念,它作用在特定的DOM元素上,可以扩展这个元素的功能,为元素增加新的行为.本质上,组件可以被理解为一种带有视图的指令.组件继承自 ...
- angular复习笔记4-模板
Angular复习笔记4-模板 简介 模板是一种自定义的标准化页面,通过模板和模板中的数据结合,可以生成各种各样的网页.在Angular中,模板的默认语言是HTML,几乎所有的HTML语法在模板中都是 ...
随机推荐
- Solution -「HNOI 2010」城市建设
Description Link. 修改边权的动态 MST. Solution 讲清楚点. 修改边权的 MST,考虑对时间分治.设我们当前操作的操作区间是 \([l,r]\),直接暴力找 MST 是不 ...
- Springboot实现注解判断权限
Springboot实现注解判断权限 今天记录一下使用springboot的注解来给方法加权限 避免了每个方法都需要大量的权限判断 超级好用√ @ 目录 Springboot实现注解判断权限 1.创建 ...
- Aveva Marine VBNET 编程系列-搭建开发框架
引用的Dll Aveva.ApplicationFramework.dll Aveva.ApplicationFramework.Presentation 菜单展示效果 创建Attribute,用于反 ...
- Sentinel系列之SlotChain、NodeSelectorSlot、ClusterBuilderSlot分析
本文基于Sentinel 1.8.6版本分析 1. SlotChain 我们从入口com.alibaba.csp.sentinel.SphU#entry(java.lang.String) 开始分析. ...
- Jellyfin Documentation
Skip to main content Introduction On this page Welcome to the Jellyfin Documentation Jellyfin is ...
- 可视化-vscode安装pandas
pandas 是基于NumPy 的一种工具,该工具是为解决数据分析任务而创建的.Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具.pandas提供了大量能使我们快速 ...
- 基于LangChain的LLM应用开发2——模型、提示和输出解析
本次会讲解LangChain的三个基本组件:模型.提示和解析器. 名词解析 模型(Models):是指作为基础的大语言模型.LangChain中通过ChatOpenAI或者AzureChatOpenA ...
- Python 面向对象编程:类、对象、初始化和方法详解
Python 是一种面向对象的编程语言.在 Python 中,几乎所有东西都是对象,都具有其属性和方法. 类似于对象构造函数或用于创建对象的"蓝图"的类. 创建一个类 要创建一个类 ...
- GameFramework摘录 - 1. ReferencePool
GameFramework是一个结构很优秀的Unity游戏框架,但意图似乎在构建可跨引擎的框架?对要求不高的小型个人(不专业)开发来说有些设计过度了,但其中的设计精华很值得学习. 首先来说一下其中的R ...
- 什么是yaml格式与json格式
什么是yaml格式与json格式 yaml格式:文件名格式以 .yml .yaml 为后缀,用 空格 缩进表示字段的层级关系,可读性高,易于人类管理 yaml格式 布尔值类型:只有在是true/fal ...