【动手学深度学习】--语言模型

news2024/9/20 18:38:06

文章目录

  • 语言模型
    • 1.学习语言模型
    • 2.马尔可夫模型与N元语法
    • 3.自然语言统计
    • 4.读取长序列数据
      • 4.1随机采样
      • 4.2顺序分区

语言模型

学习视频:语言模型【动手学深度学习v2】
官方笔记:语言模型和数据集

在【文本预处理】中了解了如何将文本数据映射为词元,以及将这些词元可以视为一系列离散的观测,例如单词或字符。假设长度为T的文本序列中的词元依次为 x 1 , x 2 , . . , x T x_1,x_2,..,x_T x1,x2,..,xT,于是, x t ( 1 ≤ t ≤ T ) x_t(1≤t≤T) xt(1tT)可以被认为是文本序列在时间步t处的观测或标签, 在给定这样的文本序列时,语言模型(language model)的目标是估计序列的联合概率 P ( x 1 , x 2 , . . . , x T ) P(x_1,x_2,...,x_T) P(x1,x2,...,xT)

image-20230908112113250

image-20230908113226499

1.学习语言模型

使用计数来建模

image-20230908112248119

image-20230908113436891

image-20230908113516605

2.马尔可夫模型与N元语法

image-20230908113607126

image-20230908112426860

总结:

  • 语言模型估计文本序列的联合概率
  • 使用统计方法时常采用n元语法

3.自然语言统计

看看在真实数据上如果进行自然语言统计,根据前面介绍的时光机器数据集构建词表,并打印前10个最常用的(频率最高的)单词

import random
import torch
from d2l import torch as d2l

tokens = d2l.tokenize(d2l.read_time_machine())
# 因为每个文本行不一定是一个句子或一个段落,因此我们把所有文本行拼接到一起
corpus = [token for line in tokens for token in line]
vocab = d2l.Vocab(corpus)
vocab.token_freqs[:10]
[('the', 2261),
 ('i', 1267),
 ('and', 1245),
 ('of', 1155),
 ('a', 816),
 ('to', 695),
 ('was', 552),
 ('in', 541),
 ('that', 443),
 ('my', 440)]

正如我们所看到的,最流行的词看起来很无聊, 这些词通常被称为停用词(stop words),因此可以被过滤掉。 尽管如此,它们本身仍然是有意义的,我们仍然会在模型中使用它们。 此外,还有个明显的问题是词频衰减的速度相当地快。 例如,最常用单词的词频对比,第10个还不到第1个的1/5。 为了更好地理解,我们可以画出的词频图:

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

image-20230908114030770

image-20230908163607645

bigram_tokens = [pair for pair in zip(corpus[:-1], corpus[1:])]
bigram_vocab = d2l.Vocab(bigram_tokens)
bigram_vocab.token_freqs[:10]
[(('of', 'the'), 309),
 (('in', 'the'), 169),
 (('i', 'had'), 130),
 (('i', 'was'), 112),
 (('and', 'the'), 109),
 (('the', 'time'), 102),
 (('it', 'was'), 99),
 (('to', 'the'), 85),
 (('as', 'i'), 78),
 (('of', 'a'), 73)]

这里值得注意:在十个最频繁的词对中,有九个是由两个停用词组成的, 只有一个与“the time”有关。 我们再进一步看看三元语法的频率是否表现出相同的行为方式

trigram_tokens = [triple for triple in zip(
    corpus[:-2], corpus[1:-1], corpus[2:])]
trigram_vocab = d2l.Vocab(trigram_tokens)
trigram_vocab.token_freqs[:10]
[(('the', 'time', 'traveller'), 59),
 (('the', 'time', 'machine'), 30),
 (('the', 'medical', 'man'), 24),
 (('it', 'seemed', 'to'), 16),
 (('it', 'was', 'a'), 15),
 (('here', 'and', 'there'), 15),
 (('seemed', 'to', 'me'), 14),
 (('i', 'did', 'not'), 14),
 (('i', 'saw', 'the'), 13),
 (('i', 'began', 'to'), 13)]

最后,我们直观地对比三种模型中的词元频率:一元语法、二元语法和三元语法。

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'])

image-20230908121616250

上述表明:

1.除了一元语法词,单词序列似乎也遵循齐普夫定律,尽管公式中的指数 α \alpha α更小(指数的大小受序列长度的影响)

2.词表中n元组的数量并没有那么大,这说明语言中存在相当多的结构,这些结构给了我们应用模型的希望

3.很多n元组很少出现,这使得拉普拉斯平滑非常不适合语言建模,作为代替,我们将使用基于深度学习的模型

4.读取长序列数据

image-20230908164043832

image-20230908164053695

4.1随机采样

在随机采样中,每个样本都是在原始的长序列上任意捕获的子序列。 在迭代过程中,来自两个相邻的、随机的、小批量中的子序列不一定在原始序列上相邻。 对于语言建模,目标是基于到目前为止我们看到的词元来预测下一个词元, 因此标签是移位了一个词元的原始序列。

