日本語極性判定を作って公開した～SentencePiece版～

## はじめに
[Apitore](https://apitore.com/)では[Word2Vec](https://apitore.com/store/apis/details?id=8)+RNN+LSTMによる[極性判定WebAPI](https://apitore.com/store/apis/details?id=11)を公開しています。そして先日、Googleの工藤さんが作った[SentencePieceのWebAPI](https://apitore.com/store/apis/details?id=38)も公開しました。今回は、この2つを組み合わせてみたいと思います。[SentencePiece版の極性判定技術](https://apitore.com/store/apis/details?id=39)です。

<img src="http://blog.apitore.com/wp-content/uploads/2017/05/amarec-20170514-082840.png" alt="" width="744" height="336" class="aligncenter size-full wp-image-1019" />


## デモサイト
- [みんなで改善するSocial Sentiment (kuromoji版)](https://mashup.apitore.com/social-sentiment/index.html)
- [極性判定 WebAPI (kuromoji版）](https://apitore.com/store/apis/details?id=11)
- [みんなで改善するSocial Sentiment V2 (SentencePiece版)](https://mashup.apitore.com/social-sentiment-v2/index.html)
- [極性判定V2 WebAPI (SentencePiece版）](https://apitore.com/store/apis/details?id=39)

## サンプルコード
※以前の極性判定WebAPIのプログラムで、エンドポイントを変えれば動きます

- [Java](https://github.com/keigohtr/apitore-response-parent/tree/master/word2vec-response)
- [Ruby](https://github.com/keigohtr/apitore-sdk-ruby/tree/master/api_11_sentiment)
- [AppleScript（ぴよまる様）](http://piyocast.com/as/archives/4289)

## 解説
アルゴリズムを箇条書きにします。

1. [Tweet版SentencePiece WebAPI](https://apitore.com/store/apis/details?id=38)で形態素解析っぽく分割
1. SentencePiece版のWord2Vecで200次元のベクトルに変換
1. RNN+LSTMでpositive/negative/neutralの3値に分類

### Tweet版のSentencePieceについて
技術内容というか実装としか、そういうのは[以前ブログ](http://blog.apitore.com/2017/04/26/api-sentencepiece-2/)でも解説しました。Google工藤さんによると、SentecePieceはドメイン依存性が高いそうなので[Tweet版SentencePiece WebAPI](https://apitore.com/store/apis/details?id=38)を新たに作りました。学習設定はWikipedia版のときと一緒で、出力は8000語です。

ツイートは以下の条件で集めました。だいたい200万ツイートです。

- 任意の目的語（人手で作成した約2500語）を含むツイート
- 20文字以上
- URLは含まない。リツイートは含まない。
- 投稿クライアントはTwitter公式（web、Android、iOS）

### SentencePiece単語をWord2Vecで変換
SentencePieceの出力8000語でOne-Hotベクトルを作ってRNN+LSTMで学習させたかったのですが、私のPC（メモリ16GB）ではOutOfMemoryになってしまって実行できませんでした。フレームワークはdeeplearning4jの最新版を使っているのですが、もしかしたらTensorFlow/Kerasなら実行できるのかもしれません。[Apitore](https://apitore.com/)はJavaでWebAPIを作っている関係でdeeplearning4jを使いました（近いうちにPythonでWebAPI作れるようにして、現状システムと統合できるようにします）。

仕方がないので、いったんWord2Vecを挟むことにします。SentencePieceの学習に使った約200万ツイートにSentencePieceを適用し、Word2Vecに流しました。Word2Vecの実行方法や設定は[以前ブログで紹介](http://blog.apitore.com/2016/09/22/deeplearning4j-word2vec-limitation-and-application/)しました。今回の設定は以下に示します。

Word2Vecの設定

- skip-gram
- 次元数 200
- window size 5
- 階層化ソフトマックス なし
- サンプリング 1e-3
- ネガティブサンプリング 5
- iteration 5
- 最小出現数 0

SentencePieceのVocabularyは8000語なのですが、200万ツイートのSentencePiece適用結果は7600語でした。

### RNN+LSTMでpositive/negative/neutralの3値に分類
学習データやアルゴリズムは以前の[極性判定で使ったものとほぼ同じ](http://blog.apitore.com/2016/10/20/deeplearning4j-word2vec-rnn/)です。Optimizerとかパラメータは多少変えましたが、相変わらずパラメータチューニングは厳密にはやっていません。あと、[本日投稿しているもう一つの記事](http://blog.apitore.com/2017/05/15/sentiment-neutral-data-reinforcement/)で紹介した方法でNeutralの学習データは補強してあります。

学習データ

|positive |negative |neutral |
|:------------:|:------------:|:------------:|
|18,462 |98,457 |75,660 |

評価データ

|positive |negative |neutral |
|:------------:|:------------:|:------------:|
|9,164 |33,915 |25,139 |

## 性能
性能は以下になります。ただし、以下の2点がありますので参考情報です。

1. Distant Supervisionで集めたデータが大半である
1. 学習データ≠評価データだが、評価データのスコアが最大になるように学習している

SentencePiece版の極性判定の性能

```
Examples labeled as 0 classified by model as 0: 7401 times
Examples labeled as 0 classified by model as 1: 520 times
Examples labeled as 0 classified by model as 2: 1243 times
Examples labeled as 1 classified by model as 0: 881 times
Examples labeled as 1 classified by model as 1: 31534 times
Examples labeled as 1 classified by model as 2: 1500 times
Examples labeled as 2 classified by model as 0: 1005 times
Examples labeled as 2 classified by model as 1: 568 times
Examples labeled as 2 classified by model as 2: 23566 times

 Accuracy:        0.9162
 Precision:       0.8864
 Recall:          0.8916
 F1 Score:        0.889
```

kuromoji版の極性判定（以前公開したやつ）の性能

```
Examples labeled as 0 classified by model as 0: 7048 times
Examples labeled as 0 classified by model as 1: 759 times
Examples labeled as 0 classified by model as 2: 1822 times
Examples labeled as 1 classified by model as 0: 2090 times
Examples labeled as 1 classified by model as 1: 28438 times
Examples labeled as 1 classified by model as 2: 3045 times
Examples labeled as 2 classified by model as 0: 1101 times
Examples labeled as 2 classified by model as 1: 1015 times
Examples labeled as 2 classified by model as 2: 23805 times

 Accuracy:        0.8578
 Precision:       0.82
 Recall:          0.8325
 F1 Score:        0.8262
```

パット見た感じだと以前公開した極性判定よりも性能が上がっているかのように見えます。が、実際に使った感じだと五分五分で、むしろ以前公開した極性判定の方が性能が良い印象があります。
※よく見ると、学習データの母体は同じものを使っているはずなのにデータ数が違います。コレガワカラナイ。たぶん、全部OOVになるデータは除外したとか（過去の賢い私が）やったんだと思います。

## 実際に使ってみた
色々と試してみましたが、なんかNeutralの分類が多いような・・・。あと、興味深い結果出ました笑

以下の例。合ってる。

```
  "text": "悲しみに暮れる ",
  "predict": {
    "sentiment": "negative",
    "score": 0.9625707864761353
  },
```

句点（。）ってポジティブ要素なの？

```
  "text": "悲しみに暮れる。",
  "predict": {
    "sentiment": "negative",
    "score": 0.5054083466529846
  },
```

繰り返すとニュートラルに！？

```
  "text": "悲しみに暮れる。悲しみに暮れる。",
  "predict": {
    "sentiment": "neutral",
    "score": 0.9570062756538391
  },
```

繰り返しすぎて楽しくなってきた！？

```
  "text": "悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。悲しみに暮れる。",
  "predict": {
    "sentiment": "positive",
    "score": 0.839227557182312
  },
```

あくまで一例で、全部がこういう傾向にあるわけじゃないです（「好き」とか「失敗した」とかだったら繰り返してもちゃんと出力します）。印象としてはほぼほぼニュートラルに分類してしまいますね。うーん、改善の余地ありです。


## おわりに
SentencePieceを極性判定に適用してみました。本当はOne-HotでRNNやりたかったんですが、メモリ足りなくて断念。
今回やった感想としては、kuromojiなどの形態素解析技術を用いる場合と比べ、SentencePieceは語彙数を強制的に抑えられます。というわけで、未知語だろうとなんだろうととりあえず機械学習に入力できてしまいます。このあたりが極性判定というタスクにおいてプラスに働くのかマイナスに働くのかは一概には言えないですが、むずかしいところですね。ツイートなんかを対象にする場合、文章はその時代ごとに変わってくるのでSentencePieceもWord2Vecも定期的にモデルを更新してやらないといけないかなと思います。
あと、今回の場合はDistant Supervisionがベースとなっているので、どうしても顔文字を過学習してしまいます（今回の実験では顔文字はある程度フィルタリングしました）。Distant Supervisionをやるときは気をつけないといけないポイントですね。学習データも適当にサンプリングして目を通してみましたが、うーんって感じです。間違いが結構多い。Twitter社の極性判定結果はあまり使えないかもしれないですね。別の顔文字でDistant Supervisionした方が良いかもしれません。


## 関連情報
- <a href="http://blog.apitore.com/2016/09/19/deeplearning4j-jwikipedia-word2vec/">deeplearning4jで日本語WikipediaのWord2Vecを作る</a>
- <a href="http://blog.apitore.com/2016/09/22/deeplearning4j-word2vec-limitation-and-application/">deeplearning4jのword2vecの限界とその上手な使い方</a>
- [deeplearning4jのdoc2vecで極性判定してみた](http://blog.apitore.com/2016/10/17/deeplearning4j-doc2vec-sentiment/)
- [deeplearning4jのdoc2vecにwikipediaのword2vecモデルを注入する](http://blog.apitore.com/2016/10/18/deeplearning4j-doc2vec-word2vec-injection/)
- [deeplearning4jでword2vecのベクトルデータからNNで極性判定してみる](http://blog.apitore.com/2016/10/19/deeplearning4j-word2vec-neuralnetwork-sentiment/)
- [deeplearning4jでword2vecのベクトルデータからRNNで極性判定してみる](http://blog.apitore.com/2016/10/20/deeplearning4j-word2vec-rnn/)
- [【API】日本語極性判定APIを公開しました](http://blog.apitore.com/2016/10/24/sentiment-classification-api/)
- [日本語極性判定技術のデモサイト作りました](http://blog.apitore.com/2016/10/25/ja-sentiment-classification-demo/)
- [deeplearning4jのRNNで極性判定を作った～Early Stop編～](http://blog.apitore.com/2016/11/01/deeplearning4j-rnn-sentiment-early-stop/)
- [deeplearning4jの極性判定でオンライン学習をやってみた](http://blog.apitore.com/2016/11/12/deeplearning4j-sentiment-online-learning/)
- [極性判定のニュートラルのデータを補強する](http://blog.apitore.com/2017/05/15/sentiment-neutral-data-reinforcement/)
- [【API】SentencePieceを極性判定に適用してみた](http://blog.apitore.com/2017/05/15/api-sentencepiece-sentiment/)
- [【アップデート情報】極性判定APIの精度改善](http://blog.apitore.com/2016/11/06/update-info-sentiment-api/)

## 極性辞書（レファレンス）

1. 小林のぞみ，乾健太郎，松本裕治，立石健二，福島俊一. 意見抽出のための評価表現の収集. 自然言語処理，Vol.12, No.3, pp.203-222, 2005. / Nozomi Kobayashi, Kentaro Inui, Yuji Matsumoto, Kenji Tateishi. Collecting Evaluative Expressions for Opinion Extraction, Journal of Natural Language Processing 12(3), 203-222, 2005.
1. 東山昌彦, 乾健太郎, 松本裕治, 述語の選択選好性に着目した名詞評価極性の獲得, 言語処理学会第14回年次大会論文集, pp.584-587, 2008. / Masahiko Higashiyama, Kentaro Inui, Yuji Matsumoto. Learning Sentiment of Nouns from Selectional Preferences of Verbs and Adjectives, Proceedings of the 14th Annual Meeting of the Association for Natural Language Processing, pp.584-587, 2008.

## その他関連（Qiita）
- [Twitter Stream APIデータに対して初歩的な感情分析を試みる](http://qiita.com/kenmatsu4/items/52ab6deffdd61e7d8c0f)
- [ディープラーニングを使って転職会議の企業クチコミデータを感情分析してみる](http://qiita.com/inuscript/items/54daa5aedde599e2637c)
- [深層学習でツイートの感情分析](http://qiita.com/hogefugabar/items/93fcb2bc27d7b268cbe6)