doc2vecをしてみた（機械学習名古屋第１３回勉強会）


# 自己紹介・近況
名前: 中西克典
所属: 有限会社 来栖川電算（バイト）
twitter: @n_kats_
昔は数学をしていた。

数週間前、全脳アーキテクチャ若手の会 関西異分野交流会なるものに参加するも、学生さんばかりで浮いていた気がする。

---

# 内容
* 経緯
* pythonでdoc2vecをする方法
* 実際に使った話

---

# 経緯
---
先輩「好みの小説を探したいから小説をベクトル化してくれ」

---
# 最初の案
* word2vecで単語をベクトルにして平均を取る？    
* タグやジャンルを推測する？

---
# 最初の案はダメ
* 単純な平均じゃ意味のあるベクトルが取れる気がしない
* 先輩「タグやジャンルよりもっと細かい検索がしたい」

---
# doc2vecがあるやん！

---
# doc2vecとは
文章をベクトルに変換する機械学習アルゴリズム

word2vecの進化形

---
# 不安要素
* 小説みたいな長い文章も大丈夫？
* doc2vecって技術的な評価はどうなっているの？強いの？

とりあえず、やってみよう
（この疑問は解決していません）

---
# doc2vecの話
---
# 調べたこと
* doc2vecのアルゴリズム
* pythonでお手軽にdoc2vecが試せるパッケージ「gensim」

---
# doc2vecの前にword2vecについて

word2vecは、単語をベクトルに変換。
文章の中でその単語の近くに出る単語の確率を学習するモデル。（雑）

``` math

\text{単語} \rightarrow \text{ベクトル} \rightarrow \text{近くの単語の確率}

```

左の矢印の部分が単語のベクトル化

---
# doc2vecでは

```math
\begin{align}
\text{単語} \rightarrow \text{ベクトル} \rightarrow &
 \text{足したベクトル} &
\leftarrow \text{ベクトル} \leftarrow \text{文章} \\
& \downarrow & \\
& \text{近くの単語の確率} & 
\end{align}
```

単語だけでなく、文章をベクトル化して、その単語の近くの単語を予想

---
# 未知の文章には？
word2vecでは、頻度の高いものだけベクトル化できればOK。未知の単語は重要ではない。（雑）

通常、ベクトル化したい文章は学習データの文章と一致しない。

最適化で実現

---
# 最適化で未知の文章をベクトル化

```math

f(\text{単語のベクトル}, \text{文章のベクトル}) = \text{近くの単語の確率}

```

単語のベクトルは固定したまま、文章のベクトルだけ学習（最適化）

以上がdoc2vecのアルゴリズム

---
# pythonでdoc2vec

---
# gensim
https://radimrehurek.com/gensim/
(GNU LGPLv2.1 license)
自然言語に関する機械学習ライブラリ

---
# 学習の流れ
1. 文章を用意する
2. 単語に分解
3. 単語を登録
4. 学習

---
# 文章を用意する
gensimはしてくれないので、自分で頑張る。
学習用データとなる文章を十分に多く用意する。

素朴に、一行に一つの文章を書いたテキストファイルで十分。

---
# 単語に分解
文章を単語のリストにする。

* 短い・長すぎる単語、頻度の低い・高すぎる単語、を削除
* mecabなどで分かち書きへ変換
* 扱う文章データ固有の前処理

gensimではsimple_preprocessという関数がある。

``` python
import gensim
gensim.utils.simple_preprocess("This is a document.")
# ['this', 'is', 'document']

```
---
# 学習データの入力
文章のID（何個目の文章かなど）と、単語に分割された文章をTaggedDocumentという形式で入力する。

``` python
from gensim.models.doc2vec import TaggedDocument
TaggedDocument(単語に分解された文章, [文章のID])

```

---
# doc2vecのモデルを作成

```
from gensim.models import Doc2Vec
model = Doc2Vec(size=ベクトルの次元)
```

