提交 33be423b 编写于 作者: W wizardforcel

token => 标记,tokenize => 分词,tokenizer => 分词器

上级 4618de3a
......@@ -207,7 +207,7 @@ NLP的基本路径是我们必须采用句子并将它们转换为数字,并
#### 语言模型标记 [[28:03](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D28m3s)]
接下来我们要做的就是标记化。 标记化意味着在这个阶段,对于文档(即电影评论),我们有一个很长的字符串,我们想把它变成一个标记列表,类似于单词列表但不完全。 例如, `don't`希望它是`do``n't` ,我们可能希望完全停止成为标记,等等。 标记化是我们传递给一个名为spaCy的极好的库 - 部分非常棒,因为澳大利亚人写了它并且部分非常棒,因为它擅长它的功能。 我们在spaCy上添加了一些东西,但绝大部分工作都是由spaCy完成的。
接下来我们要做的就是分词。 分词意味着在这个阶段,对于文档(即电影评论),我们有一个很长的字符串,我们想把它变成一个标记列表,类似于单词列表但不完全。 例如, `don't`希望它是`do``n't` ,我们可能希望完全停止成为标记,等等。 分词是我们传递给一个名为spaCy的极好的库 - 部分非常棒,因为澳大利亚人写了它并且部分非常棒,因为它擅长它的功能。 我们在spaCy上添加了一些东西,但绝大部分工作都是由spaCy完成的。
```
chunksize=24000
......@@ -245,7 +245,7 @@ NLP的基本路径是我们必须采用句子并将它们转换为数字,并
* 在我们包含文本之前,我们在开头定义了“开始流”( `BOS` )标记。 这些特殊的字母串没有什么特别之处 - 它们只是我认为不经常出现在普通文本中的字母。 因此,每个文本都将以`'xbos'`开头 - 为什么? 因为模型通常有助于了解新文本何时开始。 例如,如果它是一种语言模型,我们将把所有文本连接在一起。 因此,知道所有这些文章已经完成并且新的文章已经开始真的很有用,所以我现在可能会忘记它们的一些上下文。
* 同上,文本通常有多个字段,如标题和摘要,然后是主文档。 因此,出于同样的原因,我们在这里得到了这个东西,它让我们在CSV中实际上有多个字段。 所以这个过程的设计非常灵活。 再次在每一个的开头,我们放置一个特殊的“field starts here”标记,后跟从这里开始的字段数量,就像我们拥有的字段一样多。 然后我们对它应用`fixup`
* 然后最重要的是 [[33:54](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D33m54s)] ,我们将它标记化 - 我们通过执行“进程所有多处理”( `proc_all_mp` )来标记它。 标记化速度往往相当缓慢,但我们现在已经在我们的机器中拥有多个内核,而AWS上的一些更好的机器可以拥有数十个内核。 spaCy不太适合多处理,但Jeremy最终想出了如何让它发挥作用。 好消息是它现在全部包含在这一功能中。 因此,你需要传递给该函数的是要标记化的事物列表,该列表的每个部分将在不同的核心上进行标记化。 还有一个名为`partition_by_cores`的函数,它接受一个列表并将其拆分为子列表。 子列表的数量是计算机中的核心数。 在没有多处理的Jeremy机器上,这需要大约一个半小时,并且通过多处理,大约需要2分钟。 所以这是一个非常有用的东西。 随意查看它,并利用它为你自己的东西。 请记住,即使在我们的笔记本电脑中,我们都拥有多个内核,并且Python中很少有东西可以利用它,除非你付出一些努力使其工作。
* 然后最重要的是 [[33:54](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D33m54s)] ,我们将它分词 - 我们通过执行“进程所有多处理”( `proc_all_mp` )来标记它。 分词速度往往相当缓慢,但我们现在已经在我们的机器中拥有多个内核,而AWS上的一些更好的机器可以拥有数十个内核。 spaCy不太适合多处理,但Jeremy最终想出了如何让它发挥作用。 好消息是它现在全部包含在这一功能中。 因此,你需要传递给该函数的是要分词的事物列表,该列表的每个部分将在不同的核心上进行分词。 还有一个名为`partition_by_cores`的函数,它接受一个列表并将其拆分为子列表。 子列表的数量是计算机中的核心数。 在没有多处理的Jeremy机器上,这需要大约一个半小时,并且通过多处理,大约需要2分钟。 所以这是一个非常有用的东西。 随意查看它,并利用它为你自己的东西。 请记住,即使在我们的笔记本电脑中,我们都拥有多个内核,并且Python中很少有东西可以利用它,除非你付出一些努力使其工作。
```
df_trn = pd.read_csv(LM_PATH/'train.csv', header= **None** , chunksize=chunksize) df_val = pd.read_csv(LM_PATH/'test.csv', header= **None** , chunksize=chunksize)
......@@ -263,7 +263,7 @@ NLP的基本路径是我们必须采用句子并将它们转换为数字,并
(LM_PATH/'tmp').mkdir(exist_ok= **True** )
```
这是最后的结果 [[35:42](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D35m42s)] 。 流标记( `xbos` )的开头,字段编号1标记( `xfld 1` )的开头和标记化文本。 你会看到标点符号现在是一个单独的标记。
这是最后的结果 [[35:42](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D35m42s)] 。 流标记( `xbos` )的开头,字段编号1标记( `xfld 1` )的开头和分词文本。 你会看到标点符号现在是一个单独的标记。
`**t_up**``t_up mgm` - MGM最初资本化。 但有趣的是,通常人们要么小写一切,要么就是按原样离开。 现在,如果你保持原样,那么“SCREW YOU”和“screw you”是两组完全不同的标记,必须从头开始学习。 或者如果你将它们全部小写,那么根本就没有区别。 那么你如何解决这个问题,以便你们都能得到“我现在正在发挥作用”的语义影响,但不必学习大喊大叫的版本与正常版本。 因此,我们的想法是提出一个独特的标记来表示接下来的事情都是大写的。 然后我们小写它,所以现在任何曾经是大写的是小写的,然后我们可以学习所有大写的语义含义。
......@@ -275,7 +275,7 @@ NLP的基本路径是我们必须采用句子并将它们转换为数字,并
![](../img/1_avBwSHfjT31_-m28KGf4NA.png)
以这种方式做事的`np.save`是我们现在可以只是`np.save`并将其加载回来 [[37:44](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D37m44s)] 。 我们不必每次重新计算所有这些东西,就像我们倾向于使用torchtext或许多其他库一样。 现在我们已经将它标记化了,接下来我们要做的就是把它变成我们称之为数字化的数字。 我们将它数字化的方式非常简单。
以这种方式做事的`np.save`是我们现在可以只是`np.save`并将其加载回来 [[37:44](https://youtu.be/h5Tz7gZT9Fo%3Ft%3D37m44s)] 。 我们不必每次重新计算所有这些东西,就像我们倾向于使用torchtext或许多其他库一样。 现在我们已经将它分词了,接下来我们要做的就是把它变成我们称之为数字化的数字。 我们将它数字化的方式非常简单。
* 我们列出了以某种顺序出现的所有单词的列表
* 然后我们将每个单词的索引替换为该列表
......@@ -988,7 +988,7 @@ Jeremy:“你还不能写一篇关于这个的论文,因为你必须做类
#### 技巧#3:IMDb脚本 [[2:02:47]( data-href=)]
你会在里面找到`courses/dl2`,现在有一些叫做的东西`imdb_scripts`,我把塞巴斯蒂安和我用过的所有脚本都放了。因为我们需要对每个数据集进行标记化和数字化,然后为每个数据集训练语言模型和分类器。我们必须以各种不同的方式做所有这些事情来比较它们,所以我们有所有这些事情的脚本。你可以查看并查看我们使用的所有脚本。
你会在里面找到`courses/dl2`,现在有一些叫做的东西`imdb_scripts`,我把塞巴斯蒂安和我用过的所有脚本都放了。因为我们需要对每个数据集进行分词和数字化,然后为每个数据集训练语言模型和分类器。我们必须以各种不同的方式做所有这些事情来比较它们,所以我们有所有这些事情的脚本。你可以查看并查看我们使用的所有脚本。
![](../img/1_4wNUZhHpjSgRLj6s6ECddQ.png)![](../img/1_SkRiJH47FdHtubjyUeYdLA.png)
......@@ -1000,7 +1000,7 @@ Jeremy:“你还不能写一篇关于这个的论文,因为你必须做类
#### 技巧#5:SentencePiece [[2:05:06]( data-href=)]
如果你愿意,这是你可以尝试的。你不必进行标记化。你可以将所谓的子词单元标记​​化,而不是标记单词。例如,“无监督”可以被标记为“un”和“supervised”。 “Tokenizer”可以被标记为[“token”,“izer”]。然后你可以做同样的事情。适用于子单词单元的语言模型,适用于子单词单元的分类器等。这有效吗?我开始玩它并且没有太多的游戏,我得到的分类结果几乎与使用字级标记化一样好 - 不太好,但几乎一样好。我怀疑经过更仔细的思考和玩耍,也许我可以变得更好或更好。但即使我不能,如果你创建一个子字单元wiki文本模型,那么IMDb语言模型,然后分类器向前和向后,然后将它与向前和向后的单词级别合并,你应该能够击败我们。所以这里有一种方法可以击败我们最先进的结果。
如果你愿意,这是你可以尝试的。你不必进行分词。你可以将所谓的子词单元标记​​化,而不是标记单词。例如,“无监督”可以被标记为“un”和“supervised”。 “Tokenizer”可以被标记为[“token”,“izer”]。然后你可以做同样的事情。适用于子单词单元的语言模型,适用于子单词单元的分类器等。这有效吗?我开始玩它并且没有太多的游戏,我得到的分类结果几乎与使用字级分词一样好 - 不太好,但几乎一样好。我怀疑经过更仔细的思考和玩耍,也许我可以变得更好或更好。但即使我不能,如果你创建一个子字单元wiki文本模型,那么IMDb语言模型,然后分类器向前和向后,然后将它与向前和向后的单词级别合并,你应该能够击败我们。所以这里有一种方法可以击败我们最先进的结果。
![](../img/1_Ihivmbwld8tPdMracJ-FuQ.png)
......
......@@ -149,7 +149,7 @@
en_qs,fr_qs = zip(*qs)
```
然后我们将英语问题标记出来并将法语问题标记化。 所以请记住,只是意味着将它们分成单独的单词或类似单词的东西。 默认情况下 [[25:11](https://youtu.be/tY0n9OT5_nA%3Ft%3D25m11s)] ,我们在这里使用的标记器(记住这是一个围绕spaCy标记器的包装器,这是一个很棒的标记器)假设是英文。 所以要求法语,你只需添加一个额外的参数`'fr'` 。 第一次执行此操作时,你将收到一条错误消息,指出你没有安装spaCy French模型,因此你可以运行`python -m spacy download fr`来获取法语模型。
然后我们将英语问题标记出来并将法语问题分词。 所以请记住,只是意味着将它们分成单独的单词或类似单词的东西。 默认情况下 [[25:11](https://youtu.be/tY0n9OT5_nA%3Ft%3D25m11s)] ,我们在这里使用的分词器(记住这是一个围绕spaCy分词器的包装器,这是一个很棒的分词器)假设是英文。 所以要求法语,你只需添加一个额外的参数`'fr'` 。 第一次执行此操作时,你将收到一条错误消息,指出你没有安装spaCy French模型,因此你可以运行`python -m spacy download fr`来获取法语模型。
```
en_tok = Tokenizer.proc_all_mp(partition_by_cores(en_qs))
......@@ -167,7 +167,7 @@
![](../img/1_9_D6dkXM4mR8fPf0E2eLcg.png)
将英语和法语标记化后,你可以看到它如何分裂 [[28:04](https://youtu.be/tY0n9OT5_nA%3Ft%3D28m4s)] :
将英语和法语分词后,你可以看到它如何分裂 [[28:04](https://youtu.be/tY0n9OT5_nA%3Ft%3D28m4s)] :
```
en_tok[0], fr_tok[0]
......@@ -177,7 +177,7 @@
(['what', 'is', 'light', '?'], ['qu'', 'est', '-ce', 'que', 'la', 'lumière', '?'])
```
你可以看到法语的标记化看起来完全不同,因为法国人喜欢他们的撇号和连字符。 因此,如果你尝试使用英语标记符来表示法语句子,那么你将获得非常糟糕的结果。 你不需要知道大量的NLP思想来使用NLP的深度学习,但只是为你的语言使用正确的标记化器这些基本的东西很重要 [[28:23](https://youtu.be/tY0n9OT5_nA%3Ft%3D28m23s)] 。 本周我们学习小组的一些学生一直在尝试为中文实例建立语言模型,当然这些模型并没有真正具有标记器的概念,所以我们一直在开始研究[句子](https://github.com/google/sentencepiece) 。将事物分成任意子字单元,所以当Jeremy说标记化时,如果你使用的语言没有空格,你可能应该检查句子或其他类似的子词单位。 希望在接下来的一两周内,我们将能够用中文报​​告这些实验的早期结果。
你可以看到法语的分词看起来完全不同,因为法国人喜欢他们的撇号和连字符。 因此,如果你尝试使用英语标记符来表示法语句子,那么你将获得非常糟糕的结果。 你不需要知道大量的NLP思想来使用NLP的深度学习,但只是为你的语言使用正确的分词器这些基本的东西很重要 [[28:23](https://youtu.be/tY0n9OT5_nA%3Ft%3D28m23s)] 。 本周我们学习小组的一些学生一直在尝试为中文实例建立语言模型,当然这些模型并没有真正具有分词器的概念,所以我们一直在开始研究[句子](https://github.com/google/sentencepiece) 。将事物分成任意子字单元,所以当Jeremy说分词时,如果你使用的语言没有空格,你可能应该检查句子或其他类似的子词单位。 希望在接下来的一两周内,我们将能够用中文报​​告这些实验的早期结果。
```
np.percentile([len(o) **for** o **in** en_tok], 90), np.percentile([len(o) **for** o **in** fr_tok], 90)
......@@ -203,7 +203,7 @@
en_tok = pickle.load((PATH/'en_tok.pkl').open('rb')) fr_tok = pickle.load((PATH/'fr_tok.pkl').open('rb'))
```
因此将其标记化 [[29:25](https://youtu.be/tY0n9OT5_nA%3Ft%3D29m25s)] ,我们将其保存到磁盘。 然后记住,我们创建标记后的下一步是将它们变成数字。 要做到这一点,我们有两个步骤 - 第一步是获取所有出现的单词的列表,然后我们将每个单词转换为索引。 如果出现超过40,000个单词,那么让我们将其剪掉,这样就不会太疯狂了。 我们为流( `_bos_` ),填充( `_pad_` ),流尾( `_eos_` )和未知( `_unk` )的开头插入了一些额外的标记。 因此,如果我们试图查找不在40,000最常见的东西,那么我们使用`deraultdict`返回3,这是未知的。
因此将其分词 [[29:25](https://youtu.be/tY0n9OT5_nA%3Ft%3D29m25s)] ,我们将其保存到磁盘。 然后记住,我们创建标记后的下一步是将它们变成数字。 要做到这一点,我们有两个步骤 - 第一步是获取所有出现的单词的列表,然后我们将每个单词转换为索引。 如果出现超过40,000个单词,那么让我们将其剪掉,这样就不会太疯狂了。 我们为流( `_bos_` ),填充( `_pad_` ),流尾( `_eos_` )和未知( `_unk` )的开头插入了一些额外的标记。 因此,如果我们试图查找不在40,000最常见的东西,那么我们使用`deraultdict`返回3,这是未知的。
```
**def** toks2ids(tok,pre): freq = Counter(p **for** o **in** tok **for** p **in** o) itos = [o **for** o,c **in** freq.most_common(40000)] itos.insert(0, '_bos_') itos.insert(1, '_pad_') itos.insert(2, '_eos_') itos.insert(3, '_unk') stoi = collections.defaultdict( **lambda** : 3, {v:k **for** k,v **in** enumerate(itos)}) ids = np.array([([stoi[o] **for** o **in** p] + [2]) **for** p **in** tok]) np.save(TMP_PATH/f' **{pre}** _ids.npy', ids) pickle.dump(itos, open(TMP_PATH/f' **{pre}** _itos.pkl', 'wb')) **return** ids,itos,stoi
......@@ -211,7 +211,7 @@
现在我们可以继续将每个标记转换为ID,方法是将它通过字符串`stoi`我们刚刚创建的整数字典( `stoi` )中,然后在结尾处添加数字2,这是流的结尾。 你在这里看到的代码是Jeremy在迭代和试验时写的代码 [[30:25](https://youtu.be/tY0n9OT5_nA%3Ft%3D30m25s)] 。 因为他在迭代和实验时编写的代码中有99%证明是完全错误或愚蠢或令人尴尬,而你却无法看到它。 但是,当他写这篇文章时,没有点重构并使它变得美丽,所以他希望你能看到他所拥有的所有小捷径。 而不是为`_eos_`标记使用一些常量并使用它,当他进行原型设计时,他只是做了简单的事情。 并非如此,他最终会破坏代码,但他试图在美丽的代码和有效的代码之间找到一些中间立场。
**问** :刚听到他提到我们将CPU的数量除以2,因为使用超线程,我们无法使用所有超线程内核加速。 这是基于实际经验还是有一些潜在的原因导致我们不能获得额外的加速 [[31:18](https://youtu.be/tY0n9OT5_nA%3Ft%3D31m18s)] ? 是的,这只是实际经验而且并非所有事情都像这样,但我确实注意到了标记化 - 超线程似乎让事情变得缓慢。 此外,如果我使用所有内核,通常我想同时做其他事情(比如运行一些交互式笔记本),我没有任何空余的空间来做这件事。
**问** :刚听到他提到我们将CPU的数量除以2,因为使用超线程,我们无法使用所有超线程内核加速。 这是基于实际经验还是有一些潜在的原因导致我们不能获得额外的加速 [[31:18](https://youtu.be/tY0n9OT5_nA%3Ft%3D31m18s)] ? 是的,这只是实际经验而且并非所有事情都像这样,但我确实注意到了分词 - 超线程似乎让事情变得缓慢。 此外,如果我使用所有内核,通常我想同时做其他事情(比如运行一些交互式笔记本),我没有任何空余的空间来做这件事。
现在我们的英语和法语,我们可以获取ID列表`en_ids` [[32:01](https://youtu.be/tY0n9OT5_nA%3Ft%3D32m1s)] 。 当我们这样做时,当然,我们需要确保我们也存储词汇。 如果我们不知道数字5代表什么是没有任何意义,那就没有数字5.这就是我们的词汇表`en_itos`和反向映射`en_stoi` ,我们可以用来转换未来更多的语料库。
......@@ -315,7 +315,7 @@ pytext中没有fasttext Python库,但这是一个方便的技巧 [[35:03](http
_(29, 33)_
```
我们[快到](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m24s)[[37:24](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m24s)] 。 我们已经获得了我们的标记化,数字化的英语和法语数据集。 我们有一些单词向量。 所以现在我们需要为PyTorch做好准备。 PyTorch需要一个`Dataset`对象,希望现在可以说数据集对象需要两个东西 - 长度( `__len__` )和索引器( `__getitem__` )。 Jeremy开始编写`Seq2SeqDataset` ,结果证明它只是一个通用的`Dataset` [[37:52](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m52s)] 。
我们[快到](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m24s)[[37:24](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m24s)] 。 我们已经获得了我们的分词,数字化的英语和法语数据集。 我们有一些单词向量。 所以现在我们需要为PyTorch做好准备。 PyTorch需要一个`Dataset`对象,希望现在可以说数据集对象需要两个东西 - 长度( `__len__` )和索引器( `__getitem__` )。 Jeremy开始编写`Seq2SeqDataset` ,结果证明它只是一个通用的`Dataset` [[37:52](https://youtu.be/tY0n9OT5_nA%3Ft%3D37m52s)] 。
```
en_ids_tr = np.array([o[:enlen_90] **for** o **in** en_ids]) fr_ids_tr = np.array([o[:frlen_90] **for** o **in** fr_ids])
......
......@@ -573,7 +573,7 @@ IMDB [大型电影评论数据集](http://ai.stanford.edu/~amaas/data/sentiment/
_5686719_
```
在我们可以对文本执行任何操作之前,我们必须将其转换为标记列表。 标记基本上就像一个单词。 最终我们将它们变成一个数字列表,但第一步是将它变成一个单词列表 - 这在NLP中称为“标记化”。 一个好的标记器可以很好地识别句子中的碎片。 每个分隔的标点符号将被分开,并且多部分单词的每个部分将被适当地分开。 Spacy做了很多NLP的东西,它拥有Jeremy所知道的最好的标记器。 因此,Fast.ai库可以与Spacech tokenizer一起使用,就像使用torchtext一样。
在我们可以对文本执行任何操作之前,我们必须将其转换为标记列表。 标记基本上就像一个单词。 最终我们将它们变成一个数字列表,但第一步是将它变成一个单词列表 - 这在NLP中称为“分词”。 一个好的分词器可以很好地识别句子中的碎片。 每个分隔的标点符号将被分开,并且多部分单词的每个部分将被适当地分开。 Spacy做了很多NLP的东西,它拥有Jeremy所知道的最好的分词器。 因此,Fast.ai库可以与Spacech tokenizer一起使用,就像使用torchtext一样。
#### 创建一个领域 [[01:41:01](https://youtu.be/gbceqO8PpBg?t=1h41m1s)]
......@@ -639,7 +639,7 @@ IMDB [大型电影评论数据集](http://ai.stanford.edu/~amaas/data/sentiment/
_Variable containing:_ _12_ _35_ _227_ _480_ _13_ _76_ _17_ _2_ _7319_ _769_ _3_ _2_ _[torch.cuda.LongTensor of size 12x1 (GPU 0)]_
```
**问题** :做任何词干或引理调整是否常见? [[01:45:47](https://youtu.be/gbceqO8PpBg?t=1h45m47s)] 不是,不。 通常,标记化是我们想要的。 为了保持尽可能通用,我们想知道接下来会发生什么,所以无论是将来时态还是过去时,复数还是单数,我们都不知道哪些东西会有趣,哪些不是,所以它似乎通常最好尽量不让它。
**问题** :做任何词干或引理调整是否常见? [[01:45:47](https://youtu.be/gbceqO8PpBg?t=1h45m47s)] 不是,不。 通常,分词是我们想要的。 为了保持尽可能通用,我们想知道接下来会发生什么,所以无论是将来时态还是过去时,复数还是单数,我们都不知道哪些东西会有趣,哪些不是,所以它似乎通常最好尽量不让它。
**问题** :处理自然语言时,上下文不重要吗? 我们为什么要对单词进行标记和查看? [[01:46:38](https://youtu.be/gbceqO8PpBg?t=1h46m38s)] 不,我们不是在看单个词 - 它们仍然是有序的。 仅仅因为我们用12号替换了我,他们仍然按照这个顺序。 处理称为“词袋”的自然语言有一种不同的方式,它们会丢弃秩序和背景。 在机器学习课程中,我们将学习如何使用词语表示,但我相信它们不再有用或者不再有用。 我们开始学习如何使用深度学习来正确使用上下文。
......@@ -825,7 +825,7 @@ Fast.ai使用由Stephen Merity开发的最先进的[AWD LSTM语言模型](https:
TEXT = pickle.load(open(f' **{PATH}** models/TEXT.pkl','rb'))
```
`sequential=False`告诉torchtext文本字段应该被标记化(在这种情况下,我们只想存储'正'或'负'单个标签)。
`sequential=False`告诉torchtext文本字段应该被分词(在这种情况下,我们只想存储'正'或'负'单个标签)。
```
IMDB_LABEL = data.Field(sequential= **False** )
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册