Chatgpt 从零开始-文本的表示方法

写在前面

   你可能听说过计算机里面图片的表示方法,如 RGB、YUV 等相关概念,那么就知道一张图片一般有 3 个通道来进行表示,每个通道上都是一个矩阵,矩阵中的一个数字就是一个像素、一个离散的数据。例如,在某个像素上的三通道数值是 (255, 255, 255),那么这个像素就是白色,这很容易理解,一些图像相关的深度学习任务可能会对图片进行处理,如进行灰度图片转化,得到的就是一个单一通道的矩阵数据,后续再进行神经网络的特征提取。
   然而在自然语言处理任务中,文字是以一种什么方式在计算机上来进行表示?本文将对这些表示方法进行阐述,以此帮助部分需要从 0 开始接触 NLP 的同学,一直到目前较为火热的 Chatgpt 的学习为止。
   文章肯定通俗易懂,相对的废话也比较多,但比较适合零基础的学习者。如果发现错误,请互相讨论和指正!如果想要使用chatgpt的同学也可以参考这篇

相关概念

语料库:本质上就是一堆文字资源,可以是一篇文章,甚至一个字(单词)、一句话等,也可以是一个地方或
       国家乃至全世界所有的书籍等里面的字。但一般情况下主要是针对自己任务中的文字资源,比
       如我们要进行一个新闻内容分类的任务,你收集了10 种类别的新闻,一共1000条新闻,那这就是一
       个语料库。而对于 Chatgpt 来说涵盖了各行各业的文字资料,它的语料库十分庞大,夸张点说覆
       盖了所有语言的资料(由于英文或外文资料更为丰富,且 openai 不会受到一些墙之类的因素影响,
       因此国内做语言大模型的干不过 chatgpt 是理所当然的,但这只是其中一个的原因)

1. 分词

   一个句子的基础元素是一个个字,因此在计算机中想要表达一句话,一个最先要做的工作就是将句子分成一个个字,在英文当中每个句子的单词是已经天然分好的,但对于中文来说,两个字分开后所表达的意思会很不一样,如 “我们是好朋友” 中 “我们” 是一个主体,拆开后“们” 字单独存在就会变得奇怪,因此在中文的语言处理任务中需要进行分词的操作。分词的方法有很多种,这里会介绍其中常用的方法,再介绍相关的分词工具——jieba。
   要分词首先需要一个巨大的词典库(词典库内容需保证尽量正确),然后再对句子或语料库内容进行字符串最大匹配算法处理(正向、逆向、双向三种最大匹配算法)或其他优秀的算法处理,这里以正向最大匹配算法对下面句子分词为例:

string = "我今天早上的时候吃过饭了"
  1. 初始状态下我们假设一个词的最长长度为 6,从 string[0] 开始以长度 6 扫描句子,发现前 6 个字符 “我今天早上的” 在词典库种不存在,因此这个字符串不是词语,接下来缩短长度为 5,发现前 5 个字符也不是词语,如此反复,发现长度为 1 时,“我” 出现在了词典库里面,因此“我” 被分词
  2. 接下来从 string[1] 以长度为 6 扫描,一直到长度为 2 时发现 “今天” 是词语,完成 “今天” 的分词,如此反复,就得到了如下的分词结果:
string[] = ["我","今天", "早上", "的", "时候", "吃过", "饭", "了"] 或
string[] = ["我","今天", "早上的", "时候", "吃过饭", "了"]  或
string[] = ["我","今天", "早上",  "时候", "吃过", "饭"] 

   具体会分成哪种还是得依据准备的词典决定,同时我们注意到第三种情况少去 “了”、“的” 这种词,原因是此处的两个字没太大实际意义,只是一些语气词等,去除后对句子的意思影响不大,交给计算机处理还能更简洁。
   一般情况下我们当然不会特意地去准备这么一个巨大的词典,目前有相当多的工具可以完成分词的工作,如 jieba 等。(PS: jieba 即结巴,说不出完整的话,不就是分词么?妙啊!)在对整个语料库完成分词后,我们就得到了在对应语言任务里可能出现的所有词语,接下来就可以进行下一步工作了,即:将文字或词语转换为可供神经网络特征提取的矩阵,这个矩阵就和一张图片一样。
   如果不懂什么是神经网络也没关系,我们可以把这个理解为一个盒子、一个机器,我们把一个句子矩阵从一端输入到这个盒子或机器里面,它就会在盒子内部分析这个句子的语义信息,用数学模型得到这个句子想表达的意思,然后从另一端输出结果,这个输出和自己的任务有关系,比如你的任务是把这个句子进行分类,它就可能输出这个句子类别是情感,如果任务是回答这个句子(就和 Chatgpt 一样),那输出就是一个回答的句子。总之,神经网络就是个黑盒子,它的输入是句子矩阵,输出依据任务决定。
    那什么是句子矩阵?我们前面对句子进行了分词,得到一个个单独的词语和字,计算机没法对些文字进行表示(不是 ascll 码、unicode 那一套),因此这里我们还需要将这些词进行向量化操作,即:将每次词用一个向量表示,具体见下文。


2. one-hot

   one-hot 是最为简单的将文字向量化方法,它的方式非常简单,比如对语料库分词后,我们得到 ( [“我”,“今天”, “早上”, “时候”, “吃过”, “饭”] ) 的分词结果,那对这个语料库分词结果的 one-hot 表示方法为:

