当前位置: 首页 > news >正文

4.3.语言模型

语言模型

​ 假设长度为 T T T的文本序列中的词元依次为 x 1 , x 2 , ⋯ , x T x_1,x_2,\cdots,x_T x1,x2,,xT。 于是, x T x_T xT 1 ≤ t ≤ T 1\le t\le T 1tT) 可以被认为是文本序列在时间步 t t t处的观测或标签。 在给定这样的文本序列时,语言模型(language model)的目标是估计序列的联合概率:
P ( x 1 , x 2 , ⋯ , x T ) P(x_1,x_2,\cdots,x_T) P(x1,x2,,xT)
​ 应用包括:

  1. 做预训练模型(BERT,GPT-3)
  2. 生成本文,给定前面几个词,不断的使用 x t ∼ p ( x t ∣ x 1 , ⋯ , x t − 1 ) x_t\sim p(x_t|x_1,\cdots,x_{t-1}) xtp(xtx1,,xt1)生成后续文本
  3. 判断多个序列中哪个更常见

1.使用计数来建模(n_gram)

​ 假设序列长度为2,我们预测:
p ( x , x ′ ) = p ( x ) p ( x ′ ∣ x ) = n ( x ) n n ( x , x ′ ) n ( x ) p(x,x')=p(x)p(x'|x)=\frac{n(x)}{n}\frac{n(x,x')}{n(x)} p(x,x)=p(x)p(xx)=nn(x)n(x)n(x,x)
​ 其中 n n n是总次数, n ( x ) , n ( x , x ′ ) n(x),n(x,x') n(x),n(x,x)是单个单词和连续单词对的出现次数

​ 序列长度为3的情况也很容易: p ( x , x ′ , x ′ ′ ) = p ( x ) p ( x ′ ∣ x ) p ( x ′ ′ ∣ x , x ′ ) = n ( x ) n n ( x , x ′ ) n ( x ) n ( x , x ′ ) n ( x , x ′ , x ′ ′ ) p(x,x',x'')=p(x)p(x'|x)p(x''|x,x')=\frac{n(x)}{n}\frac{n(x,x')}{n(x)}\frac{n(x,x')}{n(x,x',x'')} p(x,x,x′′)=p(x)p(xx)p(x′′x,x)=nn(x)n(x)n(x,x)n(x,x,x′′)n(x,x)

​ 显然我们得到了一种简单的建模方式:
p ( x t ∣ x 1 , ⋯ , x t ) = n ( x 1 , ⋯ , x t ) n p(x_t|x_1,\cdots,x_t)=\frac{n(x_1,\cdots,x_t)}{n} p(xtx1,,xt)=nn(x1,,xt)
​ 但这样有个问题:

​ 当序列很长时,因为文本量不够大,很可能 n ( x 1 , ⋯ , x T ) ≤ 1 n(x_1,\cdots,x_T)\le 1 n(x1,,xT)1,即某些序列是合理的,但文本中没有出现。可以使用马尔科夫假设缓解这个问题:

  1. 一元语法: p ( x 1 , x 2 , x 3 , x 4 ) = n ( x 1 ) n n ( x 2 ) n n ( x 3 ) n n ( x 5 ) n p(x_1,x_2,x_3,x_4)=\frac{n(x_1)}n\frac{n(x_2)}n\frac{n(x_3)}n\frac{n(x_5)}n p(x1,x2,x3,x4)=nn(x1)nn(x2)nn(x3)nn(x5)与前面无关
  2. 二元语法: p ( x 1 , x 2 , x 3 , x 4 ) = n ( x 1 ) n n ( x 1 , x 2 ) n ( x 1 ) n ( x 2 , x 3 ) n ( x 2 ) n ( x 3 , x 4 ) n ( x 3 ) p(x_1,x_2,x_3,x_4)=\frac{n(x_1)}n \frac{n(x_1,x_2)}{n(x_1)} \frac{n(x_2,x_3)}{n(x_2)} \frac{n(x_3,x_4)}{n(x_3)} p(x1,x2,x3,x4)=nn(x1)n(x1)n(x1,x2)n(x2)n(x2,x3)n(x3)n(x3,x4)与前面一个词有关系
  3. 三元语法: p ( x 1 , x 2 , x 3 , x 4 ) = p ( x 1 ) p ( x 2 ∣ x 1 ) p ( x 3 ∣ x 1 , x 2 ) p ( x 4 ∣ x 2 , x 3 ) p(x_1,x_2,x_3,x_4)=p(x_1)p(x_2|x_1)p(x_3|x_1,x_2)p(x_4|x_2,x_3) p(x1,x2,x3,x4)=p(x1)p(x2x1)p(x3x1,x2)p(x4x2,x3)与前面两个词有关系

​ 另一种常见的策略师执行某种形式的拉普拉斯平滑,具体方法是在所有计数中添加一个小常量,用 n n n表示训练集中的单词总数,用 m m m表示唯一单词的数量,这个方案有助于处理单元素问题

在这里插入图片描述

​ 其中 ϵ 1 , ϵ 2 , ϵ 3 \epsilon_1,\epsilon_2,\epsilon_3 ϵ1,ϵ2,ϵ3是超参数,这样的模型很容易变得无效,原因如下:首先,我们需要存储所有的计数; 其次,这完全忽略了单词的意思。 例如,“猫”(cat)和“猫科动物”(feline)可能出现在相关的上下文中, 但是想根据上下文调整这类模型其实是相当困难的。 最后,长单词序列大部分是没出现过的, 因此一个模型如果只是简单地统计先前“看到”的单词序列频率, 那么模型面对这种问题肯定是表现不佳的。

2.语言模型和数据集的代码实现

import random
import torch
import re
from d2l import torch as d2ld2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt','090b5e7e70c295757f55df93cb0a180b9691891a')def read_time_machine():  # @save"""将时间机器数据集加载到文本行的列表中"""with open(d2l.download('time_machine'), 'r') as f:lines = f.readlines()return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]tokens = d2l.tokenize(read_time_machine())
# 因为每个文本行不一定是一个句子或一个段落,因此我们把所有文本行拼接到一起
corpus = [token for line in tokens for token in line]
vocab = d2l.Vocab(corpus)
print(vocab.token_freqs[:10])freqs = [freq for token, freq in vocab.token_freqs]
print(freqs[:10])
d2l.plot(freqs, xlabel='token: x', ylabel='frequency: n(x)',xscale='log', yscale='log')
d2l.plt.show()

在这里插入图片描述

​ 词频图:词频以一种明确的方式迅速衰减,将前几个单词作为例外消除后(停用词,类似the,a,I,and之类的),生育的所有单词大致遵循双对数坐标图上的一条直线,这意味着单词的频率满足齐普夫定律(Zipf’s law),即第 i i i个最常用的频率 n i n_i ni为:
n i ∝ 1 n i n_i\propto \frac 1{n_i} nini1
等价于:


l o g n i = − α l o g i + c log\ n_i = -\alpha log\ i+c log ni=αlog i+c
​ 这意味着通过计数统计和平滑来建模单词是不可行的,因为这样建模的结果会大大高估尾部单词的频率。

多元语法

​ 注意最新的d2l库中的Vocab类好像有问题,处理不了元组,将库中的Vocab类替换一下,再加上count_corpus函数就可以正常处理元组。


bigram_tokens = [pair for pair in zip(corpus[:-1], corpus[1:])]
bigram_vocab = d2l.Vocab(bigram_tokens)
print('二元:',bigram_vocab.token_freqs[:10])trigram_tokens = [triple for triple in zip(corpus[:-2], corpus[1:-1], corpus[2:])]
trigram_vocab = d2l.Vocab(trigram_tokens)
print('三元:',trigram_vocab.token_freqs[:10])bigram_freqs = [freq for token, freq in bigram_vocab.token_freqs]
trigram_freqs = [freq for token, freq in trigram_vocab.token_freqs]
d2l.plot([freqs, bigram_freqs, trigram_freqs], xlabel='token: x',ylabel='frequency: n(x)', xscale='log', yscale='log',legend=['unigram', 'bigram', 'trigram'])
d2l.plt.show()

在这里插入图片描述

​ 发现:

  1. 除了一元语法词,单词序列似乎也遵循齐普夫定律, 尽管公式中的指数𝛼更小 (指数的大小受序列长度的影响);
  2. 词表中n元组的数量并没有那么大,这说明语言中存在相当多的结构, 这些结构给了我们应用模型的希望;
  3. 很多n元组很少出现,这使得拉普拉斯平滑非常不适合语言建模。 作为代替,我们将使用基于深度学习的模型。

随机采样

# 随机采样
def seq_data_iter_random(corpus, batch_size, num_steps):  #@save"""使用随机抽样生成一个小批量子序列"""# num_steps意思是取多少个token来进行预测# 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1corpus = corpus[random.randint(0, num_steps - 1):]# 减去1,是因为我们需要考虑标签,最后一个样本没有可预测的数据num_subseqs = (len(corpus) - 1) // num_steps# 长度为num_steps的子序列的起始索引initial_indices = list(range(0, num_subseqs * num_steps, num_steps))# 在随机抽样的迭代过程中,# 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻print(initial_indices)random.shuffle(initial_indices) # 打乱顺序,不会生成新的列表,在原列表上打乱的print(initial_indices)def data(pos):# 返回从pos位置开始的长度为num_steps的序列return corpus[pos: pos + num_steps]num_batches = num_subseqs // batch_sizefor i in range(0, batch_size * num_batches, batch_size): #后面一个是步长# 在这里,initial_indices包含子序列的随机起始索引initial_indices_per_batch = initial_indices[i: i + batch_size]X = [data(j) for j in initial_indices_per_batch]Y = [data(j + 1) for j in initial_indices_per_batch]yield torch.tensor(X), torch.tensor(Y)'''生成一个0到34的序列,假设批量大小为2,时间步数为5,这意味着可以生成(35-1)/5 = 6个特征-标签子序列对'''my_seq = list(range(35))
for X, Y in seq_data_iter_random(my_seq, batch_size=2, num_steps=5):print('X: ', X, '\nY:', Y)

顺序分区

def seq_data_iter_sequential(corpus, batch_size, num_steps):  # @save"""使用顺序分区生成一个小批量子序列"""# 顺序分区保证不同批次内的子序列在原始序列上是连续的,不会跳过任何元素,这对某些任务(语言建模)可能更合适# X:  tensor([[ 1,  2,  3,  4,  5],#         [17, 18, 19, 20, 21]])# Y: tensor([[ 2,  3,  4,  5,  6],#         [18, 19, 20, 21, 22]])# X:  tensor([[ 6,  7,  8,  9, 10], 和[1,2,3,4,5]是连续的#         [22, 23, 24, 25, 26]])    和[17,18,19,20,21]是连续的# Y: tensor([[ 7,  8,  9, 10, 11],#         [23, 24, 25, 26, 27]])# X:  tensor([[11, 12, 13, 14, 15],#         [27, 28, 29, 30, 31]])# Y: tensor([[12, 13, 14, 15, 16],#         [28, 29, 30, 31, 32]])# 从随机偏移量开始划分序列offset = random.randint(0, num_steps)num_tokens = ((len(corpus) - offset - 1) // batch_size) * batch_sizeXs = torch.tensor(corpus[offset: offset + num_tokens])Ys = torch.tensor(corpus[offset + 1: offset + 1 + num_tokens])Xs, Ys = Xs.reshape(batch_size, -1), Ys.reshape(batch_size, -1)num_batches = Xs.shape[1] // num_stepsfor i in range(0, num_steps * num_batches, num_steps):X = Xs[:, i: i + num_steps]Y = Ys[:, i: i + num_steps]print('X: ', X, '\nY:', Y)yield X, Y #返回一个值序列,而不是一次性返回所有值。for X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):print('X: ', X, '\nY:', Y)

包装

class SeqDataLoader:  # @save"""加载序列数据的迭代器"""def __init__(self, batch_size, num_steps, use_random_iter, max_tokens):if use_random_iter:self.data_iter_fn = d2l.seq_data_iter_randomelse:self.data_iter_fn = d2l.seq_data_iter_sequentialself.corpus, self.vocab = d2l.load_corpus_time_machine(max_tokens)self.batch_size, self.num_steps = batch_size, num_stepsdef __iter__(self):return self.data_iter_fn(self.corpus, self.batch_size, self.num_steps)def load_data_time_machine(batch_size, num_steps,  # @saveuse_random_iter=False, max_tokens=10000):"""返回时光机器数据集的迭代器和词表"""data_iter = SeqDataLoader(batch_size, num_steps, use_random_iter, max_tokens)return data_iter, data_iter.vocab

NLP BERT GPT等模型中 tokenizer 类别说明详解-腾讯云开发者社区-腾讯云 (tencent.com)

http://www.lryc.cn/news/415486.html

相关文章:

  • (学习总结10)C++类和对象1
  • 进击大数据系列(一):Hadoop 基本概念与生态介绍
  • 评价类算法--模糊综合评价算法模型
  • 哪些系统需要按照等保2.0进行定级?
  • 自注意力和位置编码
  • “文件夹提示无法访问?高效数据恢复策略全解析“
  • 结构开发笔记(一):外壳IP防水等级与IP防水铝壳体初步选型
  • WPF Datagrid控件,获取某一个单元格中的控件
  • P10838 『FLA - I』庭中有奇树
  • WebRTC简介
  • 一套直播系统带商城源码 附搭建教程
  • Netty 总结与补充(十)
  • 循环实现异步变同步的问题
  • 测试GPT4o分析巴黎奥运会奖牌数据
  • TF卡(SD NAND)参考设计和使用提示
  • 电源芯片负载调整率测试方法、原理以及自动化测试的优势-纳米软件
  • C++威力强大的助手 --- const
  • 测试环境搭建整套大数据系统(十八:ubuntu镜像源进行更新)
  • 第128天:内网安全-横向移动IPCATSC 命令Impacket 套件CS 插件全自动
  • 记录一次学习过程(msf、cs的使用、横向渗透等等)
  • C#中DataTable新增列、删除列、更改列名、交换列位置
  • C#编写多导联扫描式的波形图Demo
  • QT网络编程
  • Django ASGI服务
  • Servlet(2)
  • 电竞玩家的云端盛宴!四大云电脑平台:ToDesk、顺网云、青椒云、极云普惠云实测大比拼
  • 基础复习(反射、注解、动态代理)
  • OGG同步目标端中文乱码处理
  • 使用WPF调用Python进行图像灰度处理
  • (二)测试工具