语言模型

一段自然语言文本可以看作是一个离散时间序列
给定一个长度为T的词的序列w1,w2,…,wT,语言模型的目标就是评估该序列是否合理,即计算该序列的概率:
语言模型与数据集 - 图1
假设序列中的每个单词是依次生成的,有
语言模型与数据集 - 图2

语言模型的参数就是词的概率以及给定前几个词情况下的条件概率,可以用词频进行估计

n元语法

  • 序列长度增加,计算和存储多个词共同出现的概率的复杂度会呈指数级增加
  • n元语法通过马尔可夫假设简化模型,马尔科夫假设是指一个词的出现只与前面n个词相关,即n阶马尔可夫链(Markov chain of order n)
    • 语言模型可以改写为

语言模型与数据集 - 图3

  • n元语法的缺陷

    • 参数空间过大-指数级增长
    • 数据稀疏-语言普遍存在的问题

      时序数据的采样

  • 时序数据的一个样本通常包含连续的字符

    • 假设时间步数为5,样本序列为5个字符,即“想”“要”“有”“直”“升”。该样本的标签序列为这些字符分别在训练集中的下一个字符,即“要”“有”“直”“升”“机”
  • 如果序列的长度为T,时间步数为n,那么一共有T−n个合法的样本,但是这些样本有大量的重合,我们通常采用更加高效的采样方式。

    随机采样

    在随机采样中,每个样本是原始序列上任意截取的一段序列
    相邻的两个随机小批量在原始序列上的位置不一定相毗邻。
  1. import torch
  2. import random
  3. def data_iter_random(corpus_indices, batch_size, num_steps, device=None):
  4. # 减1是因为对于长度为n的序列,X最多只有包含其中的前n - 1个字符
  5. num_examples = (len(corpus_indices) - 1) // num_steps # 下取整,得到不重叠情况下的样本个数
  6. example_indices = [i * num_steps for i in range(num_examples)] # 每个样本的第一个字符在corpus_indices中的下标
  7. random.shuffle(example_indices)
  8. def _data(i):
  9. # 返回从i开始的长为num_steps的序列
  10. return corpus_indices[i: i + num_steps]
  11. if device is None:
  12. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  13. for i in range(0, num_examples, batch_size):
  14. # 每次选出batch_size个随机样本
  15. batch_indices = example_indices[i: i + batch_size] # 当前batch的各个样本的首字符的下标
  16. X = [_data(j) for j in batch_indices]
  17. Y = [_data(j + 1) for j in batch_indices]
  18. yield torch.tensor(X, device=device), torch.tensor(Y, device=device)

相邻采样

在相邻采样中,相邻的两个随机小批量在原始序列上的位置相毗邻。

  1. def data_iter_consecutive(corpus_indices, batch_size, num_steps, device=None):
  2. if device is None:
  3. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  4. corpus_len = len(corpus_indices) // batch_size * batch_size # 保留下来的序列的长度
  5. corpus_indices = corpus_indices[: corpus_len] # 仅保留前corpus_len个字符
  6. indices = torch.tensor(corpus_indices, device=device)
  7. indices = indices.view(batch_size, -1) # resize成(batch_size, )
  8. batch_num = (indices.shape[1] - 1) // num_steps
  9. for i in range(batch_num):
  10. i = i * num_steps
  11. X = indices[:, i: i + num_steps]
  12. Y = indices[:, i + 1: i + num_steps + 1]
  13. yield X, Y