引数は色々指定できる（[公式ドキュメント](https://radimrehurek.com/gensim/models/doc2vec.html)）

---
# 単語の登録
build_vocabメソッドを使う。

```
model.build_vocab(train_corpus)
# train_corpusは、TaggedDocumentのリスト
```

---
# 学習
学習はtrainメソッドを呼ぶだけ。

``` python
model.train(
  train_corpus, 
  total_examples=model.corpus_count,
  epochs=50)
```

---
# 文章のベクトル化
infer_vectorメソッドを使う

```
model.infer_vector(preprocess(document))
# preprocessは前処理を行う関数
```

---
# まとめると

```
from gensim.models.doc2vec import TaggedDocument
from gensim.utils import simple_preprocess as preprocess
from gensim.models import Doc2Vec


# 学習データ読み込み
train_data = ...  # 学習文章データのパスに置き換えてください
assert train_data != ...

train_corpus = [
    TaggedDocument(preprocess(doc), [i])
    for i, doc in enumerate(open(train_data))]

# モデル作成
model = Doc2Vec(size=50)
model.build_vocab(train_corpus)
# 学習
model.train(train_corpus, total_examples=model.corpus_count, epochs=10)

print(model.infer_vector(preprocess("This is a document.")))

```

---
# 使用例
## 文章ベクトルで近傍探索
ベクトルが近い文章を探す

```
result = model.docvecs.most_similar([vec])
# modelは上で学習したmodel
# vecは入力の文章のベクトル
# resultは文章のIDとスコア（どれだけ近いか）の対のリスト
```

---
# 使ってみた

---
# 目標
doc2vecで論文のabstractをベクトル化してそ、論文の近傍探索したい

* この論文に近い論文はこれだ、読んでみよう
* 最近投稿された論文で、よく参照するような論文と近いのはこれだ
* 別ジャンルだけど、似たようなことを扱っているものを見つける

みたいな使い方をしたい

---
# 現状
まだまだ開発中
https://github.com/n-kats/arxiv2vec

* ベクトル化や近傍探索は試せる
* いい感じに近い論文が出てきているかは怪しい

---
# 日本語の小説は・・・

* 分かち書きが必要
* 頼まれたけど自分が小説を読まない

という理由で不採用

---
# 文章を用意する

arXivにある論文のabstractを利用
APIを叩いて適当な分野の論文の情報を取得
一行に一つの論文のabstract文章が書かれたテキストファイルを用意

---
# 課題
abstractは数式混じりの文章

```
For an oriented link $L \subset S^3 = \Bd\!D^4$, let $\chi_s(L)$ be the greatest 
Euler characteristic $\chi(F)$ of an oriented 2-manifold $F$ (without closed components) 
smoothly embedded in $D^4$ with boundary $L$. 
```

等式も\$で囲われるし、一文字のものも\$で囲われる

例は、[https://arxiv.org/abs/math/9307233](https://arxiv.org/abs/math/9307233)から。いい加減に選んだだけです。

---
# 単語に分解
## 数式部分を隔離する
$\TeX$では、例えば、\$記号で囲った部分を数式部分と解釈される

空白が無しで、`foo$y=f(x)$bar`のように単語と数式がくっついていることがあるのを`foo` + `$y=f(x)$` + `bar`のように数式部分の前後を単語の切り目として切る

---
# 後は適当に学習

---
# ベクトルの近傍探索の例
入力: Resnetの論文のアブストラクト
結果:

```
1位 0.7645617723464966
Deep Residual Learning for Image Recognition
http://arxiv.org/abs/1512.03385v1

2位 0.6277217268943787
DiracNets: Training Very Deep Neural Networks Without Skip-Connections
http://arxiv.org/abs/1706.00388v1

3位 0.614996075630188
The Reversible Residual Network: Backpropagation Without Storing Activations
http://arxiv.org/abs/1707.04585v1

```

---

```

4位 0.6054012775421143
Truncating Wide Networks using Binary Tree Architectures
http://arxiv.org/abs/1704.00509v1

5位 0.602472186088562
Places205-VGGNet Models for Scene Recognition
http://arxiv.org/abs/1508.01667v1

6位 0.5984947085380554
Densely Connected Convolutional Networks
http://arxiv.org/abs/1608.06993v4

7位 0.5884192585945129
Face Detection with the Faster R-CNN
http://arxiv.org/abs/1606.03473v1
```

---

```
8位 0.5854528546333313
Deep Residual Networks with Exponential Linear Unit
http://arxiv.org/abs/1604.04112v4

9位 0.581209123134613
Wide Residual Networks
http://arxiv.org/abs/1605.07146v4

10位 0.5765923857688904
Inception-v4, Inception-ResNet and the Impact of Residual onnections on Learning
http://arxiv.org/abs/1602.07261v2
```

画像分類系の論文が見つかりました！

---

# ご清聴ありがとうございました