- Published on
GloVe: Global Vectors for Word Representation 読んだ
- Authors
- Name
- Minato Sato
- @minatosatou
論文について
タイトル
GloVe: Global Vectors for Word Representation
著者
Jeffrey Pennington, Richard Socher, Christopher D. Manning
所属
Stanford NLP
3行まとめ
"global matrix factorization methods"と"local context window methods"のいいとこ取りをしていい感じのword embeddingを獲得する手法を提案するよ。GloVeは単語-単語のスパースな共起行列全体や超巨大なコーパス上の個々のlocal context windowを使うことなく、共起行列の非ゼロな要素だけを使って効率的に学習できるよ。
補足:前者の"global matrix factorization"はいわゆるカウントベースの手法で、単語-単語の共起行列をmatrxi factorizeするモデルで、後者の"local contet windows methods"というのは対象語(target)を周辺語(local context)から予測するというモデル(e.g. CBOWやその他言語モデル)である。
関連研究
- global matrix factorization methods
- このような手法は、統計情報を効率的に活用しているが、アナロジータスクに弱い。
- LSA、HAL
- 最も出現回数の高い語は不均衡な影響を与える。
- COALS [Rohde et al., 2006]
- ↑の問題に対応するためにエントロピーあるいは相関に基づくnormalizationにより共起行列の変換を行っている。
- positive pointwise mutual information (PPMI)に基づく変換
- Hellinger PCA (HPCA) [Lebret and Collobert, 2014]
- 平方根型の変換
- local context window methods
- Skip-gram、CBOW
- このような手法は、アナロジータスクに強いが、統計情報は(コーパス全体の共起行列ではなくlocalなcontext windowを使っているため)活用できていない。
- Skip-gram、CBOW
手法
まず、単語-単語の共起のカウントを格納した行列(共起行列)をと表す。このとき、
とは、文脈語の文脈で単語の出現回数を表す。さらに、
はが文脈語として出現した合計回数になる。また、
は単語が文脈語の文脈で出現する確率とする。
熱力学を考えたときにでで考えてみる。
のとき、solidはsteamではなく、iceに関連があるための値は大きくなると考えられる。
逆にのとき、gasはiceではなく、steamに関連があるための値は小さくなると考えられる。
のときは、はiceとsteamの両方に関係しているか、どちらにも関係していないので、の値は1に近づくはず。
上記の議論は、単語ベクトル学習のための適切な出発点は、確率それ自体よりもむしろ共起確率の比率にあるべきであることを示唆している。これを定式化すると、
ここで、は単語ベクトル、は文脈単語ベクトルである。
最初に、単語ベクトル空間においてを表す情報に変換するを考える。ベクトル空間は線形構造なので、ベクトルの差を使って
左辺の引数はベクトル、右辺はスカラである。 は、例えばニューラルネットワークによってパラメータ化された複雑な関数であると見なすことができるが、そうしてしまうと前提にある線形構造をobfuscateしてしまうので、の引数同士のdot productとしてしてあげると、
次に、単語-単語の共起行列の場合、単語と文脈語の区別は任意であり、2つの役割を自由に交換できます。つまり、だけでなく、も交換可能でないといけないが、は満たしていない。
まずはじめに、についてとの間で準同型(homomorphism)を仮定すると、
補足:について加法群から乗法群への準同型であるとは、
を満たすことを言う。
より、
とおくと、
のがなければ、交換対称性があるのに。。。。
補足:、としたときに(6)は
となる。一方としたときに、
となり、とを比較したときに矛盾する。()
そこで、について、この項はとは関係がないので(に対する)バイアスで置き換えることを考え、さらに(に対する)バイアスを付け加えることで、対称性を持った
を得る。これの2乗誤差に重み関数で重み付けを行ったものを損失関数とする。
ここでは語彙数、重み関数は
は、はのときに良い結果が得られた。negative samplingのときと同じ値だ。。。 なのでそもそもの非ゼロな要素だけ見れば良いので嬉しい。(語彙やコーパスサイズにもよるが、の75–95%はゼロな要素らしい。。。)
実験
タスク
Word analogies
- is to as is to ___ ?
- にコサイン類似が近い語を探してくるタスク。
- 意味的なタスク
e.g. Athens is to Greece as Berlin is to ______ ? - 文法的なタスク
e.g. dance is to dancing as fly is to ______ ?
- 意味的なタスク
Word similarity
- データセット
- WordSim-353
- MC
- RG
- SCWS
- RW
- データセット
Named entity recognition (NER)
- 単語ベクトルを入力とし、CRF(Conditional Random Fields)で学習する。
- 訓練データセット
- CoNLL-2003 training data
- テストデータセット
- ConLL-03 testing data
- ACE Phase2 (2001-02)
- MUC7 Formal Run test set
学習につかったコーパス
- 2010 Wikipedia dump with 1 billion tokens
- 2014 Wikipedia dump with 1.6 billion tokens
- Gigaword 5 which has 4.3 billion tokens
- 2と3の足し合わせ 6 billion tokens
- 42 billion tokens of web data, from Common Crawl
Stanford tokenizerでトークナイズ、 最頻出の40万語を語彙として使用。
※5.については200万語を語彙として使用。
比較手法
- Skip-gram
- CBOW
- SVD (最頻出の1万語のみで共起行列を作る)
- SVD-S()
- SVD-L()
結果
- Word analogies
概して、GloVeが良かった。特に、42Bものバカでかいコーパスでも簡単に学習することができた。SVD-Lはコーパスサイズが大きくなると逆に精度が悪くなったが、GloVeは良くなった。(GloVeは重み関数が効いている?)
- Word similarity
概してGloVeが良い。SVD-Lとの比較は先程と同じだが、より大きいコーパスで学習したCBOWよりもGloVeの方が良かった。
- NER
概してGloVeが良い。SVD-Lとの比較は先程と同じだが、より大きいコーパスで学習したCBOWよりもGloVeの方が良かった。
考察
Embeddingの次元と文脈の長さについて
- (a) だいたい200次元くらいでaccuracyが頭打ちになる。
- (b)(c) Syntacticについては語順に強く依存するためAsynmmetric context(contextが注目語の左のみ)の方が良く、window sizeを大きくすると悪化する。Semanticについてはlocalではなく、window sizeが大きければ大きいほどよい結果となった。
コーパスサイズについて
Syntacticについてはコーパスのサイズが大きければ大きいほど良い傾向にあるが、Semnticについては必ずしもその限りではなく、コーパスの性質によって変わってくる。例えばアナロジータスクでは地名に関する設問があったが、Wiki2014の方ではそれをカバーできてきたと考えれる。
学習時間について
40万語彙、60億語のコーパスでWindow size = 10で共起行列をつくるのに85分かかったらしい。学習には32コアすべてを使って1イテレーション14分しかかからなかった。(Figure 4参照)
Skip-gram、CBOWとの比較
単純な比較はパラメータが多すぎるのでむずかしい。学習時間で比較したい。GloVeの学習時間がiterationで表されるのに対し、Skip-gram、CBOWはepochである。しかし、残念ながら現状の(Skip-gram、CBOWの)コードがsingle epochしか学習しないように実装されているため、ひとまずnegative samplingの個数が訓練に使いデータ量に関連があるので、これと比較する。CBOWに至ってはnegative samplingの個数を増やすとかえって精度が悪くなった。これは、negative samplingが対象となる確率分布をうまく近似できていないからなのかも知れない。
NNablaでの実装
import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PF
x_central = nn.Variable((batch_size, ))
x_context = nn.Variable((batch_size, ))
with nn.parameter_scope('central_embedding'):
central_embedding = PF.embed(x_central, vocab_size, embedding_size)
with nn.parameter_scope('context_embedding'):
context_embedding = PF.embed(x_context, vocab_size, embedding_size)
with nn.parameter_scope('central_bias'):
central_bias = PF.embed(x_central, vocab_size, 1)
with nn.parameter_scope('context_bias'):
context_bias = PF.embed(x_context, vocab_size, 1)
dot_product = F.reshape(
F.batch_matmul(
F.reshape(central_embedding, shape=(batch_size, 1, embedding_size)),
F.reshape(context_embedding, shape=(batch_size, embedding_size, 1))
),
shape=(batch_size, 1)
)
prediction = dot_product + central_bias + context_bias
t = nn.Variable((batch_size, 1))
zero = F.constant(0, shape=(batch_size, 1))
one = F.constant(1, shape=(batch_size, 1))
weight = F.clip_by_value(t / 100, zero, one) ** 0.75
loss = F.sum(weight * ((prediction - F.log(t+1)) ** 2))