首页IT科技torchtext教程(Torchtext快速入门(一)——Vocab)

torchtext教程(Torchtext快速入门(一)——Vocab)

时间2025-05-03 00:45:54分类IT科技浏览5699
导读:🧑‍💻 本系列文章采用 Torchtext 0.13.1 版本...

🧑‍💻 本系列文章采用 Torchtext 0.13.1 版本

前言

词典(Vocab)是NLP任务中最为重要的工具之一             ,本文将详细介绍Torchtext中的词典类及其使用方法              。

安装Torchtext:

conda install -c pytorch torchtext

导入本文所需要的所有包:

from collections import Counter, OrderedDict from torchtext.vocab import vocab, build_vocab_from_iterator

一             、创建词典

Torchtext中创建词典有两种方法                    ,第一种是根据有序字典(OrderedDict)进行创建        ,第二种是根据生成器(Generator)/可迭代对象(Iterable)进行创建                     。

1.1 根据有序字典进行创建

NLP任务中          ,绝大多数时候 tokens 是一个二维列表                   ,即 tokens[0] 代表一个句子            ,tokens[0][0] 代表一个词元(单词)      。为了使用 Counter() 统计词频       ,我们需要先将 tokens 展平成一维列表(事实上展平成一维的可迭代对象即可)                  ,最常用的方法如下:

from tkinter import _flatten tokens = _flatten(tokens) # 这里tokens是一个一维元组               ,是可迭代对象

如果 tokens 本身就是个一维列表    ,则 _flatten(tokens) 仍然会返回一维元组                   ,因此我们可以总是使用 _flatten(tokens)          。

之后我们可以对这个一维可迭代对象使用 Counter() 统计词频                  ,并将其从高到低进行过排序

>>> tokens = [["I", "am", "very", "happy"], ["I", "seem", "to", "have", "lost", "something"]] >>> sorted(Counter(_flatten(tokens)).items(), key=lambda x: x[1], reverse=True) [(I, 2), (am, 1), (very, 1), (happy, 1), (seem, 1), (to, 1), (have, 1), (lost, 1), (something, 1)]

可以看出输出结果是形如 List[Tuple[str, int]] 这样的类型,我们可以根据此结果来构造有序字典

tokens = [["I", "am", "very", "happy"], ["I", "seem", "to", "have", "lost", "something"]] ordered_dict = OrderedDict(sorted(Counter(_flatten(tokens)).items(), key=lambda x: x[1], reverse=True)) print(ordered_dict) # OrderedDict([(I, 2), (am, 1), (very, 1), (happy, 1), (seem, 1), (to, 1), (have, 1), (lost, 1), (something, 1)])

然后基于有序字典创建词典

v = vocab(ordered_dict) print(type(v)) # <class torchtext.vocab.vocab.Vocab>

⚠️ 这里的 vocab() 是一个函数                ,创建得到的 v 是 Vocab 类的实例                      。第二章节我们会详细介绍 Vocab 类的用法         。

我们还可以向 vocab() 函数传入其他参数      。例如如果一词元的出现次数低于 2 就丢弃                     ,则可设置

v = vocab(ordered_dict, min_freq=2)

在NMT(机器翻译)任务中    ,我们往往需要一些特殊词元             ,这时可以使用 specials 参数进行指定

v = vocab(ordered_dict, min_freq=2, specials=[<pad>, <unk>, <bos>, <eos>])

此时这些特殊词元会被添加到词表的最上方                      。如果需要将特殊词元添加到词表的最下方                    ,则可指定

v = vocab(ordered_dict, min_freq=2, specials=[<pad>, <unk>, <bos>, <eos>], special_first=False)

1.2 根据可迭代对象进行创建

根据可迭代对象创建词典需要用到以下函数

build_vocab_from_iterator(iterator: Iterable, min_freq: int = 1, specials: Optional[List[str]] = None, special_first: bool = True, max_tokens: Optional[int] = None)

接下来重点讲解第一个和最后一个参数            。

首先 iterator 是一个可迭代对象        ,观察 build_vocab_from_iterator 源码的 9~11 行可知(见本文附录)          ,Counter 的实例每次会 update iterator 中的一个元素                   ,而 Counter 的 update 方法源码如下:

def update(self, iterable=None, /, **kwds): if iterable is not None: if isinstance(iterable, _collections_abc.Mapping): if self: self_get = self.get for elem, count in iterable.items(): self[elem] = count + self_get(elem, 0) else: # fast path when counter is empty super().update(iterable) else: _count_elements(self, iterable) if kwds: self.update(kwds)

这说明 iterator 中的每一个元素仍是一个可迭代对象            ,所以我们可以直接向 iterator 传入二维列表 tokens       ,如下:

tokens = [["I", "am", "very", "happy"], ["I", "seem", "to", "have", "lost", "something"]] v = build_vocab_from_iterator(tokens) print(v.get_stoi()) # {to: 7, seem: 5, very: 8, something: 6, lost: 4, have: 3, happy: 2, am: 1, I: 0}

