CS224d: Deep Learning for NLP Part1

Feb 25, 2017   #Python  #Machine Learning  #NLP 

はじめに

 YouTubeにStanfordのCS224d: Deep Learning for Natural Language Processing 2016の動画があがっていて、面白そうだったので少しだけみてみた(2016は、2016/03/29 - 2016/06/03までなので、ちょうど1年前くらいの内容)。
 シラバスはこれで、スライドと課題もあがっている。今回は以下の講義をみた。

Lecture1 Intro to NLP and Deep Learning

 一回目なのでコース自体の概要と、NLPの概要が中心。特徴量表現を学習できるDeep Learningの登場で、NLP界隈では[Dahl 2010]の「Context-Dependent Pre-Trained Deep Neural Networks for Large-Vocabulary Speech Recognition」以降、いろんなタスク(音素、形態素、文法、意味解析と翻訳、感情、QAにおける応用など)で精度が向上している。また、これまでは離散カテゴリ的な特徴量を使っていたが、その多くがベクトル表現とその結合処理に置き換わったと説明している。

Lecture2 Simple Word Vector representations: word2vec, GloVe

 ざっくりいえばword2vecまでの話しと、モデルの簡単な説明だった。one-hot-vectorから始まって、それから、注目語の周辺語の分布の類似度に基づくベクトルができた(付近の単語が似ていたら似た単語仮説)。 ナイーブにやると、語彙の増減への対処やそもそも高次元でスパースな問題があるし、SVDで次元削減するにしても計算量の問題がある。なので、はじめから低次元のベクトル表現を学習する方が良いだろうというアイデアから[Mikolov 2013]の「Distributed Representations of Words and Phrases and their Compositionality」(いわゆるword2vec)などのいい感じのモデルができた。

word2vec

 ある語から、window幅m内の周辺語を予測することを考える。目的関数は下式で、最大化する。
Tはデータセット中のすべての語で、$w_t$が注目語を$w_{t+1}$が周辺語をそれぞれ意味する。

$$ J(\theta) = \frac{1}{T} \sum_{t=1}^T \sum_{j=-m, j\neq0}^{j=m} \log p(w_{t+j}|w_t) $$

 関数pは以下とする。$u$が周辺語を表すベクトル表現$v$が入力後を表すベクトル表現である。分母は正規化項で、Wはすべての語彙集合である。

$$ p(o|c) = \frac{\exp(u_o^T v_c)}{ \sum^{W}_{w=1} \exp(u_w^T v_c)} $$

 最適化に勾配をつかうので、以下のようには、$\log p$の微分の解説があった。 $$ \frac{\partial}{\partial v_c} \log p(o|c) = \frac{\partial}{\partial v_c} (\log \exp(u_o^T v_c) - \log \sum^{W}_{w=1} \exp(u_w^T v_c)) $$  logの商を差に分けて、それぞれを微分する。第二項は合成関数の微分。 $$ \frac{\partial}{\partial v_c} \log p(o|c) = u_o - \frac{1}{\sum_{w=1}^{W} \exp(u_w^T v_c)} \sum^{W}_{x=1} u_x \exp(u_x^T v_c) $$

$$ \frac{\partial}{\partial v_c} \log p(o|c) = u_o - \sum^{W}_{x=1} \frac{\exp(u_x^T v_c)}{\sum_{w=1}^{W} \exp(u_w^T v_c)} u_x $$  きれいにすると以下になり、第二項ですべての語彙をWを捜査する必要があるため、計算量が高い。 $$ \frac{\partial}{\partial v_c} \log p(o|c) = u_o - \sum^{W}_{x=1} p(x|c) u_x $$

Lecture3 Advanced word vector representations: language models, softmax, single layer networks

 今回は、Word Vector representationsの少し詳細な話。
 まずは前回でた計算量が高い問題に対する解決策として、negative samplingを導入して、ついでに一括更新は効率が悪いのでバッチ学習のStochastic Gradient Descent(SGD)を使う。具体的には以下の式でskip-gramを用いた場合のベクトル表現を計算するための目的関数を定義する。

$$ J(\theta) = \frac{1}{T} \sum_{t=1}^{T} J_t(\theta) $$

$$ J_t(\theta) = \log \sigma (u_o^Tv_c) + \sum_{j \sim P(w)} [\log \sigma (-u_j^Tv_c)] $$

$$ \sigma(x) = \frac{1}{1+e^{-x}} $$

 学習の各イテレーション$t$では、10~20程度の事例(中心語$u_c$と周辺語$v_o$のペア)をサンプリングし、$J_t(\theta)$の勾配を求める。 negative samplingではランダムに$k$個サンプリングした語$u_j$と中心語$v_c$の内積を小さくする(負の内積を大きくする)。よって、目的関数を最大化することにより、周辺語と中心語の内積を最大化しランダムサンプリングした語と中心後の内積を最小化する。
 尚negative samplingには、unigramの分布を$U$として、$P(w)=U(w)^{\frac{3}{4}}/Z$を使うとのこと。
 次に、skip-gramとは異なるアプローチとしてCBOW(Continuous Bag of Words)がある。これはほとんどskip-gram同じで、中心語から周辺語を推定する代わりに周辺語から中心語を推定する。
 最後のベクトル表現として、コーパス全体を使って高速に訓練できるGloVe(Global Vectors for Word Representation)が紹介された。GloVeの目的関数は次の式である。

$$ J(\theta) = \frac{1}{2} \sum^{W}_{i,j=1} f(P_{ij})(u_i^Tv_j - \log P_{ij})^2 $$

$$ \begin{eqnarray} f(x) = \begin{cases} (x/x_{max})^{\alpha} & (x \lt x_{max}) \\ 1 & ( otherwise ) \end{cases} \end{eqnarray} $$

 全ての語のペア$i,j$を考え、共起頻度を$P_{i,j}$とする。まずこの目的関数では、基本的に、二つのベクトルの内積と対数共起頻度の二乗誤差を最小化する。つまり共起頻度が高いペアの内積を高くする。次に関数$f$では、$P$が疎であるため、頻度が低いペアが及ぼす影響を小さくし、同時に、stop wordのように高頻度で出現するペアの影響も飽和させる。GloVeの説明は短かったので、公式サイト1やOkazaki先生のスライド2が参考になった。

 ところで、ベクトル表現の評価方法には、IntrinsicとExtrinsicの2パターンがある。Intrinsicはアナロジーを使って、例えば$man:woman = king:?$の関係をどれくらいの精度で解けるかを評価する方法で、ExtrinsicはNER(Named Entity Recognition)などの応用タスクの精度で評価する方法である。

おわりに

 解説が丁寧なので数学忘れていても問題なかったが、質問の英語はほとんど聞き取れなかった。リスニング力が低いとつらい。
 完全に余談だが、今回はじめてJavaScriptでLatexっぽい数式表記をいい感じに表示してくれるMathJaxをHugoに入れてみた。クライアントで置き換えているせいか、表示がかなり遅いし、Markdownのsyntaxとコンフリクトしてるのでワークアラウンドが必要3だが(別にMathJaxが悪いわけではない)、よいライブラリ。

参考

関連記事