友情提示:由于HuggingFace社区触犯了天朝的某些法律,有关HuggingFace系列的内容中,提到“冲浪板”就指科学上网,需要借助国外旅游工具。
加载编码工具
下面这段代码加载了一个名为”bert-base-chinese”的中文编码工具。
1 | from transformers import BertTokenizer |
注意:如果是第一次使用,那么需要先下载,下载时需要借助冲浪板。后续再使用时可以不使用冲浪板,也可以使用。如果不使用,可能会出现下面这些输出,但是不影响使用。
1 | '(MaxRetryError("HTTPSConnectionPool(host='huggingface.co', port=443): Max retries exceeded with url: /bert-base-chinese/resolve/main/tokenizer_config.json (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000002677A291C10>, 'Connection to huggingface.co timed out. (connect timeout=10)'))"), '(Request ID: fe978ef6-5237-46ce-b0bb-fb6e0290fe6f)')' thrown while requesting HEAD https://huggingface.co/bert-base-chinese/resolve/main/tokenizer_config.json |
准备数据
现在准备一些中文的句子。
1 | sents = ['你站在桥上看风景', |
编码函数
有了编码工具和数据以后就可以使用编码函数对数据进行编码。
基本的编码函数
这是最简单的编码函数。虽说是最简单的编码工具,但也是一堆的参数。
1 | #调用encode函数。 |
1 | [101, 872, 4991, 1762, 3441, 677, 4692, 7599, 3250, 102, 4692, 7599, 3250, 4638, 782, 1762, 3517, 677, 4692, 872, 102, 0, 0, 0, 0] |
解释:
输出的第一行就是中文数据转为数字后的结果,因为在使用编码函数的时候没有指定返回类型,所以这里默认返回了列表,实际使用时可能会返回张量。中文文字一共是18个,而列表的长度是25。这其中补充了’[CLS]’(表示句子开头)’[SEP]’(句子分隔符)’[PAD]’(补足长度)。
输出的第二行是解码,就是把数字再转为文本。
进阶编码函数
这是一个稍微复杂一些的编码函数。
1 | out = tokenizer.encode_plus( |
1 | input_ids : [101, 872, 4991, 1762, 3441, 677, 4692, 7599, 3250, 102, 4692, 7599, 3250, 4638, 782, 1762, 3517, 677, 4692, 872, 102, 0, 0, 0, 0] |
解释:
input_ids:中文文本编码后的结果。
token_type_ids:在编码函数中给了两个编码句子,这里的0和1分别指该处的文字属于第1个句子或第2个句子。具体的,1代表第二个句子,其余均为0。
special_tokens_mask:标注句子中的特殊符号,1代表特殊符号,其余均为0。
attention_mask:标注句子中的补足符号[PAD],1代表[PAD],其余均为0。
length:编码后的长度。
批量编码函数
可以一次性编码多个句子的函数。
1 | out = tokenizer.batch_encode_plus( |
1 | {'input_ids': [[101, 872, 4991, 1762, 3441, 677, 4692, 7599, 3250, 102, 4692, 7599, 3250, 4638, 782, 1762, 3517, 677, 4692, 872, 102, 0, 0, 0, 0], [101, 3209, 3299, 6163, 7652, 749, 872, 4638, 4970, 2094, 102, 872, 6163, 7652, 749, 1166, 782, 4638, 3457, 102, 0, 0, 0, 0, 0]], 'length': [21, 20]} |
可以看到input_ids中包含的两个列表,分别是两组句子编码后的结果。可以查看一下解码的结果。
1 | tokenizer.decode(out['input_ids'][0]) |
1 | '[CLS] 你 站 在 桥 上 看 风 景 [SEP] 看 风 景 的 人 在 楼 上 看 你 [SEP] [PAD] [PAD] [PAD] [PAD]' |
注意:
batch_text_or_text_pairs=[(sents[0],sents[1]),(sents[2],sents[3])]
在这个参数中,给定的是一个列表,列表中包含了文本。如果是成对的文本要带上括号用元组打包起来,并且一个元组只能打包最多两个文本。列表中可以同时含有成对的文本和单个文本。
编码工具的成分
虽然我们通过编码函数可以轻松地得到文本编码后的结果,也可以轻松地将数字解码成文本,但还不清楚编码工具都包含了什么。
字典
1 | vocab = tokenizer.get_vocab() |
1 | <class 'dict'> |
这是一个获取字典的方法,可以看到vocab的类型就是字典,长度是21128,也就是说包含了21128个汉字及其对应的编码。同时也就是说,它只认识单个的汉字,多个字组成的词就不认识了。
1 | vocab['你'],vocab['我'],vocab['[CLS]'],vocab['氟'],vocab[','],vocab[','] |
1 | (872, 2769, 101, 3703, 8024, 117) |
查找某个字或符号的方法就是像用字典一样。最后两个符号是不一样的,第一个是中文逗号,第二个是英文逗号,可以看到它们的编码也不一样。
不过,对于某些生僻字,字典中没有收录。
1 | vocab['燚'] #念yi,第四声。 |
1 | Traceback (most recent call last): |
向字典中添加内容
原先的字典虽然收录了两万多个汉字,但是它不认识词语和一些生僻字。我们可以手动添加这些内容。
1 | '明月' in vocab |
1 | False |
添加时tokenizer.add_tokens()会返回成功添加的数量,添加完成之后需要重新获取一下字典。如果需要添加的内容本来就存在于字典中,那么就不会添加。
在编码结果和解码结果里,可以看出编码工具已经可以识别词语了。