语言模型
一段自然语言文本可以看作是一个离散时间序列
给定一个长度为T的词的序列w1,w2,…,wT,语言模型的目标就是评估该序列是否合理,即计算该序列的概率:
假设序列中的每个单词是依次生成的,有
语言模型的参数就是词的概率以及给定前几个词情况下的条件概率,可以用词频进行估计
n元语法
- 序列长度增加,计算和存储多个词共同出现的概率的复杂度会呈指数级增加
- n元语法通过马尔可夫假设简化模型,马尔科夫假设是指一个词的出现只与前面n个词相关,即n阶马尔可夫链(Markov chain of order n)
- 语言模型可以改写为
n元语法的缺陷
时序数据的一个样本通常包含连续的字符
- 假设时间步数为5,样本序列为5个字符,即“想”“要”“有”“直”“升”。该样本的标签序列为这些字符分别在训练集中的下一个字符,即“要”“有”“直”“升”“机”
- 如果序列的长度为T,时间步数为n,那么一共有T−n个合法的样本,但是这些样本有大量的重合,我们通常采用更加高效的采样方式。
随机采样
在随机采样中,每个样本是原始序列上任意截取的一段序列
相邻的两个随机小批量在原始序列上的位置不一定相毗邻。
import torchimport randomdef data_iter_random(corpus_indices, batch_size, num_steps, device=None):# 减1是因为对于长度为n的序列,X最多只有包含其中的前n - 1个字符num_examples = (len(corpus_indices) - 1) // num_steps # 下取整,得到不重叠情况下的样本个数example_indices = [i * num_steps for i in range(num_examples)] # 每个样本的第一个字符在corpus_indices中的下标random.shuffle(example_indices)def _data(i):# 返回从i开始的长为num_steps的序列return corpus_indices[i: i + num_steps]if device is None:device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')for i in range(0, num_examples, batch_size):# 每次选出batch_size个随机样本batch_indices = example_indices[i: i + batch_size] # 当前batch的各个样本的首字符的下标X = [_data(j) for j in batch_indices]Y = [_data(j + 1) for j in batch_indices]yield torch.tensor(X, device=device), torch.tensor(Y, device=device)
相邻采样
在相邻采样中,相邻的两个随机小批量在原始序列上的位置相毗邻。
def data_iter_consecutive(corpus_indices, batch_size, num_steps, device=None):if device is None:device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')corpus_len = len(corpus_indices) // batch_size * batch_size # 保留下来的序列的长度corpus_indices = corpus_indices[: corpus_len] # 仅保留前corpus_len个字符indices = torch.tensor(corpus_indices, device=device)indices = indices.view(batch_size, -1) # resize成(batch_size, )batch_num = (indices.shape[1] - 1) // num_stepsfor i in range(batch_num):i = i * num_stepsX = indices[:, i: i + num_steps]Y = indices[:, i + 1: i + num_steps + 1]yield X, Y
