Skip to content

Commit

Permalink
[terminology] (d2l-ai#912)
Browse files Browse the repository at this point in the history
  • Loading branch information
goldmermaid authored Jul 25, 2021
1 parent c93a51c commit 8d365f0
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 48 deletions.
12 changes: 6 additions & 6 deletions chapter_recurrent-neural-networks/language-models-and-dataset.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# 语言模型和数据集
:label:`sec_language_model`

在 :numref:`sec_text_preprocessing` 中,我们了解了如何将文本数据映射为标记,以及这些标记可以被视为一系列离散的观测,例如单词或字符。假设长度为 $T$ 的文本序列中的标记依次为 $x_1, x_2, \ldots, x_T$。于是,$x_t$($1 \leq t \leq T$) 可以被认为是文本序列在时间步 $t$ 处的观测或标签。在给定这样的文本序列时,*语言模型*(language model)的目标是估计序列的联合概率
在 :numref:`sec_text_preprocessing` 中,我们了解了如何将文本数据映射为词元,以及这些词元可以被视为一系列离散的观测,例如单词或字符。假设长度为 $T$ 的文本序列中的词元依次为 $x_1, x_2, \ldots, x_T$。于是,$x_t$($1 \leq t \leq T$) 可以被认为是文本序列在时间步 $t$ 处的观测或标签。在给定这样的文本序列时,*语言模型*(language model)的目标是估计序列的联合概率

$$P(x_1, x_2, \ldots, x_T).$$

语言模型是非常有用的。例如,只需要一次抽取一个标记 $x_t \sim P(x_t \mid x_{t-1}, \ldots, x_1)$,一个理想的语言模型就能够基于模型本身生成自然文本。与猴子使用打字机完全不同的是,从这样的模型中浮现的所有文本都将作为自然语言(例如,英语文本)来传递。此外,只需要基于前面的对话片断中的文本,就足以生成一个有意义的对话。显然,我们离设计出这样的系统还很遥远,因为它需要“理解”文本,而不仅仅是生成在语法上合理的内容。
语言模型是非常有用的。例如,只需要一次抽取一个词元 $x_t \sim P(x_t \mid x_{t-1}, \ldots, x_1)$,一个理想的语言模型就能够基于模型本身生成自然文本。与猴子使用打字机完全不同的是,从这样的模型中浮现的所有文本都将作为自然语言(例如,英语文本)来传递。此外,只需要基于前面的对话片断中的文本,就足以生成一个有意义的对话。显然,我们离设计出这样的系统还很遥远,因为它需要“理解”文本,而不仅仅是生成在语法上合理的内容。

尽管如此,语言模型依然是非常有用的,即使在它们受限的形式下。例如,短语“to recognize speech”和“to wreck a nice beach”听起来非常相似。这种相似性会导致语音识别中的歧义,但是这很容易通过语言模型来解决,因为第二种翻译的感觉很奇怪。同样,在文档摘要生成算法中,“狗咬人”比“人咬狗”出现的频率要高得多,或者“我想吃奶奶”是一个相当令人不安的语句,而“我想吃,奶奶”则要和蔼得多。

## 学习语言模型

显而易见,我们面对的问题是如何对一个文档,甚至是一个标记序列进行建模。假设在单词级别对文本数据进行词元化,我们可以依靠在 :numref:`sec_sequence` 中对序列模型的分析。让我们从基本概率规则开始:
显而易见,我们面对的问题是如何对一个文档,甚至是一个词元序列进行建模。假设在单词级别对文本数据进行词元化,我们可以依靠在 :numref:`sec_sequence` 中对序列模型的分析。让我们从基本概率规则开始:

$$P(x_1, x_2, \ldots, x_T) = \prod_{t=1}^T P(x_t \mid x_1, \ldots, x_{t-1}).$$

Expand Down Expand Up @@ -127,7 +127,7 @@ trigram_vocab = d2l.Vocab(trigram_tokens)
trigram_vocab.token_freqs[:10]
```

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

```{.python .input}
#@tab all
Expand All @@ -144,7 +144,7 @@ d2l.plot([freqs, bigram_freqs, trigram_freqs], xlabel='token: x',

由于序列数据本质上是连续的,因此我们在处理数据时需要解决这个问题。在 :numref:`sec_sequence` 中我们以一种相当特别的方式做到了这一点。当序列变得太长而不能被模型一次性全部处理时,我们可能希望拆分这样的序列方便模型读取。现在让我们描述一下总体策略。在介绍该模型之前,假设我们将使用神经网络来训练语言模型,模型中的网络一次处理具有预定义长度(例如 $n$ 个时间步)的一个小批量序列。现在的问题是如何[**随机地生成一个小批量数据的特征和标签以供读取。**]

首先,由于文本序列可以是任意长的,例如整本《时光机器》(*The Time Machine*),于是任意长的序列可以被我们划分为具有相同时间步数的子序列。当训练我们的神经网络时,这样的小批量子序列将被输入到模型中。假设网络一次只处理具有 $n$ 个时间步的子序列。 :numref:`fig_timemachine_5gram` 画出了从原始文本序列获得子序列的所有不同的方式,其中 $n=5$,并且每个时间步的标记对应于一个字符。请注意,因为我们可以选择任意偏移量来指示初始位置,所以我们有相当大的自由度。
首先,由于文本序列可以是任意长的,例如整本《时光机器》(*The Time Machine*),于是任意长的序列可以被我们划分为具有相同时间步数的子序列。当训练我们的神经网络时,这样的小批量子序列将被输入到模型中。假设网络一次只处理具有 $n$ 个时间步的子序列。 :numref:`fig_timemachine_5gram` 画出了从原始文本序列获得子序列的所有不同的方式,其中 $n=5$,并且每个时间步的词元对应于一个字符。请注意,因为我们可以选择任意偏移量来指示初始位置,所以我们有相当大的自由度。

![分割文本时,不同的偏移量会导致不同的子序列。](../img/timemachine-5gram.svg)
:label:`fig_timemachine_5gram`
Expand All @@ -153,7 +153,7 @@ d2l.plot([freqs, bigram_freqs, trigram_freqs], xlabel='token: x',

### 随机采样

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

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

Expand Down
18 changes: 9 additions & 9 deletions chapter_recurrent-neural-networks/rnn-scratch.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ train_random_iter, vocab_random_iter = d2l.load_data_time_machine(

## [**独热编码**]

回想一下,在 `train_iter` 中,每个标记都表示为一个数字索引。将这些索引直接输入神经网络可能会使学习变得困难。我们通常将每个标记表示为更具表现力的特征向量。最简单的表示称为*独热编码*(one-hot encoding),它在 :numref:`subsec_classification-problem` 中介绍过。
回想一下,在 `train_iter` 中,每个词元都表示为一个数字索引。将这些索引直接输入神经网络可能会使学习变得困难。我们通常将每个词元表示为更具表现力的特征向量。最简单的表示称为*独热编码*(one-hot encoding),它在 :numref:`subsec_classification-problem` 中介绍过。

简言之,将每个索引映射为相互不同的单位向量:假设词汇表中不同标记的数目为$N$(即 `len(vocab)`),标记索引的范围为$0$到$N-1$。如果标记的索引是整数$i$,那么我们创建一个长度为$N$的全$0$向量,并将第$i$处的元素设置为$1$。此向量是原始标记的一个独热向量。索引为$0$和$2$的独热向量如下所示。
简言之,将每个索引映射为相互不同的单位向量:假设词汇表中不同词元的数目为$N$(即 `len(vocab)`),词元索引的范围为$0$到$N-1$。如果词元的索引是整数$i$,那么我们创建一个长度为$N$的全$0$向量,并将第$i$处的元素设置为$1$。此向量是原始词元的一个独热向量。索引为$0$和$2$的独热向量如下所示。

```{.python .input}
npx.one_hot(np.array([0, 2]), len(vocab))
Expand Down Expand Up @@ -458,7 +458,7 @@ def grad_clipping(grads, theta): #@save
def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):
"""训练模型一个迭代周期(定义见第8章)。"""
state, timer = None, d2l.Timer()
metric = d2l.Accumulator(2) # 训练损失之和, 标记数量
metric = d2l.Accumulator(2) # 训练损失之和, 词元数量
for X, Y in train_iter:
if state is None or use_random_iter:
# 在第一次迭代或使用随机抽样时初始化`state`
Expand All @@ -484,7 +484,7 @@ def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):
def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):
"""训练模型一个迭代周期(定义见第8章)。"""
state, timer = None, d2l.Timer()
metric = d2l.Accumulator(2) # 训练损失之和, 标记数量
metric = d2l.Accumulator(2) # 训练损失之和, 词元数量
for X, Y in train_iter:
if state is None or use_random_iter:
# 在第一次迭代或使用随机抽样时初始化`state`
Expand Down Expand Up @@ -521,7 +521,7 @@ def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):
def train_epoch_ch8(net, train_iter, loss, updater, params, use_random_iter):
"""训练模型一个迭代周期(定义见第8章)。"""
state, timer = None, d2l.Timer()
metric = d2l.Accumulator(2) # 训练损失之和, 标记数量
metric = d2l.Accumulator(2) # 训练损失之和, 词元数量
for X, Y in train_iter:
if state is None or use_random_iter:
# 在第一次迭代或使用随机抽样时初始化`state`
Expand Down Expand Up @@ -567,7 +567,7 @@ def train_ch8(net, train_iter, vocab, lr, num_epochs, device, #@save
net, train_iter, loss, updater, device, use_random_iter)
if (epoch + 1) % 10 == 0:
animator.add(epoch + 1, [ppl])
print(f'困惑度 {ppl:.1f}, {speed:.1f} 标记/秒 {str(device)}')
print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
print(predict('time traveller'))
print(predict('traveller'))
```
Expand All @@ -594,7 +594,7 @@ def train_ch8(net, train_iter, vocab, lr, num_epochs, device,
if (epoch + 1) % 10 == 0:
print(predict('time traveller'))
animator.add(epoch + 1, [ppl])
print(f'困惑度 {ppl:.1f}, {speed:.1f} 标记/秒 {str(device)}')
print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
print(predict('time traveller'))
print(predict('traveller'))
```
Expand All @@ -620,12 +620,12 @@ def train_ch8(net, train_iter, vocab, num_hiddens, lr, num_epochs, strategy,
print(predict('time traveller'))
animator.add(epoch + 1, [ppl])
device = d2l.try_gpu()._device_name
print(f'困惑度 {ppl:.1f}, {speed:.1f} 标记/秒 {str(device)}')
print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')
print(predict('time traveller'))
print(predict('traveller'))
```

[**现在,我们训练循环神经网络模型。**]因为我们在数据集中只使用10000个标记,所以模型需要更多的迭代周期来更好地收敛。
[**现在,我们训练循环神经网络模型。**]因为我们在数据集中只使用10000个词元,所以模型需要更多的迭代周期来更好地收敛。

```{.python .input}
#@tab mxnet,pytorch
Expand Down
Loading

0 comments on commit 8d365f0

Please sign in to comment.