日本語テキストのトピック抽出1　基礎編

[Aidemy](https://aidemy.net/)　2020/10/30
#はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、日本語テキストのトピック抽出の1つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・自然言語処理における深層学習
・Embedding,RNN,LSTM,Softmaxなど

#自然言語処理における深層学習
・自然言語処理の中で使われる深層学習には、__機械翻訳や自動要約、質問への自動応答__などが挙げられる。
・このような自然言語処理において、ニューラルネットワークのモデルを使うと、__誤差逆伝播法__によって単語のベクトル（Embedding）を、文脈を考慮しながら、かつ次元を押さえながら学習できるという利点がある。

##Embedding
・__Embedding__とは__「埋め込み」__という意味である。単語を扱うニューラルネットワークを構築する際に一番はじめに行う処理である。具体的には、__単語という記号をd（100〜300程度）次元に埋め込む__という処理である。
・Embeddingは__「model.add(Embedding(引数))」__というように行う。引数は以下の通り。
　・__input_dim__:語彙（単語の種類）の数
　・__output_dim__:単語ベクトルの次元dの大きさ
　・__input_length__:各文の長さ

##RNN
・__RNN__とは「__再帰ニューラルネット__」というもので、自然言語処理の深層学習でよく使われるニューラルネットワークである。__任意の長さを持つ入力列（可変長系列）を扱うことに優れる__。

##LSTM
・__LSTM__はRNNの一種で、RNNの欠点を補う機能を持つ。RNNは時間方向に深いニューラルネットワークなので、__初期の方に入力した値は「忘れて」しまうという欠点がある__。すなわちRNNは長期記憶が苦手だが、LSTMは「LongShortTermMemory」という名前の通り、__短期記憶も長期記憶も行える__。

##LSTMの実装
・LSTMもkerasからインポートして簡単に実装することができる。Embeddingと同様__「model.add(LSTM())」__で使用できる。引数については以下の通り。
　・__units__:隠れ状態ベクトルの次元数（100~300程度）
　・__return_sequences__:「True」で__全ての入力系列__に対する出力系列（隠れ状態ベクトル）を出力、「False」で__最後の時刻Tにおける隠れ状態ベクトルのみ__を出力。

##BiLSTM
・LSTMは入力系列xを1から順に最後まで入力していくが、逆に、__後ろから順に入力する手法__を取ることもできる。これを応用して、__双方向__から情報を入力する__「BiLSTM」__という手法がよく用いられる。日本語では__「双方向再帰ニューラルネット」__という。
・BiLSTMの利点は、一つのある時刻において、「先頭から伝播してきた情報」と「後ろから伝播してきた情報」の二つを取得することができる点である。
・実装の方法は、kerasの__「model.add(Bidirectional(引数))」__を使う。第一引数には、前項の__LSTM()__をそのまま格納し、第二引数には__「merge_mode」__として2方向のLSTMをどのようにつなげるかを指定する。
・第二引数には__['sum','mul','concat','ave']__のどれか一つを指定する。__sum__は要素を足してつなげ、__mul__はかけることで繋げる。__concat__は結合してつなげ、__ave__は平均してつなげる。

#Softmax関数
・今回の自然言語に限らず、クラス分類を行う深層学習においては、ニューラルネットの出力層に一番近い層では__Softmax関数__が使われる。「ディープラーニング基礎」でも、この関数は使われていた。
・「男女識別」の際に確認したことであるが、出力にSoftmaxを使うことで、各クラスの出力の確率分布の__総和が1となる__ような出力がなされるようになる。
・これまでは__Sequentialモデル__の中で、__「model.add(Activation("softmax"))」__のように使用していたが、Sequentialを使わずにモデルを記述する「__Functional API__」の場合は「__Activation('softmax')(x)__」というように記述する。このxには__[バッチサイズ,クラス数]__を渡す。

#Attention
##Attentionとは
・__Attention__とは__「Attention Mechanism(注意機構)」__のことである。これは__機械翻訳や自動要約などで頻出のメカニズムである__。
・例えば質問への自動応答の例を挙げると、ある質問文のリストsとそれに対応する回答文のリストtがあったとする。この時機械に__「tがsに対する回答文として妥当かを判断させる」__ということを行いたいとき、RNNによって__これらの文を隠れ状態ベクトルに変換__し、__ある時刻におけるsの隠れ状態ベクトルを考慮してtの特徴を計算する__ことで、__sの情報（sのどこに注意するか）を考慮したtの情報を取得できる__ため、上記判断が可能となる。

##Attentionの実装
・Attentionの実装にあたって、__Sequentialモデルでは実装することができない__ので、前々項で見た「__Functional API__」を使う。Functional APIは、ただLayerをaddするだけだったSequentialモデルと違って複雑ではあるが、__その分自在にモデルの構築を行うことが可能になる__。
・Functional APIでのモデルの構築は__「Model(inputs,outputs)」__で行う。そのため、モデル構築の際に渡す__「inputs」と「outputs」をあらかじめ作成する必要がある__。
・__inputsの作成__については、入力層を__「Input(shape=(文の長さ,))」__で作成(第二引数にbatch_sizeは入れなくてOK)し、これに__Embeddingを適用__し、これをさらに__BiLSTM__にしたら完成となる。__入力層が複数あるときは同じものを複数作成すれば良い__。
・__outputについてはAttentionを実装することで作成する__。今回で言えば、二つの文のBiLSTM「bilstm1」「bilstm2」について「__dot()__」で行列積を算出し、それに対し__Softmax関数__を適用させ、更に__これとbilstm1との行列積を算出__し、これとbilstm2を「__concatenate()__」で連結させたものを出力層として形成させることでoutputに渡すデータが完成する。

・具体的なコードは以下の通り
![スクリーンショット 2020-10-30 10.41.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/e0d23438-a87c-6824-8738-4bed9fc0151e.png)

#Dropout
・（復習）__Dropout__は過学習を防ぐために、一部データをランダムで__「0」__に設定して学習させる手法である。
・Sequentialモデルを使う場合は__「model.add(Dropout(割合))」__で使用できるが、今回のようにFunctional APIを使う場合は__「Dropout(割合)(x)」__のように使えば良い。

#まとめ
・自然言語処理の深層学習では、まずEmbeddingと言う処理を行い、単語をベクトルに変換する。
・この深層学習ではRNNというモデルが使われる。この中でも、長期記憶に優れたLSTMを使うことが圧倒的に多い。また、このLSTMをデータの両端から適用する「BiLSTM」を使うことで入力系列全体の情報を考慮することができる。
・アウトプット時にAttentionを実装することで、あるベクトルの情報を、別のベクトルの情報を考慮した上で抽出できる。この技術は自然言語処理では頻出である。
・同様に、出力層でDropoutすることでデータの汎化が防げる。

今回は以上です。最後まで読んでいただき、ありがとうございました。