2018年03月22日

TensorFlowのハンズオンをしました

エモトです.先日,某作品のOVA・劇場版・最終章の三連続マサラ上映に参加しました.発生可能な応援上映に加えて,クラッカーや紙吹雪も大丈夫な上映形態,楽しくないわけがない.約3時間半ほど,クラッカーを発砲やイベントシーンのタイミングに合わせて鳴らしてました.次はあのシーンだなと右手で数個のクラッカーを持ち,左手でタイミングよく順々に鳴らしたときの達成感はなんともすごい.少しセーブしたものの,持ち込んだ200個のクラッカーでは足りなかった.劇場の音響の力に,クラッカーの音と火薬の匂いが混じり,とても楽しい時間でした.静かに映画を見るのも良いですが,わいわい見れる映画館も本当に良いですね.

運営協力している Kyoto.LT にて TensorFlow ハンズオンを行いました.

周りに機械学習する人・興味ある人が増えたらいいなと入門的なハンズオンをしたいと思っていましたが,環境構築で時間が終わりそうなので断念していました.そうしていたところ,Google Colab で GPU が利用できるようになったと聞き,これはやらねばということで,開催しました(実際は簡単なコードしか取り扱わなかったので CPU 計算で十分ですが).

ハンズオン資料はこちらで 公開 しています.各自の環境で ipynb ファイルを展開してもらえば,動くと思います.理論も紹介したいし,肝心のコードもやらないといけないと,時間が足りず中途半端な感じになっていますが,雰囲気を体験してもらえば幸いです.


posted by Seesaa京都スタッフ at 13:00| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする

2018年02月21日

TopicModelを使って,livedoorニュースコーパスを解析してみた

エモトです.さいきんバーフバリというインド映画にどハマりしました.インド映画特有の歌とダンスに加え,ストーリーやアクションシーンの完成度もすごい.出演陣も敵味方含めて全員かっこいい.敵役の中の人が私より年下だったことが一番の驚きでした.まだ見てない方は是非.オームシャンティオームやクリッシュもおすすめ.

Topic Modelとは

簡単に説明すると,文書は複数の潜在的なトピックから確率的に生成されると仮定したモデルです.下記に図例を示しました.この例では,ニュース記事は動物トピックとイベントトピックから文章が生成されて,特に動物トピックの影響が大きいのを示してます.なお,xxトピックと書いてますが,実際の計算ではトピックのラベル付けまで行われずに,計算終了後に別途でラベル付けを行います.

tm01.png

さて今回,そのTopic Modelを実装してみました.対象データは livedoor ニュースコーパス を使用しました.実装言語はPython,主な使用ライブラリはGensimを使用しています

1. データ作成

ニュースの本文を入力データ,カテゴリーをラベルとしました.本文はMeCabを使用して分かち書きにしました。なお、名詞と動詞の原形を使用しました。形容詞など他の品詞は、今回の実装では精度が上がらなかったのでデータから外しました。
docments = [["分かち書き", "された", "文章1"], ... ]
categories = ["文章1のカテゴリー", ...]
全データ7367件中,訓練データには9割,テストデータには1割を使用しました.

2. 実装

gensimのLDAmodel(Latent Dirichlet Allocation,潜在的ディリクレ配分法)を使用して実装しました.コードの一部を紹介します.なお,ストップワードの選定には,Slothlibのストップワード を使用しました.
from gensim import corpora
from gensim import models
from sklearn.model_selection import train_test_split

dictionary = corpora.Dictionary(documents)

# ストップワード
ignores = []
ignored_words_file = "./stop_words.txt"
with open(ignored_words_file, "r", encoding="utf-8") as f:
    ignores = [line.replace(os.linesep, "") for line in f]

# フィルタリング
dictionary.filter_extremes(no_below=20, no_above=0.5, keep_n=100000)
stop_ids = [dictionary.token2id[ig] for ig in ignores if ig in dictionary.token2id]
dictionary.filter_tokens(stop_ids)
dictionary.compactify()

コーパスデータを訓練とテストに分けて,LDAを学習します.学習時にトピック数を指定するのですが,今回は入力するカテゴリーと同数の9を設定しています.なお,学習メソッドのパラメータはヒューリスティックにいじって調整した値なので,本当に適正かどうかは不明です.
corpus = [dictionary.doc2bow(text) for text in documents]
x_train, x_test, y_train, y_test = train_test_split(corpus, categories, test_size=0.1, random_state=1)
    
lda = models.LdaModel(corpus=x_train, id2word=dictionary, num_topics=9, iterations=50, passes=20)

評価には,パープレキシティ,学習したトピックの上位語彙および分類結果を用いました.
def calc_perplexity(m, c):
    import numpy as np
    return np.exp(-m.log_perplexity(c))

# パープレキシティ
p = calc_perplexity(lda, x_test)

# 上位語彙
each_topics = []
for i in range(lda.num_topics):
    words = lda.show_topic(i, topn=topic_count)
    each_topics += [[w[0] for w in words]]

# 分類
for x in x_test:
    topics = lda.get_document_topics(x)
    top_topic = sorted(topics, key=lambda topic: topic[1], reverse=True)[0][0]

