0


Torchtext快速入门(一)——Vocab

🧑‍💻 本系列文章采用 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

方法源码如下:

defupdate(self, iterable=None,/,**kwds):if iterable isnotNone:ifisinstance(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 emptysuper().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

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

defyield_tokens(path):withopen(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)# Trueprint('k'in v)# False

附录

vocab

函数源码:

defvocab(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 tokensfor 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

函数源码:

defbuild_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 isNone:
        ordered_dict = OrderedDict(sorted_by_freq_tuples)else:assertlen(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

本文转载自: https://blog.csdn.net/raelum/article/details/127355349
版权归原作者 Iareges 所有, 如有侵权,请联系我们删除。

“Torchtext快速入门(一)——Vocab”的评论:

还没有评论