机器学习深度学习—语言模型和数据集

news/2025/1/12 17:23:32/

👨‍🎓作者简介:一位即将上大四,正专攻机器学习的保研er
🌌上期文章:机器学习&&深度学习——文本预处理
📚订阅专栏:机器学习&&深度学习
希望文章对你们有所帮助

语言模型和数据集

  • 引入
  • 学习语言模型
  • 马尔可夫模型与n元语法
  • 自然语言统计
  • 读取长序列数据
    • 随机采样
    • 顺序分区
    • 包装
  • 小结

引入

假设长度为T的文本序列,那么语言模型的目标是估计序列的联合概率:
P ( x 1 , x 2 , . . . , x T ) P(x_1,x_2,...,x_T) P(x1,x2,...,xT)
在抽取一个词元:
x t 符合 P ( x t ∣ x t − 1 , . . . , x 1 ) x_t符合P(x_t|x_{t-1},...,x_1) xt符合P(xtxt1,...,x1)
的时候,一个理想的语言模型就能基于模型本身生成自然文本。
而从这样的模型中提取的样本要作为自然语言来传递,因此我们需要生成一个有意义的对话,也就是说,我们的设计需要理解文本,而不仅仅是生成语法合理的内容。
例如:“狗咬人”就比“人咬狗”看起来更正常;“我想吃老妈”看起来语法没问题,但是很emmm,而“我想吃,老妈”就看起来合理多了。

学习语言模型

从基本概率规则开始:
P ( x 1 , x 2 , . . . , x T ) = ∏ t = 1 T P ( x t ∣ x 1 , . . . , x t − 1 ) P(x_1,x_2,...,x_T)=\prod_{t=1}^TP(x_t|x_1,...,x_{t-1}) P(x1,x2,...,xT)=t=1TP(xtx1,...,xt1)
那么包含了四个单词的一个文本序列的概率是:
P ( d e e p , l e a r n i n g , i s , f u n ) = P ( d e e p ) P ( l e a r n i n g ∣ d e e p ) P ( i s ∣ d e e p , l e a r n i n g ) P ( f u n ∣ d e e p , l e a r n i n g , i s ) P(deep,learning,is,fun)=P(deep)P(learning|deep)P(is|deep,learning)P(fun|deep,learning,is) P(deep,learning,is,fun)=P(deep)P(learningdeep)P(isdeep,learning)P(fundeep,learning,is)
而其中的P,也就是数据集中词的概率可以根据给定词的相对词频来计算,如:
P ^ ( l e a r n i n g ∣ d e e p ) = n ( d e e p , l e a r n i n g ) n ( d e e p ) \hat{P}(learning|deep)=\frac{n(deep,learning)}{n(deep)} P^(learningdeep)=n(deep)n(deep,learning)
其中,n(x)和n(x,x)分别是单个单词和连续单词对的出现次数。
但连续的单词出现的概率会低很多,特别可能有些是三个或更多的单词组合( 除非我们提供某种解决方案,来将这些单词组合指定为非零计数,否则将无法在语言模型中使用它们。如果数据集很小,或者单词非常罕见,那么这类单词出现一次的机会可能都找不到。)

马尔可夫模型与n元语法

之前讲过马尔可夫模型,比如一阶马尔可夫性质:
P ( x t + 1 ∣ x t , . . . , x 1 ) = P ( x t + 1 ∣ x t ) P(x_{t+1}|x_t,...,x_1)=P(x_{t+1}|x_t) P(xt+1xt,...,x1)=P(xt+1xt)
阶数越高,对应的依赖关系就越长,这种性质推导出了很多可以应用于序列建模的公式:
P ( x 1 , x 2 , x 3 , x 4 ) = P ( x 1 ) P ( x 2 ) P ( x 3 ) P ( x 4 ) P ( x 1 , x 2 , x 3 , x 4 ) = P ( x 1 ) P ( x 2 ∣ x 1 ) P ( x 3 ∣ x 2 ) P ( x 4 ∣ 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(x_1,x_2,x_3,x_4)=P(x_1)P(x_2)P(x_3)P(x_4)\\ P(x_1,x_2,x_3,x_4)=P(x_1)P(x_2|x_1)P(x_3|x_2)P(x_4|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(x2)P(x3)P(x4)P(x1,x2,x3,x4)=P(x1)P(x2x1)P(x3x2)P(x4x3)P(x1,x2,x3,x4)=P(x1)P(x2x1)P(x3x1,x2)P(x4x2,x3)
上面上式分别被称为一元语法二元语法三元语法

自然语言统计

我们首先在《时光机器》数据集总构建词表,并打印前10个最常用单词:

import random
import torch
from d2l import torch as d2ltokens = d2l.tokenize(d2l.read_time_machine())
# 每个文本行不一定是一个句子或一个段落,因此我们把所有文本行拼接到一起
corpus = [token for line in tokens for token in line]
vocab = d2l.Vocab(corpus)
print(vocab.token_freqs[:10])

运行结果:

[(‘the’, 2261), (‘i’, 1267), (‘and’, 1245), (‘of’, 1155), (‘a’, 816), (‘to’, 695), (‘was’, 552), (‘in’, 541), (‘that’, 443), (‘my’, 440)]

上面的很多流行词,看起来可能没有那么有意义,被称为停用词
我们可以打印一下词频图:

freqs = [freq for token, freq in vocab.token_freqs]
d2l.plot(freqs, xlabel='token: x', ylabel='frequency: n(x)',xscale='log', yscale='log')
d2l.plt.show()

在这里插入图片描述
这个图可以发现,词频在以一种明确的方式迅速衰减。将前几个单词作为例外消除后,剩余的单词大致遵循双对数坐标图上的一条直线(单词满足着齐普夫定律),即第i个最常用单词的频率为:
n i ≈ 1 i α n_i≈\frac{1}{i^α} niiα1
等价于
l o g n i = − α l o g i + c logn_i=-αlogi+c logni=αlogi+c
其中α是刻画分布的质数,c是常数。
我们可以验证二元语法、三元语法等的频率是否和一元语法的频率表现出相同的行为方式:

# 二元语法
bigram_tokens = [pair for pair in zip(corpus[:-1], corpus[1:])]  # 第0位到最后一位以及第1位到最后一位组合起来就是二元组
bigram_vocab = d2l.Vocab(bigram_tokens)
# 三元语法
trigram_tokens = [triple for triple in zip(corpus[:-2], corpus[1:-1], corpus[2:]
)]
trigram_vocab = d2l.Vocab(trigram_tokens)
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()

运行结果:
在这里插入图片描述
这张图可以看出:除了一元语法,单词序列也遵循齐普夫定律,区别也就是α更小(指数大小受序列长度影响)

读取长序列数据

由于文本序列可以是任意长的,于是任意长的序列可以被我们划分为具有相同时间步数的子序列。当训练我们的神经网络时,这样的小批量子序列将被输入到模型中。下图给出了n=5的情况:
在这里插入图片描述
可以看出,我们也可以选择任意偏移量来指示初始位置,所以我们有很好的自由度。
上图中的他们都一样好,但是我们如果只能选一个偏移量,那么用来训练网络的、所有可能的子序列的覆盖范围是有限的。
因此我们可以从随机偏移量开始划分序列,以同时获得覆盖性和随机性。

随机采样

在随机采样中,每个样本都是在原始的长序列上任意捕获的子序列。 在迭代过程中,来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻。 对于语言建模,目标是基于到目前为止我们看到的词元来预测下一个词元, 因此标签是移位了一个词元的原始序列。
下面的代码每次可以从数据中随机生成一个小批量。 在这里,参数batch_size指定了每个小批量中子序列样本的数目, 参数num_steps是每个子序列中预定义的时间步数。

import torch
import random
from d2l import torch as d2ldef seq_data_iter_random(corpus, batch_size, num_steps):  #@save"""使用随机抽样生成一个小批量子序列"""# 从随机偏移量开始对序列进行分区,随机范围包括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))# 在随机抽样的迭代过程中,# 来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻random.shuffle(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个“特征-标签”子序列对。如果设置小批量大小为2,我们只能得到3个小批量。

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)

结果:

X: tensor([[22, 23, 24, 25, 26],
[27, 28, 29, 30, 31]])
Y: tensor([[23, 24, 25, 26, 27],
[28, 29, 30, 31, 32]])
X: tensor([[ 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16]])
Y: tensor([[ 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17]])
X: tensor([[ 2, 3, 4, 5, 6],
[17, 18, 19, 20, 21]])
Y: tensor([[ 3, 4, 5, 6, 7],
[18, 19, 20, 21, 22]])

可以看出Y比起对应的X同位置都是多一个的。

顺序分区

在迭代过程中,除了对原始序列可以随机抽样外,我们还可以保证两个相邻的小批量中的子序列在原始序列上也是相邻的。这种策略在基于小批量的迭代过程中保留了拆分的子序列的顺序,因此称为顺序分区。

def seq_data_iter_sequential(corpus, batch_size, num_steps):  #@save"""使用顺序分区生成一个小批量子序列"""# 从随机偏移量开始划分序列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]yield X, Y

基于相同的设置,通过顺序分区读取每个小批量的子序列的特征X和标签Y。 通过将它们打印出来可以发现: 迭代期间来自两个相邻的小批量中的子序列在原始序列中确实是相邻的(每个相邻X之间数据都是接在一起的)。

my_seq = list(range(35))
for X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):print('X: ', X, '\nY:', Y)
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],[22, 23, 24, 25, 26]]) 
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]])