パープレキシティ(分類精度を示し,1に近いほど良い)です.訓練でさえ2000を超えているので,あまり良い分類精度ではないようでした.
訓練 テスト
2090.9748423332085 4603.607550110796

各カテゴリの上位語彙.学習したトピック(1列目)それぞれの上位5つの語彙を示してます.
topics 0 1 2 3 4
0 twitter ネット掲示板 情報 当選
1 使う 女子 人気 女性
2 話題 機能 見る 使う pc
3 思う 女性 結婚 男性 仕事
4 smartphone 対応 搭載 max 2012年
5 アプリ 更新 画面 表示 ソフトウェア
6 転職 写真 知る 仕事 得る
7 思う 選手 語る 日本 試合
8 映画 公開 作品 監督 本作

訓練データに対して,実際のラベル(1列目)がどのトピック(2列目以降)に分類されたかの表です.ニュースコーパスのカテゴリー分類に従えば,それぞれのデータ群が1つの固有トピックに集中するのが望ましい結果と言えるでしょう.
訓練 0 1 2 3 4 5 6 7 8
dokujo-tsushin 4 122 2 628 1 0 4 3 27
it-life-hack 52 12 385 20 66 107 121 8 15
kaden-channel 40 51 612 20 10 7 22 4 20
livedoor-homme 3 161 37 60 3 8 131 8 29
movie-enter 19 2 2 25 0 0 0 2 726
peachy 45 459 9 137 1 9 17 1 86
smax 5 11 22 0 416 334 0 0 3
sports-watch 38 2 0 28 0 0 1 728 5
topic-news 498 6 29 65 0 3 8 61 24

上記の結果をテストデータに対して行った結果.
テスト 0 1 2 3 4 5 6 7 8
dokujo-tsushin 0 9 0 66 0 0 1 0 3
it-life-hack 7 1 44 2 11 12 3 1 3
kaden-channel 5 6 54 4 1 4 1 1 2
livedoor-homme 1 25 9 5 0 0 19 2 10
movie-enter 0 0 0 3 0 0 0 0 91
peachy 2 48 1 13 0 2 1 0 11
smax 0 7 3 0 41 28 0 0 0
sports-watch 3 0 0 2 0 0 0 92 1
topic-news 56 1 1 9 0 0 0 7 2

分類結果の表から dokujo-tsushin と sports-watch と topic-news と movie-enter が上手に分類できるように見えます.しかしながら,トピック2は it-life-hack と kaden-channel が混在しました.ただ,その両者はもともと近しいジャンルのように見えるので,妥当な結果とも言えます.

HDP

ここで,LDAでトピックモデルを行ったとき,トピック数を指定して学習しました.例では入力データのカテゴリー数と同数を設定しましたが,本当にこのトピック数が適正な値かどうかは,わかりません.いくつもの候補を設定して,パープレキシティや分類結果を確認して決定する工程が必要になると思います.

その工程が面倒なので,HDP(Hierarchical Dirichlet Process,階層ディリクレ過程)を用いて,トピック数自体を推定しました.
# 推定トピック数の最大値はデフォルトで150に設定されている
hdp = models.hdpmodel.HdpModel(corpus, id2word=dictionary, alpha=0.1)

学習結果の評価は,こちら を参考に推定したトピックそれぞれの重みを加算して,比較しました.
def topic_prob_extractor(hdp, save_csv_file=None):
    import pandas as pd
    shown_topics = hdp.show_topics(num_topics=-1, formatted=False)
    topics_nos = [x[0] for x in shown_topics]
    weights = [sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos]
    data_frame = pd.DataFrame({'topic_id': topics_nos, 'weight': weights})
    if save_csv_file is not None:
        data_frame.to_csv(save_csv_file)
    return data_frame
hdp.png
最も重みが高い9が最適なトピック数となるでしょうか.25や50手前でいきなり重みがポンっと上がっているのがすごく気になります.

最適なトピック数は?

今回だと,最適なトピック数は9のようにみえます.しかしながら,より複雑なデータ(不特定多数が書いた,文章作成規則があいまい,など)を対象とした場合,HDPでも判定が難しい方が多いです.色々な質問サイト を眺めていると,はやりHDPでは決められずに,LDAの計算を反復して決定してるのをよく見かけます.

まとめ

Topic Modelのトピック数を幾つに設定することが大きな問題です.望ましい結果と比べて地道に設定していくことになると思います.しかしながら,Topic Modelは良い分類結果をもたらし,非常に興味深いですね.
posted by Seesaa京都スタッフ at 14:00| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする

2018年01月25日

fastText が Python をサポートしてた

エモトです.7.1ch最高かよ.引き続き通いたいと思ってます.

いぜんfastTextに関して,fastTextをPythonで使いたいならpyfasttext という記事を2017年10月に書いたように,fastTextはPythonを公式にサポートせず,公式サイトにも非公式のパッケージを使ってよという記載があったのを記憶してます.

ところが,fastText の readme を眺めていると, Building fastText for Python が追加されている.更新履歴を確認したところ,去年の11月あたりに追加されたようです.

$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ pip install .

pip1行で済まないのがちょっと気になりますが,非公式のパッケージは本家fastTextのバージョンアップに追いつかなくて利用できないことがあったので,公式で対応されたのは嬉しいことですね.

posted by Seesaa京都スタッフ at 17:31| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする