【非専門家向け】単語の "意味" を計算機で扱うイメージをつける - chiVe / chiTra 利活用に向けて Part1.

2022年4月末に、[WAP tech talk](https://worksapplications.connpass.com/event/244032/) にて、「単語分散表現と事前学習モデル - chiVe / chiTra 利活用のための下準備」というタイトルでお話しをしました。

<script async class="speakerdeck-embed" data-id="7c07375e20d046eea6c67d3af2a392f2" data-ratio="1.77777777777777" src="//speakerdeck.com/assets/embed.js"></script>

[単語分散表現と事前学習モデル - chiVe / chiTra 利活用のための下準備](https://speakerdeck.com/waptech/dan-yu-fen-san-biao-xian-toshi-qian-xue-xi-moderu-chive-chitra-li-huo-yong-falsetamefalsexia-zhun-bei-at-wap-nlp-tech-talk-number-5)

本記事は、この内容のQiita版という位置づけのもので、何回かに分けて紹介していきたいと思います。
Part1 では、**単語の "意味" を計算機で扱うイメージをつける** ことを目指し、**one-hotベクトル** と **共起頻度行列** を取り上げ、それにより実現できることと問題点を紹介します。

Part2 は [こちら](https://qiita.com/masakuri/items/480c093953dc9dd7f54b)

# 単語の "意味" を計算機で扱うには
自然言語処理においては、ことばの "意味" を計算機上で扱えるようになることがひとつ重要になります。
計算機で単語の”意味”を扱うには、以下のように単語を何らかの**ベクトル**（数値列）に変換する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206687/6f9a96a1-1765-1457-e767-db2fa7224ceb.png)

では、どのようにベクトルを与えるとよいでしょうか？

## one-hot ベクトル
まず、導入として、最も簡単な与え方として one-hot ベクトル を考えてみたいと思います。
one-hot ベクトルとは、**対象とする語のindexにのみ 1 、それ以外はゼロ** とするベクトルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206687/1b0d9f62-dda1-2a8e-f526-3c61880cb171.png)

例えば、全単語を五十音順に並べたとして、”イヌ” が先頭から数えて123番目だった場合、"イヌ"ベクトルは、123次元目に 1 、それ以外はゼロという形で表せます。
スダチ、ネコに関しても同様にします。これにより、一応計算機上で、それぞれの単語を表現できるようになりました。

### one-hot ベクトル の問題点
ただ、いくつか問題があり、ここでは2点紹介します。
#### 次元数が巨大になる
その語のindexにのみ1を与え、単語間でベクトルが衝突しないようにするには、**語彙数分の次元が必要** になります。
ワークスが公開している word2vec モデルの [chiVe](https://github.com/WorksApplications/chiVe) で見ると、語彙数は300万（`v1.2 mc5` モデルの場合）を超えているので、**1単語に300万次元** が必要になります。
メモリ効率が悪く、使い勝手が悪そうです。

#### 単語間の "関係" を捉えられない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206687/a4a92223-b0c4-5914-7a17-48d04c02f860.png)
我々人間は、”イヌ”と”ネコ”はどちらも動物で哺乳類でペットとして人気で...という共通点を認識しており、”イヌ”と”スダチ”の間にはあまり共通点はないかなと考えることができると思います。
一方、one-hotで与えられたベクトルから計算機が単語間の関係を見出せるかというと難しいと思います。

## 共起頻度行列
では、”意味” を捉えるための与え方として、コーパス上での共起頻度というものを考えてみたいと思います。
![PElqgsyv9eIkr1jjSgQj1654076062-1654076282.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206687/7dcb449b-7478-0040-b0ef-1deece27816b.gif)
**文書中での各単語間の共起する頻度** を数えます。
例えば、”スダチ” とよく共起するのは ”魚” だったり ”徳島” だったり ”酸っぱい” だったりで、”走る” や ”かわいい” とは同じ文書中にはあまり出現しないといった感じです。

これにより、各単語のベクトルを作ることができます。
この方法で作ると、先ほどの **one-hotベクトルより嬉しいこと** があります。

“スダチ” と ”カボス” を見ると、どちらも ”魚” や ”酸っぱい” とよく共起していて、それらと関係するものなのかなと推測できます。
“イヌ” と ”ネコ” に関しても、どちらも ”走る” や ”かわいい” とよく共起していて、それらと関係するものなのかなと推測できます。
このように、文書中での共起頻度行列を構築することにより、 one-hot ではできそうになかった、**単語の ”意味” を捉える** ベクトルができそうです。

この、**周囲の単語によって単語の”意味”は形成される** という考え方を **分布仮説** と言い、この後の発展においても重要な考え方になっています。

### 共起頻度行列 の問題点
意味が捉えられ、良さそうな共起頻度行列ですが、これにもいくつか問題が考えられ、ここでは2点紹介します。

#### 次元数が巨大になる
一つ目は、この方法でも次元数が巨大になるということが問題です。
実利用の際は次元圧縮を行うことになりますが、文書中に出現する 単語-単語 間の全ての共起頻度を持つ必要があるため、[chiVe](https://github.com/WorksApplications/chiVe) の語彙数とすると300万×300万行列 (`v1.2 mc5`モデルの場合) が必要になり、非現実的です。

#### 新語への対応の煩雑さ
世の中では、日々新しい語が生まれています。
新語を追加するには、その語が含まれるコーパスで共起頻度をカウントすることになりますが、新たなコーパスの追加で既存単語間の共起頻度も変わるので、共起頻度全体の更新が新語への対応のたびに必要になります。

# Part1. まとめ
「chiVe / chiTra 利活用に向けて」の Part1 として、単語の "意味" を計算機で扱うイメージをつけることを目的とした内容を書いてきました。
共起頻度行列により、単語の意味を捉えられそうなところまで来ましたが、利活用をする上では課題がありそうだということがわかりました。
次回のPart2では、word2vecを取り上げ、単語の "意味" を固定次元に埋め込むイメージをつけていきたいと思います。

Part2 は [こちら](https://qiita.com/masakuri/items/480c093953dc9dd7f54b)