下面的代码每次可以从数据中随机生成一个小批量。 在这里,参数batch_size指定了每个小批量中子序列样本的数目, 参数num_steps是每个子序列中预定义的时间步数。

def seq_data_iter_random(corpus, batch_size, num_steps):  #@save
    """使用随机抽样生成一个小批量子序列"""
    # 从随机偏移量开始对序列进行分区,随机范围包括num_steps-1
    corpus = 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_size
    for 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([[13, 14, 15, 16, 17],
        [28, 29, 30, 31, 32]])
Y: tensor([[14, 15, 16, 17, 18],
        [29, 30, 31, 32, 33]])
X:  tensor([[ 3,  4,  5,  6,  7],
        [18, 19, 20, 21, 22]])
Y: tensor([[ 4,  5,  6,  7,  8],
        [19, 20, 21, 22, 23]])
X:  tensor([[ 8,  9, 10, 11, 12],
        [23, 24, 25, 26, 27]])
Y: tensor([[ 9, 10, 11, 12, 13],
        [24, 25, 26, 27, 28]])

4.2顺序分区

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

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_size
    Xs = 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_steps
    for 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。 通过将它们打印出来可以发现: 迭代期间来自两个相邻的小批量中的子序列在原始序列中确实是相邻的。

for X, Y in seq_data_iter_sequential(my_seq, batch_size=2, num_steps=5):
    print('X: ', X, '\nY:', Y)
X:  tensor([[ 0,  1,  2,  3,  4],
        [17, 18, 19, 20, 21]])
Y: tensor([[ 1,  2,  3,  4,  5],
        [18, 19, 20, 21, 22]])
X:  tensor([[ 5,  6,  7,  8,  9],
        [22, 23, 24, 25, 26]])
Y: tensor([[ 6,  7,  8,  9, 10],
        [23, 24, 25, 26, 27]])
X:  tensor([[10, 11, 12, 13, 14],
        [27, 28, 29, 30, 31]])
