自然言語処理編」を読んで、Word2VecのモデルをsentencepieceとTensorFlowを使用して日本語でも実装できるんじゃないかと思い立ったのでやってみる。残念ながら、学習がうまく進まなかったのでひとまず公開だけしておき、学習が進んだらまた記事を更新したいと思う。(追記2020年2月12日)学習がうまく進んだので変更分はgithubに全面的に反映させた。中身の確認Word2vecについてWord2vecというのは単語をベクトル表現にと落とし込むのこと。bag-of-words(COBW)と呼ばれる手法を使ってベクトル表現をニューラルネットワークに学習させていく。CBOWの基本的な理念COBWでは、くり抜いた単語の、前後W単語(Wは任意の自然数)の合計2W単語から、くり抜かれた単語を予測しにいくタスクを解いていくことによって単語の内部表現を獲得しにいくモデルを指す。"your")から"[mask]"の単語を予測する。これを、中間層ありの2層のニューラルネットワークで実装する。各層の解釈は以下の通り。1層目で前後2W単語の分散表現を獲得し、足し合わせる2層目獲得された分散表現から、マスクされた単語を予測するまず、1層目では以下の式で表されるように、各単語に該当する暫定ベクトルを抜き出してその平均を取得する。番目の入力について考える。は$i$番目の入力に該当する単語の集合を示す。Samplingを使用するときはシグモイド関数)をかけた値で各語彙に対する確率を計算する。語彙数が膨大になる時、全部の出力結果を考慮すると計算量が多くなってしまうため答えに関係するものだけ考慮する場合がある。この時はシグモイド関数を活性化関数とし、正例といくつかの負例のみの確率を最適化する手法が存在する。Samplingと言う。デコード用の重み行列ただ、これだけ計算して誤差逆伝播をしてしまうと全ての出力を高くしておけば問題ないということになってしまう。そのため、負例についてもいくつかコーパスの頻度分布にしたがってランダムに入れ込み、それらについては確率がゼロになるように計算させる。\boldsymbol{b}_{out})$$これを何単語入れるかは計算機の実力次第。これらの確率からクロスエントロピー誤差を獲得して誤差逆伝播させていく。one-hotベクトル実装では実際に実装していく。以下でおいていくコードはこのレポジトリに全ておいてある。https://github.com/wildgeece96/word2vecsentencepiceの学習ずみTokenizerも置いてある。日本語Wikipediaでもよかったが時間がかかりそうだったので青空文庫の小説をとってきてそれらを学習に回すことにした。ダウンロードできる作品リストを取得する。data/list_person_all_extended_utf8.csv取得したCSVファイルの情報を元に、テキストファイルをダウンロードしていく。入れたときに、joblibを使って並列処理でダウンロードする。若干作品数が多かったので並列処理で行うことにした。urls)次に、純粋な本文のみを取り出すために前処理を行う。青空文庫はルビを籠城《ろうじょう》の一揆軍は全滅したと伝えられ丁寧につけてくれているのだが今回はいらない。抜き出していく必要がある。最初と最後に書籍情報を掲載しているところが10行ほど存在しているのでそこも削除する。occurred.")とりあえずこれでコーパスの用意は完了した。今回は英語ではなく、日本語を使うので分かち書きをするのが少々難しい。使ってやるのもよかったが、以前にも使ったsentencepieceを使おうと思う。--shuffle_input_sentence=true")簡単な動作確認をする。spm.SentencePieceProcessor()sp.Load('tokenizer/aozora_8k_model.model')text="僕の周りには分からないことだらけだけれど、1つずつ理解していくような努力をしていきたいと思う。']前回と似たような結果になったのである程度うまく学習できた様子。トークンの頻度分布を確かめる今度はトークンごとの頻度を取得する必要がある。Samplingがうまくいかないと思われるため。x_hist)レイヤー設計まずは1層目の埋め込み部分から。ここはkerasですでに実装されているEmbeddingレイヤーを使う。Embeddingレイヤーでの出力を平均する必要があったのでその操作までを含めてContextEmbeddingLayerと名付けた。xNegativeSamplingは結局実装しなかった。厳密には、実装したがうまくいきそうになかったのでやめたという表現が正しい。一応その残骸をここに載せておく。x上記2つのレイヤーをまとめたCBOWモデルクラスを実装。Samplingを行う数+1の値。xDataLoaderの実装DataLoaderもコードだけ置いておく。学習を実行するクラスTrainerをここで実装する。損失の計算部分もここに実装してしまった。(本当は別途で関数を設けるべきであったが。学習ではこれらを実装したもので学習を行う。CPUだと半日くらいかかりそうなのでGPUに計算を任せることにする。大体1時間くらいで終わった。lossの経過をTensorboardでみてみる。./out/record/20200211-0111指定したハイパーパラメータは以下の通り。"./tokenizer/aozora_8k_model.model"10エポック目(45kステップ目くらい)で学習率を1/10に縮小した。Samplingは結局使用せず、Softmαxで全体の確率を出力するようにした。学習させたベクトルをいくつかみていきたいと思う。topn=5)こんな感じで、起動し、適当な文章を打ってみると、それに類似した単語が5個くらい表示される。なった結果を見てみると、ある程度できていそうな雰囲気はあるがそもそも区切り方自体に意味が含まれにくいため、うまく学習できていないものもある。あるや猫、吾あたりは結構近い単語が出ている気がする。lossが思ったより下がりきらなかったので少々不安であったが結構面白い結果になったと思う。ubuntu著者プロフィール。