dict ={
"我" :  [1, 0, 0, 0, 0, 0],
"今天": [0, 1, 0, 0, 0, 0],
"早上": [0, 0, 1, 0, 0, 0],
"时候": [0, 0, 0, 1, 0, 0],
"吃过": [0, 0, 0, 0, 1, 0],
"饭" :  [0, 0, 0, 0, 0, 1]
}

   是不是非常简单明了?直接用向量里面哪个位置为 1 来表明这是哪个词,这句话的句子矩阵我们就可以直接用这个单位矩阵表示。同时我们也可以把这些向量相加,比如 “我吃过饭” 这句新的话,那它的句子矩阵就是 ([1, 0, 0, 0, 1, 1])。其他文章里有更加详细或深入的 one-hot 描述,感兴趣的同学可以进一步搜索。还有一个问题就是,没在词典中出现的词应该如何表示?这里提供一些思路就是,对于这些未出现过的词,有些表示方法里会直接报错(word2vec),或者直接给未出现的词定义一个默认的词向量表示方法,诸如此类。
   这种文本的表示方法的缺点也显而易见,一个词库的词语有 10000 个的时候每个词向量长度就是10000,这太浪费空间了。而且对于一些语义类似的词语,如 “早饭”、“吃饭”,这种表示方法没法表现出相近的关系。


3. tf-idf 向量

   出现奇怪的英文字符了,不用担心,这个理解起来十分简单,本质上就是依据词频权重来确定一个词向量。下面进行具体解释:

TF(Term Frequency) = 某个词在语料库中某文档出现的次数 / 语料库某文档所有词的数量  
IDF(Inverse Document Frequency) = log(语料库中的文档数 / (包含该词的文档数 + 1))
最终的值为:
tf-idf = TF × IDF

   最终每个词在每个文档出现的值相加,得到这个词在语料库的权重值 tf-idf,例如 ( [“我”,“今天”, “早上”, “时候”, “吃过”, “饭”] ) 计算每个值后得到的 tf-idf 值为:

[0.453, 0.112, 0.001, 0.233, 0.912, 0.231]
分开来就是:
"我" :  [0.453, 0, 0, 0, 0, 0],
"今天": [0, 0.112, 0, 0, 0, 0],
"早上": [0, 0, 0.001, 0, 0, 0],
"时候": [0, 0, 0, 0.233, 0, 0],
"吃过": [0, 0, 0, 0, 0.912, 0],
"饭" :  [0, 0, 0, 0, 0, 0.231]

   这种表示方法下每个词具有不同的权重,相比 one-hot 也更为合理。参考链接

4. word2vec

   从这里开始是一些基于神经网络的方法。先直接上 word2vec 的词向量表示方法,再进行原理的解释,同样以 [“我”,“今天”, “早上”, “时候”, “吃过”, “饭”] 为例:

"我" :  [0.1, 0.2, 0.3],
"今天": [0.5, 0.1, 0.1],
"早上": [0.6, 0.05, 0.01],
"时候": [0.99, 0, 0.32],
"吃过": [0.43, 0.912, 0],
"饭" :  [0.21, 0.87, 0.231]

   我们发现词向量的数量没有变,同样是和词的数量保持一致,但是每个向量的长度变短了,相比于原本的离散表示方法,所需的空间更小了。实际上在 word2vec 里面,词向量的维度(长度)我们是可以自己决定的,方法就是修改第一层神经网络的参数个数。这里向量中的数值实际上就是 word2vec 网络中的神经元参数。一般来说在长度在 150 或 300 对 word2vec 网络进行训练就能满足语料库的覆盖,或者说其复杂度满足语料库的信息量,为了举例我们这里的词向量维度是 3。
   假设我们现在已经训练完成了,经过 word2vec 训练后,我们发现 “早上”、“今天” 两个向量各个维度的值较为接近(向量内积较大),因为语义中他们的关系较大,而 “早上” 和 “我们” 两个词的积较小,相关度不是那么大,这里不需要问为什么,词库中的向量经过训练收敛后一般来说大部分的词向量都具有参考性。


5. word2vec 网络

   想要完全了解 word2vec,需要一定的神经网络基础,本质上神经网络模拟的是生物中人神经元的运作方式,如果你还不了解什么是神经网络,可以先看我写的一个简单例子。word2vec 有两种网络模型,左边为 c-bow 模型,右边为 skip-gram 模型:
在这里插入图片描述

   这两个模型的区别就是,对于语料库中的一句话,将这句话分词,并用 one-hot 方法表示每个词,以 n 个词为一组,再在将其中的某个词删去,作为对应的输入,然后用网络预测这个词是什么,skip-gram 则是保留一个词,来预测其他所有词的概率,以此遍历整个语料库中的文字,不断重复上述过程。无论是 c-bow 还是 skip-gram,它们都只有一层神经元,以 c-bow 模型为例,在这层神经元的左边,每个神经元和每个输入的词都有一个权重参数连接,例如,假设有 1000 个词,150 个神经元,这里的1000个词和每个神经元都有一个权重参数,因此我们就能得到一个 1000×150 的矩阵,输入的值经过神经元层后,变成了 150 个数值,再输出到神经元层的右边,右边是一个150 ×1000 的矩阵,但是由于输入的时候删掉了一个词,那接下来这个右边的矩阵参数会根据删去词的 one-hot 作为真实值进行自监督训练,作为输入的这句话经过多次的训练后能够逐渐正确地预测被删去的词是哪一个,这样就完成了神经网络的收敛/训练,在训练后,我们可以将神经元左侧的矩阵作为词向量,得到一种更为高级、准确的文本表示方法。

  • 26
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值