#はじめに
Transformerを前回までで整理したので、BERTに挑戦してみました。理論ベースだけになりますが絵や図を使いながら整理してみたので、一読いただき何か参考になる事があれば「ストック」「LGTM」をいただけると今後の励みになります!
#過去分
過去分はコチラ↓
①【Source Target Attention】
「Attentionを理解するためにRNN、Word2Vec、LSTM、Seq2Seq、Attentionの順に整理してみた」
https://qiita.com/ta2bonn/items/c645ecbcf9dabd0c4778
②【Self Attention】
「Self-Attention(+MultiHead)を図・ベクトル(行列)の両方で整理してみた。 」
https://qiita.com/ta2bonn/items/60601d18db57bd98d142
③【Transformer】
「Attention Is All You Need = Transformerをざっくり理解してみる。」
https://qiita.com/ta2bonn/items/4ec687bc136a41c364ae
#参考元
論文だけでは理解が難しかったので、各種サイトを参考にさせていただきました。
主な参考元を纏めて記載いたします。(画像等の使用箇所でも改めて記載します)
【BERT論文】
https://arxiv.org/pdf/1810.04805v2.pdf
【Mask_LM】
https://towardsdatascience.com/bert-explained-state-of-the-art-language-model-for-nlp-f8b21a9b6270
【fully-connected layer】
https://medium.com/@tecokids.monastir/fully-connected-layer-with-dynamic-input-shape-70c869ae71af
【GELU】
https://mc.ai/gelu-gaussian-error-linear-unit/
【BERT入出力メソッド】
https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part3.html
【BERTタスク(GLUE)】
https://ai-scholar.tech/articles/text-mining/bert-ai-93
#BERT全体像
##概要
論文の正式名称は「Pre-training of Deep Bidirectional Transformers for Language Understanding」です。つまり、BERTは事前学習モデルで予測モデルではなく、encoder、decoderの仕組みで言うと「encoder」に該当します。
事前学習モデルなので、タスクを「Pre-Training」と「Fine-Tuning」の二つに分けてあります 。
仕掛けとしては、文章の双方向でTransformerを活用して、文脈を理解させる。というものです。
##提示モデルの種類
BERT論文では以下二つのモデルを提示してあります。
・BASEモデル(L=12,H=768,A=12,Total Parameters=110M)
・LARGEモデル(L=24,H=1024,A=16,Total Parameters=340M)
※ L:レイヤー数 H:隠れ層のサイズ A:self-attention headの数
Transformerと比較すると↓の感じです。
##従来モデルとの比較
BERTが文章を双方向で学習するTransformerを使用するのに対して、以下の2つのモデルと比較してあります。
【OpenAI GPT】
文章を順に読む「片方向」のTransformer
【ELMo】
文章を双方向で学習するLSTM。ただし「左から右」と「右から左」を別々に学習させて、最後にconcat(結合)する。
ざっくり言うとこんな感じですが、当然そんなに単純じゃないのでがんばって読みほどきます。
#BERT_Input
まずは、BERTのInputです。構造とポイントは以下のとおり。
【ポイント】
・Inputは「Token Embeddings」と「Segment Embeddings」と「Position Embeddingsの総和。
・Token Embeddingsの特徴として、全文章の初めには[CLS]というトークンを挿入する(Classification Embeddingと呼称)。
・Segment Embeddingsでは文章Aと文章Bが分かるようにEmbedding情報を付与する。短文の場合は不要。また、文章毎の区切りには[SEP]というトークンを使用する。
・ Position Embeddingsは、Transformerと同様の考え方(詳細は過去分を参照ください)。
#BERT_Pre-Training
ここからBERTのPre-Trainingを説明していきます。これ↓です。
##Pre-Training概要
図を見ると、BERTと書かれた青い箇所から上に赤い矢印が出てます。
まず、青い箇所が「Bidirectional Transformers」でここでSelf-Attentionを使用してencodingしています。赤い矢印部分は、
Mask LM ⇒ Masked LM
NSP ⇒ Next Sentence Prediction
という機能です。説明は後述。
要はencodingされた文章(単語、語句)を、両機能に投入する仕組みで「encoder-decoder」モデルでいうと、両機能はdecoderのイメージですかね(decoderというのはちょっと言い過ぎかもしれません)。
###Pre-Trainingの二つの機能
先述のとおり、Pre-Trainingには2つの機能があります。
【Masked LM(Language Model)】
通称**「穴埋め問題」**
⇒文章の中でランダムに単語をマスクし、その単語を当てる学習
【Next Sentence Prediction(NSP)】
通称**「隣接文問題」**
⇒2つの文章を入力して意味的につながりがあるかないかを言い当てる学習
この2つの機能が重要なので深堀りします。
##Pre-Training_Masked LM
####【目的】
文章を単方向で学習するより双方向で学習させた方が精度が上がるので双方向学習させたいが、双方向学習をさせようと思うと、先の文字・単語(将来の文字・単語)を見てしまうのでカンニングになる。
よって、文字をマスキングすることで、カンニングの課題を克服し予測精度を向上させる。
####【手法】
①全体文書の単語の15%をランダムに選定し、「予測トークン」としてラベル付与の上、MASKする。
②「予測トークン」を以下のとおりとする。
・80%をMASKのまま。
・10%をランダムな単語に置き換える
・10%を元の単語に戻す
③予測トークンに対する予測結果と元の単語でLossを計算し学習する。
###Pre-Training_Masked LM_仕組み
以下のサイトを参考にさせていただきました。
https://towardsdatascience.com/bert-explained-state-of-the-art-language-model-for-nlp-f8b21a9b6270
仕組みは以下のとおり。
①Transformer encoderの出力を【 Classification Layer 】で受ける。
②【Classification Layer】は「Fully-connected layer」+「GELU」+「Norm」
③上記②をEmbeddingと掛け合わせたベクトルに対して、softmax関数で確率を計算する。
④予測結果と元の単語(正解ラベル)でLOSSを計算する。
上記②をもう少し掘り下げます。上記②は以下の仕組みです。
[fully-connected layer参照元]
https://medium.com/@tecokids.monastir/fully-connected-layer-with-dynamic-input-shape-70c869ae71af
[GELU参照元]
https://mc.ai/gelu-gaussian-error-linear-unit/
ここで出力したベクトルを上記③で処理します。③は以下のイメージです。
この結果を正解と突き合わせて、MASKされた単語を予測します。
##Pre-Training_Next Sentence Prediction(NSP)
####【目的】
言語予測やQA等の自然言語のタスクは、2つの文章の関係性を理解する事が基本になっているが、これまでの仕組みでは文章の文脈を理解できない。
よって、Next Sentence Prediction(NSP)を行う事でこの問題を解決する。
####【手法】
①入力文章として2つの連続した文章を用意する(前文章をA、後ろ文章をBとする)。
②AとBを1セットとして、複数セットの文章群の内50%は「Aの後にBが続いている」と学習させる(Is Next)。
③残りの50%はBをコーパスからランダムに選定した文章に置換して学習させ、「Aの後にBは続かない」と学習させる(Not Next)
なお、上記とは別で重要なポイントは、このAとBの文章を識別するために、InputにAとBが分かるEmbedding情報を付与し、また文章の区切りが分かるようにトークン[SEP]を設定している所です。
総じてNSPのやる事を簡単に言うと、
ということになります。
###(寄り道)Pre-Training_Next Sentence Prediction(NSP)
NSPは二つの論文の手法を参考にしているようなので、この二つの論文の概要を整理してみます。そこまで深く読めていませんし本旨と少しズレますので、興味の無い方は読み飛ばしていただいてokです。
#####【1つ目】
論文名:「Discourse-based objectives for fast unsupervised sentence representation learning」
Yacine Jernite, Samuel R. Bowman, and David Sontag.2017.
この論文では、2つのペア文章を用意し、ある文章から隣接(後続)文章を予測しており、タスクを3つ実施しています。仕組みは以下のとおりです。
ペア文章から分類問題を行う箇所は確かにNSPの考え方ですね。
#####【2つ目】
論文名:「An efficient framework for learning sentence representations」
Lajanugen Logeswaran and Honglak Lee. 2018
この論文では、ある文章の回答候補文を複数用意し、分類レイヤで識別するというもの。こちらもNSPに似ていますね。
##Pre-Training全体整理
今までの「Masked LM」「Next Sentence Prediction(NSP)」を含めて整理するとPre-Trainingは以下のようになります。
なお最下段の図は以下から引用させていただきました。
[MASK後input参考元]
https://towardsdatascience.com/bert-explained-state-of-the-art-language-model-for-nlp-f8b21a9b6270
さらにモジュール分割して↓に書きます。んっ?急に出てきた「BertPoolerモジュール」。実はこれが非常に重要で、ここでインプットの「CLS」にインプット文章全体をいい感じに表現したベクトル(テンソル)を格納しています。「CLS」はファインチューニングで使います。
#BERT_Fine-tuning
先述のとおり、BERTは事前学習モデルで予測モデルではないので、そのままでは何もできません。「Fine-Tuning」というタスクは、BERTのモデルに分類レイヤー等を追加するだけで、多くの言語タスクに利用することができるというものです。
ちなみに使うのは下図の赤枠の部分です。ここに「Masked LM」「Next Sentence Prediction(NSP)」でPre-Trainingした後のパラメータが入っています。
##BERTの入出力
BERTモデルの入出力は、Google の公式実装の modeling.py 中の BertModel クラスで定義されており、使用方法は以下の通り。この出力メソッドを使って後続タスクを実施します。
[画像・説明参考元]
https://www.ogis-ri.co.jp/otc/hiroba/technical/similar-document-search/part3.html
①は学習データの入力シーケンスに対応したinputになります。↓に対応したinputですね。
②は文章ベクトルのoutputになります。使用用途は以下のとおりです。
・Masked LM ラベルとの突合せ
・ファインチューニング時は入力シーケンスの各要素の品詞を判定したり、
質問の答えに相当する箇所を判断したりする。
③は出力シーケンスの先頭”[CLS]“に対応するベクトルを収録したもの(線形写像したものが入る)。要は、インプットの文章がいい感じに表現されたベクトル(テンソル)が格納されます。使用用途は以下のとおりです。
・入力シーケンス全体として何かを判定する。
・Next Sentence Prediction のラベルとの突合せ。
・ファインチューニングでの文章分類問題。
##BERTのタスク種別
BERT論文中で紹介されている使用タスクは以下のとおり(まず2つ)。
(a)ペア文の分類タスク
繰り返しになりますが、BERTの出力シーケンスの先頭[CLS]には文章全体をいい感じに表現したベクトル(テンソル)が格納されていて、Pre-Trainingにより「2つの文章が隣り合ってるか」を識別できる状態です。よって、[CLS]の後続に分類モデル(教師あり学習モデル等)を追加し、再度学習することでペア文か否かの分類タスクが解決できるようになります。
(b)単文の分類タスク
くどいですが、BERTの出力シーケンスの先頭[CLS]には文章全体をいい感じに表現したベクトル(テンソル)が格納されています。よって、ここも(a)と同様、[CLS]の後続に分類モデル(「文章が正しいか」「感情がポジティブかネガティブか」等)を追加し、再度学習することで分類タスクが解決できるようになります。
(c)質疑応答タスク
QuestionとParagraphの関係性を見て、Questionの回答となる文をParagraphから探し、その文の最初と最後に目印(トークン)を付与して出力します。よって、後続に正解ラベルとなる回答文書を用意し、再学習させることでQAタスクを解決できるようになります。
(d)固有表現抽出(NER「Named Entity Recognition Dataset」)
入力シーケンスから文字列中に含まれる多くの固有表現(人、物、地名、等々)に目印(トークン)を付与して出力する(ベクトル出力)。
上記のベクトルをinputとして後続で「固有表現抽出ラベルを予測する分類レイヤー」を追加することで固有表現抽出の学習を行う。
##BERTのタスク評価結果
BERT論文中の「GLUE」「SQuAD」「SWAG」「NER」の評価結果を記載します。
結論、すべてのタスクで勝利していて、本当にすごいモデルなんだと痛感いたします。
###GLUE
GLUEは自然言語処理に関する学習データを含んだデータセットで、テストデータの正解ラベルを公開していないため、信頼度が高いです。
【収録されているデータセット】
・CoLA(The Corpus of Linguistic Acceptability)
・diagnostic(Diagnostics Main)
・MNLI(MultiNLI Matched/Mismatched)
・MRPC(Microsoft Research Paraphrase Corpus)
・QNLI(Question NLI)・QQP(Quora Question Pairs)
・RTE(Recognizing Textual Entailment)
・SNLI(Standord Natural Language Inference)
・SST-2(The Stanford Sentiment Treebank)
・STS-B(Semantic Textual Similarity Benchmark)
・WNLI(Winograd NLI)
上記からBERTで使用したデータセットは以下のとおり。
[参考元]https://ai-scholar.tech/articles/text-mining/bert-ai-93
タスク結果は以下のとおりです。
###SQuAD
SQuAD(The Stanford Question Answering Dataset)は質問応答技術を研究するためのデータで約10万ペアを収録しています。データは「テキスト」「質問文」「正解」の3つから成っており、質問文に対する回答をテキストから抽出するというもので、文意を理解する必要があるためタスクとしての難易度が高いです。
【テキスト】 Wikipediaの記事
【質問文】 Wikipediaの記事を元にした質問
【正解】 質問に対する正解
なお、完全に正解する必要はなく「キーワード」「主旨」等が合致していれば正解になります。なお、SQuAD ver2.0から「回答できない質問には回答できないことを示す」というタスクが追加されています。タスク結果は以下のとおりです。
なお、上図の見方は以下の通りです。
【EM】予測が正解と完全一致することを要件とする評価指標**
【F1】適合率と再現率から求めるもので、予測が正解と部分一致している場合も考慮される。
###SWAG
SWAG(The Situations With Adversarial Generations Dataset )は、動画のキャプションから取った連続した2文の、2文目の文章を複数の選択肢(複数の文章)から当てるタスクで、約11万ペアの文章を収録しています。タスク結果は以下のとおりです。
###NER
NER(CoNLL-2003 Named Entity Recognition Dataset)は約20万のアノテーションされた固有表現のデータセットです。
【固有表現抽出とは】※Wikipediaより抜粋
文中から固有表現 (Named Entity) を抽出し、それを固有名詞(人名、組織名、地名など)や日付、時間表現、数量、金額、パーセンテージなどのあらかじめ定義された固有表現分類へと分類すること。
#最後に
今回は理論を整理してみましたが、大切なのは「知る⇒理解する⇒できるようになる」だと思っています。今は「理解する」の段階なので、次はBERTの実装をがんばってみたいと思います!
最後まで読んでいただき、ありがとうございました!