我们还可以指定词典的大小(算上特殊词元的大小)

v = build_vocab_from_iterator(tokens, max_tokens=3) print(v.get_stoi()) # {happy: 2, am: 1, I: 0}

⚠️ max_tokens 不能小于特殊词元的数量                  ,否则词典中将只含特殊词元   。

1.2.1 从生成器中创建

假如 ./data.txt 中的内容为

I am very happy I seem to have lost something

则我们可以构造一个生成器               ,然后使用它来创建词典                      。

def yield_tokens(path): with open(path) as f: for line in f.readlines(): yield line.strip().split() v = build_vocab_from_iterator(yield_tokens("./data.txt"))

二                    、Vocab的用法

无论使用 vocab() 函数还是 build_vocab_from_iterator() 函数    ,返回的结果都是一个 Vocab 实例                。

2.1 获取词元到索引的映射/索引到词元的映射

获取词元到索引到映射(字典)

tokens = [[a, a, b], [c, c, d, d, d]] v = build_vocab_from_iterator(tokens, specials=[<pad>, <unk>]) print(v.get_stoi()) # {b: 5, d: 2, <pad>: 0, <unk>: 1, c: 4, a: 3}

获取索引到词元的映射(列表)

print(v.get_itos()) # [<pad>, <unk>, d, a, c, b]

2.2 正/反向查询

2.2.1 根据词元查询索引

根据单个词元查询其索引

print(v[a]) # 3

根据多个词元查询它们对应的索引(常用

print(v([c, d, <unk>])) # [4, 2, 1]

2.2.2 根据索引查询词元

根据单个索引查询其词元

print(v.lookup_token(4)) # c

根据多个索引查询它们对应的词元

print(v.lookup_tokens([0, 5, 2])) # [<pad>, b, d]

2.3 设置默认索引

在实际应用中                   ,我们难免会遇到OOV(Out Of Vocabulary)词元                  ,这时如果直接查询其索引会报错

print(v[f]) # RuntimeError: Token f not found and default index is not set

因此我们需要设置一个默认索引,所有OOV词元都会被映射到该索引上。通常来讲                ,我们会将默认索引设置为未知词元的索引                     ,即

v.set_default_index(v[<unk>]) print(v[f]) # 1

如果要获取默认索引    ,可调用 get_default_index() 方法                  。

2.4 添加词元

如果一个词元不在词典当中             ,我们可以将其追加到词典的末尾

v.append_token(e) print(v.get_stoi()) # {b: 5, d: 2, <pad>: 0, <unk>: 1, e: 6, c: 4, a: 3}

除了追加到末尾之外                    ,我们还可以在词典中的任意位置插入新词元        ,此时需要同时提供词元和索引

v.insert_token(e, 3) print(v.get_stoi()) # {b: 6, c: 5, e: 3, d: 2, <pad>: 0, <unk>: 1, a: 4}

2.5 其他用法

获取词典大小

print(len(v)) # 6

判断词元是否在词典当中

print(c in v) # True print(k in v) # False

附录

vocab 函数源码:

def vocab(ordered_dict: Dict, min_freq: int = 1, specials: Optional[List[str]] = None, special_first: bool = True ) -> Vocab: specials = specials or [] for token in specials: ordered_dict.pop(token, None) tokens = [] # Save room for special tokens for token, freq in ordered_dict.items(): if freq >= min_freq: tokens.append(token) if special_first: tokens[0:0] = specials else: tokens.extend(specials) return Vocab(VocabPybind(tokens, None)) # 这里的VocabPybind是C++对象

build_vocab_from_iterator 函数源码:

def build_vocab_from_iterator( iterator: Iterable, min_freq: int = 1, specials: Optional[List[str]] = None, special_first: bool = True, max_tokens: Optional[int] = None, ) -> Vocab: counter = Counter() for tokens in iterator: counter.update(tokens) specials = specials or [] # First sort by descending frequency, then lexicographically sorted_by_freq_tuples = sorted(counter.items(), key=lambda x: (-x[1], x[0])) if max_tokens is None: ordered_dict = OrderedDict(sorted_by_freq_tuples) else: assert len(specials) < max_tokens, "len(specials) >= max_tokens, so the vocab will be entirely special tokens." ordered_dict = OrderedDict(sorted_by_freq_tuples[:max_tokens - len(specials)]) word_vocab = vocab(ordered_dict, min_freq=min_freq, specials=specials, special_first=special_first) return word_vocab
声明:本站所有文章          ,如无特殊说明或标注                   ,均为本站原创发布                    。任何个人或组织            ,在未征得本站同意时       ,禁止复制        、盗用          、采集                   、发布本站内容到任何网站            、书籍等各类媒体平台   。如若本站内容侵犯了原著者的合法权益                  ,可联系我们进行处理              。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python中if else语句一行(python装饰器如何保留原函数信息) chatGPT5参数规模(Chat GPT5如果问世会对世界产生什么影响?以及未来chat gpt 5会取代什么类型的工作。)