深入Bert实战(Pytorch)----WordPiece Embeddings
https://www.bilibili.com/video/BV1K5411t7MD?p=5
https://www.youtube.com/channel/UCoRX98PLOsaN8PtekB9kWrw/videos
深入BERT實(shí)戰(zhàn)(PyTorch) by ChrisMcCormickAI
這是ChrisMcCormickAI在油管bert,8集系列第二篇WordPiece Embeddings的pytorch的講解的代碼,在油管視頻下有下載地址,如果不能翻墻的可以留下郵箱我全部看完整理后發(fā)給你。
文章目錄
- 加載模型
- 查看Bert中的詞匯
- 單字符
- Subwords vs. Whole-words
- 開(kāi)始子詞和中間子詞
- 對(duì)于姓名來(lái)說(shuō)
- 對(duì)于數(shù)字來(lái)說(shuō)
加載模型
安裝huggingface實(shí)現(xiàn)
!pip install pytorch-pretrained-bertimport torch from pytorch_pretrained_bert import BertTokenizer# 加載預(yù)訓(xùn)練模型 tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')查看Bert中的詞匯
檢索整個(gè)“tokens”列表,并將它們寫入文本文件,可以仔細(xì)閱讀它們。
with open("vocabulary.txt", 'w', encoding='utf-8') as f:# For each token... 得到每個(gè)單詞for token in tokenizer.vocab.keys():# Write it out and escape any unicode characters. # 寫并且轉(zhuǎn)義為Unicode字符 f.write(token + '\n')-
打印出來(lái)可以得到
-
前999個(gè)詞序是保留位置,它們的形式類似于[unused957]
-
1 - [PAD] 截?cái)?br /> 101 - [UNK] 未知字符
102 - [CLS] 句首,表示分類任務(wù)
103 - [SEP] BERT中分隔兩個(gè)輸入的句子
104 - [MASK] MASK機(jī)制 -
第1000-1996行似乎是單個(gè)字符的轉(zhuǎn)儲(chǔ)。
-
它們似乎沒(méi)有按頻率排序(例如,字母表中的字母都是按順序排列的)。
-
第一個(gè)單詞是1997位置的The
-
從這里開(kāi)始,這些詞似乎是按頻率排序的。
前18個(gè)單詞是完整的單詞,第2016位是##s,可能是最常見(jiàn)的子單詞。
最后一個(gè)完整單詞是29612位的 “necessitated”
單字符
下面的代碼打印出詞匯表中的所有單字符的token,以及前面帶’##'的所有單字符的token。
結(jié)果發(fā)現(xiàn)這些都是匹配集——每個(gè)獨(dú)立角色都有一個(gè)“##”版本。有997個(gè)單字符標(biāo)記。
下面的單元格遍歷詞匯表,取出所有單個(gè)字符標(biāo)記。
one_chars = [] one_chars_hashes = []# For each token in the vocabulary... 遍歷所有單字符 for token in tokenizer.vocab.keys():# Record any single-character tokens.記錄下來(lái)if len(token) == 1:one_chars.append(token)# Record single-character tokens preceded by the two hashes. # 記錄##單字符 elif len(token) == 3 and token[0:2] == '##':one_chars_hashes.append(token)打印單字符的
print('Number of single character tokens:', len(one_chars), '\n')# Print all of the single characters, 40 per row.# For every batch of 40 tokens... for i in range(0, len(one_chars), 40):# Limit the end index so we don't go past the end of the list.end = min(i + 40, len(one_chars) + 1)# Print out the tokens, separated by a space.print(' '.join(one_chars[i:end]))打印##單字符的
print('Number of single character tokens with hashes:', len(one_chars_hashes), '\n')# Print all of the single characters, 40 per row.按每行40打印# Strip the hash marks, since they just clutter the display.去除## tokens = [token.replace('##', '') for token in one_chars_hashes]# For every batch of 40 tokens...每批40 for i in range(0, len(tokens), 40):# Limit the end index so we don't go past the end of the list.限制結(jié)束位置end = min(i + 40, len(tokens) + 1)# Print out the tokens, separated by a space.print(' '.join(tokens[i:end])) Number of single character tokens: 997 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? ¢ £ ¤ ¥ | § ¨ ? a ? ? ? ° ± 2 3 ′ μ ? · 1 o ? ? ? ? ? × ? ? e ÷ ? t ? ? ? ? ? ? ? ? ɑ ? ? ? ? ? ɡ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ? σ τ υ φ χ ψ ω а б в г д е ж з и к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ‐ ? ? – — ― ‖ ‘ ’ ? “ ” ? ? ? ? … ‰ ′ ″ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? € ? ? ? № ? ? ? ? ← ↑ → ↓ ? ? ? ? ? ? ? ? ? ∈ ? ? ° √ ∞ ∧ ∨ ∩ ∪ ≈ ≡ ≤ ≥ ? ? ⊕ ? ? ─ │ ■ ? ● ★ ☆ ☉ ? ? ? ? ? ? ? ? ? ? ? ? 、 。 〈 〉 《 》 「 」 『 』 ? あ い う え お か き く け こ さ し す せ そ た ち っ つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ を ん ァ ア ィ イ ウ ェ エ オ カ キ ク ケ コ サ シ ス セ タ チ ッ ツ テ ト ナ ニ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ャ ュ ョ ラ リ ル レ ロ ワ ン ? ー 一 三 上 下 不 世 中 主 久 之 也 事 二 五 井 京 人 亻 仁 介 代 仮 伊 會(huì) 佐 侍 保 信 健 元 光 八 公 內(nèi) 出 分 前 劉 力 加 勝 北 區(qū) 十 千 南 博 原 口 古 史 司 合 吉 同 名 和 囗 四 國(guó) 國(guó) 土 地 坂 城 堂 場(chǎng) 士 夏 外 大 天 太 夫 奈 女 子 學(xué) 宀 宇 安 宗 定 宣 宮 家 宿 寺 將 小 尚 山 岡 島 崎 川 州 巿 帝 平 年 幸 廣 弘 張 彳 後 御 德 心 忄 志 忠 愛(ài) 成 我 戦 戸 手 扌 政 文 新 方 日 明 星 春 昭 智 曲 書(shū) 月 有 朝 木 本 李 村 東 松 林 森 楊 樹(shù) 橋 歌 止 正 武 比 氏 民 水 氵 氷 永 江 沢 河 治 法 海 清 漢 瀬 火 版 犬 王 生 田 男 疒 発 白 的 皇 目 相 省 真 石 示 社 神 福 禾 秀 秋 空 立 章 竹 糹 美 義 耳 良 艸 花 英 華 葉 藤 行 街 西 見(jiàn) 訁 語(yǔ) 谷 貝 貴 車 軍 辶 道 郎 郡 部 都 里 野 金 鈴 鎮(zhèn) 長(zhǎng) 門 間 阝 阿 陳 陽(yáng) 雄 青 面 風(fēng) 食 香 馬 高 龍 ? ? ? ! ( ) , - . / : ? ~上面兩段代碼及 ##+單字符 和 單字符 結(jié)果一樣
# return True print('Are the two sets identical?', set(one_chars) == set(tokens))Subwords vs. Whole-words
打印一些詞匯的統(tǒng)計(jì)數(shù)據(jù)。
import matplotlib.pyplot as plt import seaborn as sns import numpy as npsns.set(style='darkgrid')# Increase the plot size and font size. sns.set(font_scale=1.5) plt.rcParams["figure.figsize"] = (10,5)# Measure the length of every token in the vocab. 加載每個(gè)單詞 token_lengths = [len(token) for token in tokenizer.vocab.keys()]# Plot the number of tokens of each length. sns.countplot(token_lengths) plt.title('Vocab Token Lengths') plt.xlabel('Token Length') plt.ylabel('# of Tokens')print('Maximum token length:', max(token_lengths))
統(tǒng)計(jì)一下,’##'開(kāi)頭的tokens。
相對(duì)于完整詞匯表占據(jù)的數(shù)量
vocab_size = len(tokenizer.vocab.keys())print('Number of subwords: {:,} of {:,}'.format(num_subwords, vocab_size))# Calculate the percentage of words that are '##' subwords. prcnt = float(num_subwords) / vocab_size * 100.0print('%.1f%%' % prcnt) Number of subwords: 5,828 of 30,522 19.1%作圖統(tǒng)計(jì)的結(jié)果
sns.countplot(subword_lengths) plt.title('Subword Token Lengths (w/o "##")') plt.xlabel('Subword Length') plt.ylabel('# of ## Subwords')
可以自行查看下錯(cuò)誤拼寫的例子
對(duì)于縮寫來(lái)說(shuō)
"can't" in tokenizer.vocab # False "cant" in tokenizer.vocab # False開(kāi)始子詞和中間子詞
對(duì)于單個(gè)字符,既有單個(gè)字符,也有對(duì)應(yīng)每個(gè)字符的“##”版本。子詞也是如此嗎?
# For each token in the vocabulary... for token in tokenizer.vocab.keys():# If it's a subword...if len(token) >= 2 and token[0:2] == '##':if not token[2:] in tokenizer.vocab:print('Did not find a token for', token[2:])break可以查看到第一個(gè)返回的##ly在詞表中,但是ly不在詞表中
Did not find a token for ly'##ly' in tokenizer.vocab # True 'ly' in tokenizer.vocab # False對(duì)于姓名來(lái)說(shuō)
下載數(shù)據(jù)
!pip install wgetimport wget import random print('Beginning file download with wget module')url = 'http://www.gutenberg.org/files/3201/files/NAMES.TXT' wget.download(url, 'first-names.txt')編碼,小寫化,輸出長(zhǎng)度
# Read them in. with open('first-names.txt', 'rb') as f:names_encoded = f.readlines()names = []# Decode the names, convert to lowercase, and strip newlines. for name in names_encoded:try:names.append(name.rstrip().lower().decode('utf-8'))except:continueprint('Number of names: {:,}'.format(len(names))) print('Example:', random.choice(names))查看有多少個(gè)姓名是在BERT的詞表中
num_names = 0# For each name in our list... for name in names:# If it's in the vocab...if name in tokenizer.vocab:# Tally it.num_names += 1print('{:,} names in the vocabulary'.format(num_names))對(duì)于數(shù)字來(lái)說(shuō)
# Count how many numbers are in the vocabulary. 統(tǒng)計(jì)詞匯表中有多少數(shù)字 count = 0# For each token in the vocabulary... for token in tokenizer.vocab.keys():# Tally if it's a number.if token.isdigit():count += 1# Any numbers >= 10,000?if len(token) > 4:print(token)print('Vocab includes {:,} numbers.'.format(count))計(jì)算一下在1600-2021中有幾個(gè)數(shù)字在
# Count how many dates between 1600 and 2021 are included. count = 0 for i in range(1600, 2021):if str(i) in tokenizer.vocab:count += 1print('Vocab includes {:,} of 421 dates from 1600 - 2021'.format(count))總結(jié)
以上是生活随笔為你收集整理的深入Bert实战(Pytorch)----WordPiece Embeddings的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: this指针详解
- 下一篇: java 调用 delphi_【java