【技術本】ゼロから作るDeepLearning❷―自然言語処理編
https://amzn.to/4eTaAUx
【技術本】ゼロから作るDeepLearning❷―自然言語処理編
へポスト
ゼロベースから実装(ブラックボックスの機械学習ライブラリ使用ゼロ)してディープラーニングの中身を理解できる著作の第2弾。
本書は主に、以下の3つの技術(word2vec, RNN, RNNのseq2seq)の紹介となっている。8章の最後にTransformerもアーキテクチャ概要を図を含めて軽く話題に触れていくれている。
・word2vec
自然言語処理におけるword2vecによる推論ベースの機械学習をスクラッチで実装を体験できる。紹介されるモデルの種類は、CBOWモデル(コンテキスト(前後の単語)が与えられたとき、その間にどの単語があてはまるかを推論する方法)、skip-gramモデル(コンテキスト(単語)に対して、前後の単語を推測する方法。CBOWのコンテキストとターゲットを逆転させたもの)である。CBOWモデルのみ実装と評価、および高速化の演習が含まれている。
・RNN
それまでの従来のフィードフォワードタイプのネットワークより改善され、閉じたループする系を持つRNN(リカレントニューラルネットワーク)を、時系列を踏まえた推論が可能となる点を踏まえて紹介。RNNの現状の問題点である時系列が長くなると計算量が増える問題には学習のトランケートで対処し、勾配爆発、勾配消失が起こる問題にはゲート付きRNNを使う対策なども紹介。さらなる精度向上の施策として、ゲート付きRNN(LSTM)の多層化、ドロップアウト(ニューロンをランダムで切断)、重み共有などにも言及してくれている。
・seq2seq(RNN)
EncoderとDecoder形式の学習モデル。レイヤには言語処理にはLSTM、画像処理にはCNNなどを使う。seq2seqのディープラーニングによる文章生成を紹介。反転データを学習させたり、peekyを行う事で学習効率と精度がよくなる改善方法も紹介。さらに、Attentionという必要情報に注意を向けさせる注意機構を備えた技術の導入を実装、学習、検証まで言及してくれている。
機械学習を平たく言えば、正解データを膨大な数解析し、その中から関係性、パターンをうまく数値化して評価できるように整理した状態にコンピュータシステムを保つことである。そこから、新たに評価したい入力を与えたとき、コンピュータシステムは、それまで蓄積されたデータの傾向から、もっとも評価値が高い値を選択して答えを出す。
扱うものが、文字であろうが、画像、動画であろうが、音楽であろうが、最終的に個々を数値で評価できるベクトルや行列などに、うまく数式を駆使して落とし込むことである。そのアーキテクチャがニューラルネットワークであったりするわけである。
そして、そこに至るまで最新の研究を踏まえた高度な技術がある。その知識欲を満たしてくれるのが本書。
今作では、主に自然言語処理で使用する機械学習の基盤となるアーキテクチャの実装方法、学習方法、評価方法をこの本を読むと理解することができる。
本書を読む事で、各レイヤ(全結合層、RNN, LSTM, Attention),活性化関数、損失関数の処理の流れ、役割をpythonの実装レベルで理解する事ができる。なお、本書に記載されている数式においても高校数学レベルをクリアしていれば十分に理解できる。(それ以外の数式記号は説明が入っている)
自然言語処理におけるディープラーニングの仕組みを知りたい人に価値が出てくる著作だと感じた。
概要、メモは以下の通り。
ーーーーーーー
●1.ニューラルネットワークの復習
・数学とPythonの復習(numpy)
行列とベクトル(行ベクトル、列ベクトル)
行列ごとの演算
ベクトルの内積と行列の積
・ニューラルネットワークの推論
活性化関数(非線形な効果を与えるの):sigmoid関数の紹介
ネットワークの順伝播の仕組み
全結合層>線形変換をする(隣接するニューロン間の全てに矢印による結びつきがある)
隠れ層:隠れ層のニューロンからの出力は、まとめられベクトル(列単位でまとめられ、列数と同じ要素に纏まる)となる。
活性化関数>非線形変換をする。
・ニューラルネットワークの学習
損失:学習がどれだけうまくいっているかの指標
ある時点のニューラルネットワークの性能を示す。
損失関数:交差エントロピー誤差など
微分と勾配:損失をできるだけ小さくするパラメータを探す。微分によりy=f(x)のxの値を極限まで小さく変化した時、yの変化の度合い(ベクトルの各要素の接線の傾き=勾配)が最小になるパラメータを探す。
順伝播の反対の流れをする逆伝播(誤差逆伝播法)で勾配を求め、勾配を使って重みパラメータを更新をくりかえすのが学習。
ベクトルの各要素に関する微分をまとめたものを勾配と呼ぶ。
逆伝播の仕組み:
単純な加算、乗算ノードの説明から入り、分岐、リピート、sum、MatMul、sigmoid、Affine、Softmax with Lossなどの計算グラフ、実装を紹介。
・ニューラルネットワークで非線形の問題を解く
スパイラルデータセットのクラス分け問題。
・計算の高速化
ニューラルネットワークの推論、学習は32bit演算で十分。>従来の64bitと比較し使用メモリを半分にできる。
pythonでの32bitデータ型宣言の方法。
pythonでGPU利用の方法の紹介
CuPyはNumPyと同じAPIを実装。そのためNumpyの実装をCuPy対応に簡単に変更できるメリットがある。
●2.自然言語と単語の分散表現
自然言語処理:コンピュータに言葉を理解させるための分野。
単語意味理解の手法の紹介:
・シソーラス(類語辞書)による手法
単語の同義語や階層構造の関係性を定義したもの
問題点:ラベル付けに膨大な手作業が必要、言葉の細かなニュアンスが表現できない、時代と共に変わる言葉の変化に対応できない
解決方法:
コーパス(大量のテキストデータ)を利用したカウントベースの手法の採用する
・カウントベースの手法
コーパス(大量のテキストデータ)を使用。
「単語の意味は、周囲の単語によって形成される」という仮説に基づき、その単語と周囲の単語の頻度をカウントする。>分布仮説
上述の手法で共起行列をつくり単語をベクトル表現にしたのち、単語ベクトル表現の類似度を計測するのに「コサイン類似度」を用いて評価する。二つのベクトルがどれだけ同じ方向を向いているかがわかる。
カウントベースの改善:
・隣接する単語同士の関連を計測するため、途中で冠詞「the」などが挟まれると、本来の単語より関連度が冠詞の方に高くなってしまう問題には、相互情報量という指標で対策する。
・次元削減(SVD):ベクトルの中のほとんどの要素が0である行列(疎な行列)から重要な軸をみつけて少ない次元に表現し直す>要素が0でない密なベクトルにする。
●3.word2vec
自然言語の「推論ベースの手法」
前章の「カウントベースの手法」の問題点:
大規模なコーパスを使う場合、巨大な語彙数は巨大な行列になってしまう。計算量的に次元削減(SVD)は現実的でない。
推論ベースでは、少量(ミニバッチ)ごとに重みを繰り返し更新して学習が出来る。(逐次学習が可能)
推論ベースでは、単語の意味を的確にとらえたベクトル表現=単語の「分散表現」を可能にする。
推論ベース:
・CBOWモデル
コンテキスト(前後の単語)が与えられたとき、その間にどの単語があてはまるかを推論する方法。
入力には、推論するための前後2つの単語のone-hot表現データが必要。つまり入力層は2つ。学習したい文章の単語数に応じて入力層のニューロン数が増える。
・skip-gramモデル
コンテキスト(単語)に対して、前後の単語を推測する方法。CBOWのコンテキストとターゲットを逆転させたもの。
入力は、対象コンテキスト単語のみの要素値を1として他を0と表現した「one-hot表現」の一つの入力だけで対応できる。(入力のニューロン数=one-hot表現の要素数)
実装:CBOW「コンテキストの単語穴埋め問題による単語の推論」
入力データの整形:
テキスト「you say goodbye and I say hello.」は、単語の種類はピリオドも含めて7単語となる。(sayが重複するため)
整形後:「you say goodbye and I hello .」
one-hot表現のyou [1, 0, 0, 0, 0, 0, 0]
one-hot表現のgoodbye [0, 0, 1 ,0 ,0 ,0 ,0]
モデル例:推論したいコンテキストは7単語なので入力層のニューロンは行数と合わして7とする。
入力層(行7、列5) ー>出力層(列5、行7)-> softmax with loss(7)
※入力層は「単語の意味は、周囲の単語によって形成される」という仮説に基づき、sayを推論させたい場合は、その前後の単語であるyou, goodbyeのone-hot表現(上述)のデータ2つを入力するため2つある。
実行手順:
0:入力層2つと出力層のニューロンの持つ重みをランダムで初期化。
1:入力層:入力のone-hot表現データとニューロンの重みの行列の積を計算する。入力が二つあるのでそれぞれの入力層で計算。その結果を足して2で割ったもの次の層への出力とする。
2:出力層:1で出力されたデータとニューロンの重みの行列の積を計算し出力する。
3:softmax with loss:2で出力された結果を、ソフトマックス関数で分類結果(7つの要素を持つベクトル。一番スコアが高いものが推論結果となる。)を出力する。また、損失関数で正解ラベルのone-hot表現(sayの単語を示すもの[0, 1, 0, 0, 0, 0, 0])と比較し誤差を求め、入力層2つと出力層のニューロンの重みを更新して学習する。
4:学習の場合は1〜3を学習データ文繰り返す。推論の場合は1〜3まで実施し、3の損失関数によるニューロンの重みの更新はしない。
※層のニューロン(行列要素)のそれぞれの重みこそが、単語の分散表現の正体。これによりうまく推測できるように各単語の分散表現が更新されていく。単語の意味もエンコードされていく。
●4.word2vecの高速化
問題点:
大きなコーパスを扱うときに計算量が増える
改善:
・Embeddingレイヤの追加
入力〜中間層の計算:当該単語IDの行だけ処理すればいい。行列全体の計算は不要。特定単語のベクトルのみが出力データとなる。
・多値分類を2値分類で近似する
中間層以降の計算:多値分類では出力も語彙数に比例して増える問題を、「推測する単語をyes/noで確率表現する」方式に変更する。それによって中間層の次のニューロンは一つで良くなる。従って、前の層から渡ってきた特定単語のベクトルデータと中間層の行列の内積を、次の一つのニューロンに与えれば良い。
確率を得る活性化関数:sigmoid関数
損失関数には、交差エントロピー誤差を使う。
sigmoid、交差エントロピーの逆伝播と学習効果
正解ラベルが1、正解確率が0〜1の実数。正解確率ー正解ラベルの誤差が大きい場合は、大きく学習する、小さい場合は小さく学習する。
負例(不正解)の学習は全て実施すると語彙数が増えると手に追えなくなるので少数をサンプリングして行う。
ネガティブサンプリング:
ネガティブな例(負例)を少数サンプリング(単語の出現率から確率分布を求めてサンプリング)して用いる。>コーパスで多く登場した単語が抽出されやすくなる。元の確率分布の各要素を0.75乗する(変換後も確率の総和が1になるよう分母を調整)することで、確率の低い単語に対して確率を少し高く調整ができる。
word2vecの単語分散表現を使えば、類推問題をベクトルの加算と減算で解く事ができる。
例:king-man+woman=queenなど。
例2:king:man = queen: ? の正解はwoman
次の計算で導き出せる模様:man - king + queen
似たような単語はベクトル値表現で似たような数値を持つ。
単語の似たような表現の変化は、他の単語でも似たようなベクトル値の変化で導き出せるのが面白い。
●5.リカレントニューラルネットワーク(RNN)
前章までのフィードフォワードタイプのネットワークの問題点
・時系列系のデータを正しく学習できない
与えられたコンテキストよりさらに左側(文脈でいう過去)にある単語は所定コンテキスト数から溢れ出て無視されてしまう。CBOWモデルはコンテキスト数を増やして文脈で言う所の過去のコンテキストも含められるようにできるが、単語の並びが無視されてしまう。(ネットワークの中間層では単語のベクトルの和が求められているだけのため。)
RNN=循環するニューラルネットワーク
ループする経路(閉じた経路)を持ち、隠れ状態を内部に記憶できる
RNNレイヤを展開すると、再帰でRNN層が複数(時系列の数だけ)繋がった状態とみなすことができる。
RNNレイヤに対する誤差逆伝播法も行える:BPTT
問題点:
時系列データが大きいと、比例して計算量も大きくなる。
時間サイズが長くなると逆伝播時の勾配が不安定になる
対策:
・Truncated BPTT
逆伝播のつながりを一定間隔で断ち切る。
※逆伝播のみ断ち切り、順伝播はそのまま変えない
RNNを用いた言語学習モデルの実装と学習と評価:
Time RNNレイヤ:T個のRNNレイヤから構成されるもの(Tは時系列データの数:T個の各時点の層の情報(それぞれ行列要素数のニューロンによる重みを持つ)がある)
各RNNレイヤごとの出力は、再帰でRNNに再入力される一方、もう一つの出力はAffine層,Softmax関数を経て、次の単語予測が出力結果となる。これで過去の情報をエンコードして記憶できている。
「you say goodbye I say hello」の場合、最初のsayの次の予測は、goodbye、hellloが推論確率が高いが、過去を記憶しているのでgoodbyeの方が確率が高く出る。
最終的には、AffineはTimeAffineとなりT個の時系列を個々に処理できる実装となる。SoftmaxはTimeSoftmaxとなりT個の前のRNN層->Affine層から伝わる処理結果(スコア)として出し、正解ラベルなどを元に損失関数で誤差を出し、誤差を合算して平均したもの最終的な損失とする。
言語モデルの評価にはパープレキシティ(perplexity:確率の逆数を表す)を用いる。
確率0.8の逆数は1.25, 確率0.2の逆数は5。数値として、前者は推論がほぼ1つに絞られ、後者は5個にしか絞られてない意味を表す。(これはあくまで入力が一つでのパープレキシティ)
●6.ゲート付きRNN
前章RNNの問題点:
・時系列データの長期の依存関係をうまく学習できない
・勾配消失、または勾配爆発がおきてしまう
tanh;y=tanh(x)の微分の値は1.0以下でxが0から遠ざかるにつれて値が小さくなる。つまり、tanhを逆伝播で通過するたび値が小さくなり勾配消失する。
matmal:逆伝播で繰り返し通過するごとに、重みが1より大きいと勾配爆発、1より小さいと勾配消失する。
勾配爆発対策:
・勾配クリッピング:閾値を超えたら勾配を修正する。
勾配消失対策:
・ゲート付きRNN(LSTM,GRUなど。ゲート:開くか閉じるかだけでなく、どの割合(0~1の実数)で開くかをゲートでコントロールする)
LSTM:記憶セルがあり それはLSTM層自身だけでデータ受渡する。他の層に出力しない。過去から時刻Tまでの必要な情報が格納されている。※従来の他の層にデータ受け渡しする出力もある。
ゲートはsigmoid関数でコントロール:出力が0〜1.0の実数
outputゲート:LSTMの出力のゲートを調節(sigmoid関数)
tanhノード:入力情報から新たに何を記憶セルに追加するか調節(tanh関数)
inputゲート:tanhノートからの出力をどれだけ価値があるか判断し追加情報の取捨選択をする(sigmoid関数)
forgetゲート:入力の記憶セル情報から何を忘れるかでゲートを調節(sigmoid関数)
これにより勾配の劣化(消失や爆発)が起きない理由
・逆伝播時には「+」と「✖️」ノードだけを通る。「+」は情報をそのまま流すので劣化は起きない。「✖️」は行列の積でなく要素ごとの積(アダマール積)であるため劣化は起きない。
・逆伝播時にforgetゲートが忘れるべきと判断した記憶セルの要素の勾配を小さくし、忘れてはいけないと判断した要素に対しては勾配の要素は劣化することなく過去に伝わる。そのため、長期にわたって勾配消失などは起こさずに伝播することが期待できる。
以上を踏まえLSTMを実装し、TimeLSTMに拡張実装する。
LSTMのさらなる改善:
・LSTMレイヤの多層化:PTBデータセットの場合2〜4層が適す。
・Dropoutによる過学習の抑制:ネットワークのニューロンをランダムで切断。
時間軸と独立して、深さ方向にDropoutレイヤを追加する。
・重み共有:embeddingレイヤとAffineレイヤで重み共有。学習パラメータを減らせる。
以上を踏まえて改良されたRNNLMの実装をする。
●7.RNNによる文章作成
時系列データを別の時系列データに変換するモデルとしてのseq2seq。RNNを2つ組み合わせたもの。Encoder-Decoderモデルとも言われる。
時系列データ:言語データ、音声データ、動画データなど
時系列データを別の時系列データに変換する例:翻訳、音声認識、チャットボットの対話、コンパイル
RNNによる文章生成の手順
seq2seq翻訳モデル例:
入力「吾輩は猫である」-> Encoder -> Decoder -> 出力「I am a cat」
Encoder,Decoderは協力して時系列データを別の時系列データに変換する。
Encoder,DecoderにはRNN(LSTM)を使用することができる。
Encoderは時系列データhというベクトルを出力(固定調のベクトル:これはLSTMレイヤの最後の隠れ状態)これに入力文章を翻訳するために必要な情報がエンコードされている。
Decoderは、TimeLSTM -> TimeAffine -> TimeSoftmaxで出力された推論結果データを次の再帰処理のTimeEmbedding -> TimeLSTM -> TimeAffine -> TimeSoftmax -> (次の時間のLSTM)TimeEmbedding....と入力していく。
Encoderから出力されたhは、DecoderのTimeLSTMに入力される。
逆伝播ではDecoder->Encoderへと勾配が伝わる
時系列変換seq2seqの実装:「足し算を解けるか」
足し算のロジックを知らなくても解けるのか。>桁数の異なる計算はパディングにより空白で埋めて各計算、答えの桁数を統一する。(一番長い文字列に合わす)>Decoderでパティングの場合は損失計上をしないようにしたり、Encoderではパティングを前時刻の入力をそのまま出力するなどの実装をする。
入力:57+5の場合、1文字ずつ文字ベクトルに変換し、TimeLSTMに読み込ませていく(正確には一番手間にあるのはTimeEmbedding)。
Decoderは、学習時に正解値62を('_','6','2',' ')をそれぞれ1文字ずつTimeLSTM(正確にはTimeEmbedding)に与え、正解ラベルで('6','2',' ',' ')と出力するよう各TimeSoftmaxで与えて損失関数で誤差を出し逆伝播でパラメータ(重み)の更新をする。Softmaxで出力された値のうち最もスコアが高いものを選ぶ(確率的でなく決定的に選ぶ)
seq2seqのさらなる改良:
・入力データの反転 による学習効果向上:57+5 → 5+75
変換後の各要素の距離が掴みやすくなるため、勾配が伝わりやすく学習効率が上がる。
・Peeky:覗き見
Encoderから出力された直後のデータはDecoderにとっての全てが詰まっているので、それをTimeLSTM全体の層にも共有する。>正確には、TimeLSTM,TimeAffineに時系列ごとにベクトルを結合させる。
seq2seqを用いたアプリケーション
・機械翻訳:「ある言語の文章」を「別の言語の文章」に変換
・自動要約:「長い文章」を「短い文章」に変換
・質疑応答:「質問」を「答え」に変換 >応用チャットボット
・メール自動返信:「受け取った文」から、「返信文」に変換
音声、動画などでも利用可能。
seq2seqのLSTMをCNNに置き換えるだけで画像を扱える。>画像にキャプションを行える。
●8.Attention
seq2seqを更に強力にする「注意機構(attention mechanism)」
・重要な情報に注意を向けさせる
・seq2seqには問題点があり、入力分の長さに関わらず、出力が固定長のベクトルである。そのため、必要な情報が収まり切れなくなる。
改良:
・Encoder:出力は固定長でなく、LSTMレイヤの隠れ状態のベクトルをすべて(単語列と同じ数:5つの単語なら5つのベクトル)利用できるようにする
・Decoder:
Attention:時系列のデータの中から必要な情報だけに注意を向けさせ、その情報から時系列変換を行うこと。
・Attention Weightレイヤ:注意を払い、各単語の重みを求める
・Weight Sumレイヤ:上記の重みと、その重み付き和を求め、それをコンテキストベクトルとして出力
Attention付きseq2seqの実装、学習と評価
Attentionに関する残りのテーマ
・双方向RNN:LSTMレイヤに逆向きの流れ用の層とネットワークを追加する。
左右の両方向の情報を集約してバランスのとれた情報がエンコードできるようになる。
・skipコネクション
層を深くするときの重要テクニック。層をまたぐ接続を追加する。skipのコネクション接続は「加算」。加算は逆伝播の時は情報を加工せず受け流すだけなので、これによって層を深くしても勾配が爆発、消失に影響を及ぼす事なく学習ができる。
Attentionの応用
・ニューラル翻訳:Google Neural Machine Translation(GNMT)はseq2seqのAttentionで構成。
・Transformer:RNNの欠点である並列処理化に対応。TransformerはAttentionによって構成される。
Feed Forwardレイヤを新たに実装:時間方向に独立して処理するネットワーク
翻訳性能スコアは、GNMTより高い。
●付録A.sigmoid関数とtanh関数の微分
●付録B.WordNetを動かす
●付録C.GRU
以上。
へポスト