Y: tensor([[11, 12, 13, 14, 15],
        [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_random
        else:
            self.data_iter_fn = d2l.seq_data_iter_sequential
        self.corpus, self.vocab = d2l.load_corpus_time_machine(max_tokens)
        self.batch_size, self.num_steps = batch_size, num_steps

    def __iter__(self):
        return self.data_iter_fn(self.corpus, self.batch_size, self.num_steps)

最后,我们定义了一个函数load_data_time_machine, 它同时返回数据迭代器和词表, 因此可以与其他带有load_data前缀的函数

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/988528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ATFX汇市:美初请失业金人数21.6万人,连降四期,劳动力供需偏紧

ATFX汇市:9月7日,美国劳工部数据显示:美国至9月2日当周初请失业金人数最新值21.6万人,低于前值22.9万人(修正前22.8万人),低于预期值23.4万人。回顾历史数据,美国初请失业率人数从25…

【数学建模】2023数学建模国赛C题完整思路和代码解析

C题第一问代码和求解结果已完成,第一问数据量有点大,经过编程整理出来了单品销售额的汇总数据、将附件2中的单品编码替换为分类编码,整理出了蔬菜各品类随着时间变化的销售量,并做出了这些疏菜品类的皮尔森相关系数的热力图&#…

NIFI实现JSON转SQL并插入到数据库表中

说明 本文中的NIFI是使用docker进行安装的,所有的配置参考:docker安装Apache NIFI 需求背景 现在有一个文件,里面存储的是一些json格式的数据,要求将文件中的数据存入数据库表中,以下是一些模拟的数据和对应的数据库…

传输层协议 --TCP报文格式详细介绍

一、 TCP协议格式 TCP如何将报头与有效载荷进行分离? 当TCP从底层获取到一个报文后,虽然TCP不知道报头的具体长度,但报文的前20个字节是TCP的基本报头,并且这20字节当中涵盖了4位的首部长度。 因此TCP是这样分离报头与有效载荷的…

Java——》ThreadLocal

推荐链接: 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…

ChatGPT:深度学习和机器学习的知识桥梁

目录 ChatGPT简介 ChatGPT的特点 ChatGPT的应用领域 ChatGPT的工作原理 与ChatGPT的交互 ChatGPT的优势 ChatGPT在机器学习中的应用 ChatGPT在深度学习中的应用 总结 近年来,随着深度学习技术的不断发展,自然语言处理技术也取得了显著的进步。其…

软件设计模式(二):工厂、门面、调停者和装饰器模式

前言 在这篇文章中,荔枝将会梳理软件设计模式中的四种:工厂模式、Facade模式、Mediator模式和装饰器Decorator模式。其中比较重要的就是工厂模式和装饰器模式,工厂模式在开发中使用的频数比较高。希望荔枝的这篇文章能讲清楚哈哈哈哈&#xf…

OpenCV(三十一):形态学操作

​​​​​​1.形态学操作 OpenCV 提供了丰富的函数来进行形态学操作,包括腐蚀、膨胀、开运算、闭运算等。下面介绍一些常用的 OpenCV 形态学操作函数: 腐蚀操作(Erosion): erode(src, dst, kernel, anchor, iteration…

【LeetCode】剑指 Offer <二刷>(6)

目录 题目:剑指 Offer 12. 矩阵中的路径 - 力扣(LeetCode) 题目的接口: 解题思路: 代码: 过啦!!! 题目:剑指 Offer 13. 机器人的运动范围 - 力扣&#…

docker-compose安装mysql

基于docker-compose快速安装mysql 目录 一、目录结构 1、 docker-compose.yml 2、 my.cnf 3、error.log 二、执行安装 三、连接使用 一、目录结构 1、 docker-compose.yml version: 3 services:mysql:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:5.7 #…

Kubernetes核心概念

Kubernetes是一个工业级的容器编排平台。 Kubernetes核心功能 服务发现和负载均衡。容器的自动装箱,调度(scheduling),按照容器的规格(需要的cpu和内存等)确定一个容器存放到集群中的哪一个机器上。进行自…

创建vue3项目并引用elementui

1.创建vu3项目&#xff1a; 执行命令 npm create vuelatest 2.终端会出现如下选项&#xff0c;不确定的直接enter键进入下一步&#xff1b; 3.然后再执行下方命令&#xff1a; cd <your-project-name> npm install4.安装依赖成功后引入elementui,执行命令&#xff1a…

高压电容器的内部结构是什么样的?

高压电容器的内部结构取决于其具体的设计和用途&#xff0c;但通常包括以下主要组件&#xff1a; 电介质&#xff1a;电介质是高压电容器内部的核心部分。它通常由绝缘材料制成&#xff0c;如聚丙烯薄膜、聚酯薄膜、陶瓷或其他高绝缘性材料。电介质的选择取决于电容器的电压等级…

盘点那些有高级客服分配功能的软件系统

过去&#xff0c;很多企业虽然有服务意识&#xff0c;但并不强烈&#xff0c;现在客户需求以及团队运营的发展推动着企业在客户管理的方式上采用更有效的服务方式来应对实际的变化&#xff0c;尤其是客服行业&#xff0c;所以很多企业在客服的管理和分配上下尽了功夫&#xff0…

Unity的UI管理器

1、代码 public class UIManager {private static UIManager instance new UIManager();public static UIManager Instance > instance;//存储显示着的面板脚本&#xff08;不是面板Gameobject&#xff09;&#xff0c;每显示一个面板就存入字典//隐藏的时候获取字典中对…

【自动化测试】之PO模式介绍及案例

目录 概念 PO三层模式&#xff1a; 1. 构建基础的 BasePage 对象层 2. 构建首页的 Page 层&#xff08;操作层&#xff09; 3.构建业务层 常用断言方法&#xff1a; 4. 构建用例集&#xff0c;执行文件&#xff0c;输出自动化测试报告 测试报告模板 概念 PO&#xff08…

【C++】详解红黑树并模拟实现

前言&#xff1a; 上篇文章我们一起学习了AVL树比模拟实现&#xff0c;我们发现AVL树成功地把时间复杂度降低到了O(logN)。但是同时我们不难发现一个问题&#xff0c;在构建AVL树中我们也付出了不小的代价&#xff0c;频繁的旋转操作导致效率变低。为了解决这个问题&#xff0c…

使用Fastchat部署vicuna大模型

FastChat是一个用于训练、提供服务和评估基于大型语言模型的聊天机器人的开放平台。其核心特点包括&#xff1a; 最先进模型&#xff08;例如 Vicuna&#xff09;的权重、训练代码和评估代码。一个分布式的多模型提供服务系统&#xff0c;配备 Web 用户界面和与 OpenAI 兼容的…

算法通关村第十七关:黄金挑战-跳跃游戏问题

黄金挑战-跳跃游戏问题 1. 跳跃游戏 LeetCode 55 https://leetcode.cn/problems/jump-game/ 思路分析 关键是判断能否到达终点&#xff0c;不用管每一步跳跃到哪里&#xff0c;而是尽可能的跳跃到最远的位置 看最多能覆盖到哪里&#xff0c;只要不断更新能覆盖的距离&#x…

【狂神】Spring5笔记(一)之IOC

目录 首页&#xff1a; 1.Spring 1.1 简介 1.2 优点 2.IOC理论推导 3.IOC本质 4.HelloSpring ERROR 5.IOC创建对象方式 5.1、无参构造 这个是默认的 5.2、有参构造 6.Spring配置说明 6.1、别名 6.2、Bean的配置 6.3、import 7.DL依赖注入环境 7.1 构造器注入 …