包装

我们将上面的两个采样函数包装到一个类中,以便以后可以将其用作数据迭代器。

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)

最后定义一个load_data_time_machine函数,同时返回数据迭代器和词表:

def load_data_time_machine(batch_size, num_steps, use_random_iter=False, max_tokens=10000):  #@save"""返回时光机器数据集的迭代器和词表"""data_iter = SeqDataLoader(batch_size, num_steps, use_random_iter, max_tokens)return data_iter, data_iter.vocab

小结

1、语言模型是自然语言处理的关键。
2、n元语法通过截断相关性,为处理长序列提供了一种实用的模型。
3、长序列存在一个问题:它们很少出现或者从不出现。
4、齐普夫定律支配着单词的分布,这个分布不仅适用于一元语法,还适用于其他n元语法。
5、读取长序列的主要方式是随机采样和顺序分区。在迭代过程中,后者可以保证来自两个相邻的小批量中的子序列在原始序列上也是相邻的。


http://www.ppmy.cn/news/1028145.html

相关文章

【自动化测试】概述了解

文章目录 一、了解自动化测试二、工具的配合使用三、补充 努力经营当下 直至未来明朗! 一、了解自动化测试 自动化测试主要是UI自动化以及接口自动化。功能测试与UI自动化测试的相似度是最高的,当功能测试转型自动化测试的时候一般最先接触的是UI自动化…

BGP的工作过程及报文

IGP核心:路由的计算。OSPF,ISIS等 BGP核心:路由的传递,不产生路由,只是路由的搬运工,一般用于规模特别大的网络中,只要TCP可达就可以建立邻居。 大型企业分支间采用BGP进行路由传递,不同的分支属于不同的BGP的AS,它们通过BGP进行路由交互。企业与运营商之间可使用BGP进行…

(6)(6.3) 复合连接的故障处理

文章目录 6.3 复合连接的故障处理 6.4 相关话题 6.3 复合连接的故障处理 带有 F7 或 H7 处理器并有 CAN 接口的自动驾驶仪使用的固件提供两个 USB 接口。一个用于正常的 MAVLink 连接,一个用于 SLCAN 串行连接到 CAN 接口进行配置和固件更新。这被称为复合型 USB…

Linux基础知识学习

一、i.mx6ull交叉编译QT项目 1、步骤 2、安装交叉编译链 使能交叉编译链,使能刚安装的编译器,不然还是老版本的 source /opt/fsl-imx-x11/4.1.15-2.1.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi 3、命令行交叉编译QT项目 wandzhangwa…

【舌尖优省PLUS】美团、饿了么外卖免费领红包,尽情享受美食与省钱!

家人们!我昨天刚开发完并上线了一个超棒的外卖免费领红包的小程序,它叫做【舌尖优省PLUS】!如果你喜欢美食,还想省下一些钱,那这个小程序绝对不能错过! 在【舌尖优省PLUS】上,你可以通过简单的…

大数据CDH6.3应知应会

文章目录 1. CDH 简介1.1 CDH版本 2. CDH 集群的优势是什么?3. CDH 集群的部署方式有哪些?4. CDH 集群中如何进行故障排除和监控?5. 你有使用 CDH 部署集群的经验吗?6. CDH 集群如何实现高可用性?7. 在 CDH 集群中&…

预测算法系列5—核极限学习机KELM及其实现(Matlab)

回归: 分类: 在上一篇文章中我介绍了极限学习机ELM的实现和优化,极限学习机虽然具有训练速度快、复杂度低、克服了传统梯度算法的局部极小、过拟合和学习率的选择不合适等优点,但在比较复杂的分类、回归等非线性模式识别任务往往…

Maven工程的安装配置及搭建(集成eclipse完成案例,保姆级教学)

目录 一.下载及安装及环境配置 1.下载及安装 2.环境变量的配置 3.检测是否安装成功 4.配置Maven 1.更换本地仓库 2. 配置镜像 二.集成eclipse完成案例 1.eclipse前期配置Maven 2.创建Maven工程 一.下载及安装及环境配置 1.下载及安装 下载地址:Maven – Down…