読者です 読者をやめる 読者になる 読者になる

TadaoYamaokaの日記

山岡忠夫 Home で公開しているプログラムの開発ネタを中心に書いていきます。

TF-IDFを使ってFAQに回答する

とある理由からBotについて調べています。

最近はAIを使ったBotもありますが、古典的な方法として、あらかじめ質問と回答を用意しておき、ユーザが入力した質問と類似度の高い質問を選んで回答する方法があります。

TF-IDFがその代表的なアルゴリズムになります。

ここでは、TF-IDFをPythonで実装する方法を示します。

scikit-learnにあるTfidfVectorizerクラスを利用することで、簡単に実装できます。
日本語を扱う場合は、あらかじめ形態素解析を行う必要があります。
形態素解析にはMeCab(mecab-python3)を使用します。

fit_transformで、形態素解析した質問文のセットを使用してモデルを学習します。
モデルを使用して質問文をベクトル化した結果が出力されます。

transformで学習したモデルを使用してユーザの入力文をベクトル化し、scikit-learnのcosine_similarity関数で入力文のベクトルと用意した質問文のベクトルのコサイン類似度を計算します。
最もコサイン類似度が高い質問を選択し、その回答を表示します。

コード例

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import MeCab

import argparse

parser = argparse.ArgumentParser(description="convert csv")
parser.add_argument("input", type=str, help="faq tsv file")
parser.add_argument("--dictionary", "-d", type=str, help="mecab dictionary")
parser.add_argument("--stop_words", "-s", type=str, help="stop words list")
args = parser.parse_args()

mecab = MeCab.Tagger("-Owakati" + ("" if not args.dictionary else " -d " + args.dictionary))

questions = []
answers = []
for line in open(args.input, "r", encoding="utf-8"):
    cols = line.strip().split('\t')
    questions.append(mecab.parse(cols[0]).strip())
    answers.append(cols[1])

stop_words = []
if args.stop_words:
    for line in open(args.stop_words, "r", encoding="utf-8"):
        stop_words.append(line.strip())

vectorizer = TfidfVectorizer(token_pattern="(?u)\\b\\w+\\b", stop_words=stop_words)
vecs = vectorizer.fit_transform(questions)

#for k,v in vectorizer.vocabulary_.items():
#    print(k, v)

while True:
    line = input("> ")
    if not line:
        break

    index = np.argmax(cosine_similarity(vectorizer.transform([mecab.parse(line)]), vecs))
    print(questions[index])
    print()
    print(answers[index])
    print()

TfidfVectorizerはデフォルトでは一文字の単語はトークンとして認識しませんが、日本語では一文字の単語(「雪」など)があるので、オプションで1文字もトークンとして認識するようにしています。

実行方法

>python tf_idf.py ..\data\faq.tsv -d H:\src\mecab-ipadic-neologd\build\mecab-ipadic-2.7.0-20070801-neologd-20170420 -s ..\data\stop_words.txt

引数にタブ区切りの質問と回答のテキストデータを指定し、オプションでMeCabの辞書とストップワードを指定しています。
ストップワードには、助詞や助動詞、連体詞、記号などを登録しておきます。

実行例

気象庁のよくある質問集で試した結果です。

> みぞれとは何ですか?
「 みぞれ 」 と は 何 です か ?

みぞれとは、雨と雪が混じったものをいいます。上空から雪が降ってくる途中、地上近くの気温が高いと、雪がとけて雨になります。一部分とけずに雪のまま落ちてくると、みぞれになります。みぞれは、観測分類上は雪に含めます。

> 台風とハリケーンの違いは?
台風 と ハリケーン と サイクロン の 違い は 何 です か ?

台風は、東経180度より西の北西太平洋および南シナ海に存在する熱帯低気圧のうち、最大風速が約17m/s以上になったものを指します。ハ リケーンは、北大西洋、カリブ海、メキシコ湾および西経180度より東の北東太平洋に存在する熱帯低気圧のうち、最大風速が約33m/s以上 になったものを指します。サイクロンは、ベンガル湾やアラビア海などの北インド洋に存在する熱帯低気圧のうち、最大風速が約17m/s以上に なったものを指します。このように、それぞれの名称を付している最大風速の基準には違いはありますが、台風もハリケーンもサイクロンもそれぞれの地域に存在する熱帯低気圧を強さによって分類している用語の1つということになります。なお、サイクロンは熱帯低気圧と温帯低気圧の区別をせず、広く低気圧一般を指す用語としても用いられることがあります。

> 異常気象について
「 異常気象 」 の 定義 は ある の です か ?

一般には、過去に経験した現象から大きく外れた現象のことを言います。大雨や暴風等の激しい数時間の気象から、数か月も続く干ばつ、極端な冷夏・暖冬まで含みます。また、気象災害も異常気象に含む場合があります。気象庁では、気温や降水量などの異常を判断する場合、原則として 「ある場所(地域)・ある時期(週、月、季節)において30年に1回以下で発生する現象」を異常気象としています。


文章における単語の重要度を見ているので、全文検索よりは精度が高くなりますが、古典的な方法であり類似語や質問の意味は解釈しません。
FAQに回答する場合では、これでも十分実用的です。

64bitのWindowsにMeCabをインストールする

MeCabの公式のサイトではWindows用は32bitのインストーラしか提供されていないため、64bitのWindowsで64bitのPythonから使おうとすると使用できない。

64bit向けには、32bitのインストーラでインストールした後、個別にビルドしたファイルで実行ファイルとライブラリを置き換える必要がある。
qiita.com
こちらのサイトに書かれていた方法で、ビルドして、Python3から使用することができた。

ただし、環境変数MECABRCがないと、pythonコマンドからMeCabを使用したスクリプトを実行すると、

Traceback (most recent call last):
  File "a.py", line 3, in <module>
    mecab = MeCab.Tagger("-Owakati")
  File "h:\src\mecab-python3\MeCab.py", line 307, in __init__
    this = _MeCab.new_Tagger(*args)
RuntimeError

というエラーが出力される。

その場合、環境変数MECABRCに、

<インストールパス>\etc\mecabrc

を設定すればよい。

mecab-ipadic-NEologdを使う

mecab-ipadic-NEologdを使うには、まずBash on Windowsmecab-ipadic-NEologdをインストールする。
github.com
公式に書かれている手順通りでインストールできる。
その際、git cloneするディレクトリは、Windowsから見えるパスにする。(/mnt/ドライブ名/~)

Bash on Windowsにインストールした際に、git cloneしたディレクトリ配下に
「build\mecab-ipadic-2.7.0-20070801-neologd-20170420」
というディレクトリができる。
このディレクトリを辞書として指定すれば、Windows側のMeCabでも使用できる。
ただし、辞書の文字コードは「UTF-8」となる。
Python3から使う分には問題ない。

import MeCab

mecab = MeCab.Tagger(r"-Owakati -d H:\src\mecab-ipadic-neologd\build\mecab-ipadic-2.7.0-20070801-neologd-20170420")

print(mecab.parse("私はペンを持っています。"))

このように「-d」オプションに辞書のパスを指定する。

AIで質問の回答を選ぶ

ディープラーニングを使って自然言語の質問に、自然言語の選択肢から回答することを試します。

例えば、
Which of the following is the primary advantage of sexual reproduction when compared to asexual reproduction?
という質問文に、
(A) There is a greater number of offspring.
(B) There is more food available to offspring.
(C) There is greater genetic variety in offspring.
(D) There is a longer development time for offspring.
という選択肢から回答します。(答えは、C)


試すのは以下の論文の方法です。
[1511.04108] LSTM-based Deep Learning Models for Non-factoid Answer Selection

質問と回答をそれぞれLSTMに入力して出力ベクトルのコサイン値のヒンジ損失を最小化するように学習します。

質問と回答は自然言語のため、単語単位にword2vecでベクトル化(Word Embedding)を行い、LSTMに入力します。

LSTMの出力を平均もしくは最大プーリングした出力ベクトルのコサイン値について、正解と不正解のマージンを最大化(ヒンジ損失を最小化)します。


これを一から実装するのは大変そうなので、公開されている実装がないか調べたところ、Kerasでの実装が見つかりました。
github.com

ただし、この実装は質問と回答のLSTMの出力ベクトルをマージして正解か不正解かを2値で出力し、損失関数をcategorical_crossentropyとしています。

どちらの方がよいかは実験してみないとわかりませんが、とりえずこのKerasの実装を試してみました。

準備

適当な作業ディレクトリに移動して、gitでリポジトリをcloneします。

git clone https://github.com/sujitpal/dl-models-for-qa.git

README.mdに書かれているとおり、データセットとモデル格納用のディレクトリを作成します。

cd dl-models-for-qa
mkdir data
cd data
mkdir comp_data
mkdir models

データセットダウンロード

README.mdに書かれている「AI2 8th Grade Science Questions (No Diagrams)」データセットをダウンロードします。
リンク先のURLでは見つからなかったので、以下の場所から入手しました。
dataset-sts/data/hypev/ai2-8grade at master · brmson/dataset-sts · GitHub
に書かれている
http://aristo-public-data.s3.amazonaws.com/AI2-8thGr-NDMC-Feb2016.zip
をダウンロードします。

ダウンロードしたzipに含まれる8thGr-NDMC-Train.csvを使用します。

データの加工

ダウンロードしたファイルはそのままではファイル形式が異なるため使用できません。

No. <tab> 質問文 <tab> 正解 <tab> 回答文A <tab> 回答文B <tab> 回答文C <tab> 回答文D

という形式に加工します。

以下のようなスクリプトでカンマ区切りのCSVをタブ区切りに変換した後、テキストエディタ正規表現置換で回答の選択肢を分割して、Excelで列を並べ替えました。

import argparse
import pandas as pd
import re

parser = argparse.ArgumentParser(description='convert csv')
parser.add_argument('input', type=str, help='input')
parser.add_argument('output', type=str, help='output')
args = parser.parse_args()

df = pd.read_csv(args.input)
df.to_csv(args.output, sep='\t', columns=('AnswerKey', 'question'), header=False, index=False)

文字化けする行があったので削除しました。
保存するときは改行コードをLFにする必要があります。

加工したファイルを、上記で作成したcomp_dataディレクトリに格納します。

Word2Vecの学習済みモデルのダウンロード

単語のベクトル化(Word Embedding)には、word2vecの学習済みモデルを使用します。
README.mdに書かれているGoogleNews Word2Vec modelから、GoogleNews-vectors-negative300.bin.gzをダウンロードして、上記で作成したcomp_dataディレクトリに格納します。

Python3用にスクリプト修正

Python3を使用している場合は、Python2用のコードになっているため修正が必要です。
フォークして修正したレポジトリを公開しました。
GitHub - TadaoYamaoka/dl-models-for-qa: Keras DL models to answer 8th grade science multiple choice questions (Kaggle AllenAI competition).

学習実行

srcディレクトリに移動して学習用スクリプトを実行します。
複数アルゴリズムが実装されていますが、今回は「QA-LSTM with Attention」を試しました。

python qa-lstm-attn.py

以下のように結果が表示されます。

C:\Anaconda3\lib\site-packages\gensim\utils.py:860: UserWarning: detected Windows; aliasing chunkize to chunkize_serial
  warnings.warn("detected Windows; aliasing chunkize to chunkize_serial")
Using TensorFlow backend.
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cublas64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cudnn64_5.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cufft64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library nvcuda.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library curand64_80.dll locally
Loading and formatting data...
(805, 393) (345, 393) (805, 393) (345, 393) (805, 2) (345, 2)
Loading Word2Vec model and generating embedding matrix...
Building model...
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "BestSplits" device_type: "CPU"') for unknown op: BestSplits
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "CountExtremelyRandomStats" device_type: "CPU"') for unknown op: CountExtremelyRandomStats
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "FinishedNodes" device_type: "CPU"') for unknown op: FinishedNodes
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "GrowTree" device_type: "CPU"') for unknown op: GrowTree
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ReinterpretStringToFloat" device_type: "CPU"') for unknown op: ReinterpretStringToFloat
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "SampleInputs" device_type: "CPU"') for unknown op: SampleInputs
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ScatterAddNdim" device_type: "CPU"') for unknown op: ScatterAddNdim
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNInsert" device_type: "CPU"') for unknown op: TopNInsert
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNRemove" device_type: "CPU"') for unknown op: TopNRemove
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TreePredictions" device_type: "CPU"') for unknown op: TreePredictions
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "UpdateFertileSlots" device_type: "CPU"') for unknown op: UpdateFertileSlots
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 1080
major: 6 minor: 1 memoryClockRate (GHz) 1.8225
pciBusID 0000:01:00.0
Total memory: 8.00GiB
Free memory: 6.63GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1080, pci bus id: 0000:01:00.0)
qa-lstm-attn.py:73: UserWarning: The `Merge` layer is deprecated and will be removed after 08/2017. Use instead layers from `keras.layers.merge`, e.g. `add`, `concatenate`, etc.
  attn.add(Merge([qenc, aenc], mode="dot", dot_axes=[1, 1]))
qa-lstm-attn.py:79: UserWarning: The `Merge` layer is deprecated and will be removed after 08/2017. Use instead layers from `keras.layers.merge`, e.g. `add`, `concatenate`, etc.
  model.add(Merge([qenc, attn], mode="sum"))
Training...
C:\Anaconda3\lib\site-packages\keras\models.py:834: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.
  warnings.warn('The `nb_epoch` argument in `fit` '
Train on 724 samples, validate on 81 samples
Epoch 1/20
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\pool_allocator.cc:247] PoolAllocator: After 37467 get requests, put_count=9098 evicted_count=1000 eviction_rate=0.109914 and unsatisfied allocation rate=0.786532
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\pool_allocator.cc:259] Raising pool_size_limit_ from 100 to 110
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\pool_allocator.cc:247] PoolAllocator: After 7998 get requests, put_count=16010 evicted_count=8000 eviction_rate=0.499688 and unsatisfied allocation rate=0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\pool_allocator.cc:247] PoolAllocator: After 17994 get requests, put_count=36006 evicted_count=18000 eviction_rate=0.499917 and unsatisfied allocation rate=0
(略)
Epoch 20/20
704/724 [============================>.] - ETA: 0s - loss: 0.0199 - acc: 0.9986Epoch 00019: val_loss did not improve
724/724 [==============================] - 21s - loss: 0.0195 - acc: 0.9986 - val_loss: 2.9519 - val_acc: 0.6543
Evaluation...
345/345 [==============================] - 1s
Test loss/accuracy final model = 2.7262, 0.6638
345/345 [==============================] - 1s
Test loss/accuracy best model = 0.6961, 0.7275

最終的なTest accuracyが、0.6638になっています。
README.mdより良い結果ですが、データセットの差と思われます。

README.mdの「QA-LSTM with Attention + Custom Embedding」ではさらに精度が上がっているので、word2vecのモデルを最適化すればさらに精度があがるようです。


この方法を応用することで、質問に回答するBotなどが作れると思います。
この実装で使用できるのは英語のみなので、日本語処理はこれとは別に対応が必要になります。

WindowsでKerasを使う

とある理由でKerasを使い始めました。
備忘録を兼ねてWindowsでバックエンドにTensorFlowを使用してKerasを使う方法について書きます。

環境

  • Windows 10 Home 64bit
  • Python 3.5.2(Anaconda 4.2.0 (64-bit))
  • Tensorflow-gpu (1.0.1)
  • Keras (2.0.3)

TensorFlowのインストール

まず、WindowsにTensorFlowをインストールします。
インストール手順は以前書いた日記を参考にしてください。
tadaoyamaoka.hatenablog.com

Kerasのインストール

コマンドプロンプトまたは、PowerShellから、

pip install keras

pythonコマンドでインタープリタを起動して、

import keras
keras.__version__

で、

'2.0.3'

と表示されればインストール成功です。

MNISTサンプルの実行

まず初めに行うことと言ったらMNISTサンプルの実行です。

コマンドプロンプトまたはPowerShellで適当な作業ディレクトリに移動して、リポジトリをcloneします。

git clone https://github.com/fchollet/keras.git

MNISTサンプルを実行します。

cd keras
cd examples
python mnist_mlp.py

実行結果は、以下のようになります。

Using TensorFlow backend.
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cublas64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cudnn64_5.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cufft64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library nvcuda.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library curand64_80.dll locally
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz
60000 train samples
10000 test samples
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "BestSplits" device_type: "CPU"') for unknown op: BestSplits
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "CountExtremelyRandomStats" device_type: "CPU"') for unknown op: CountExtremelyRandomStats
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "FinishedNodes" device_type: "CPU"') for unknown op: FinishedNodes
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "GrowTree" device_type: "CPU"') for unknown op: GrowTree
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ReinterpretStringToFloat" device_type: "CPU"') for unknown op: ReinterpretStringToFloat
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "SampleInputs" device_type: "CPU"') for unknown op: SampleInputs
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ScatterAddNdim" device_type: "CPU"') for unknown op: ScatterAddNdim
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNInsert" device_type: "CPU"') for unknown op: TopNInsert
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNRemove" device_type: "CPU"') for unknown op: TopNRemove
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TreePredictions" device_type: "CPU"') for unknown op: TreePredictions
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "UpdateFertileSlots" device_type: "CPU"') for unknown op: UpdateFertileSlots
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
dense_1 (Dense)              (None, 512)               401920
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0
_________________________________________________________________
dense_2 (Dense)              (None, 512)               262656
_________________________________________________________________
dropout_2 (Dropout)          (None, 512)               0
_________________________________________________________________
dense_3 (Dense)              (None, 10)                5130
=================================================================
Total params: 669,706
Trainable params: 669,706
Non-trainable params: 0
_________________________________________________________________
Train on 60000 samples, validate on 10000 samples
Epoch 1/20
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 1080
major: 6 minor: 1 memoryClockRate (GHz) 1.8225
pciBusID 0000:01:00.0
Total memory: 8.00GiB
Free memory: 6.63GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1080, pci bus id: 0000:01:00.0)
60000/60000 [==============================] - 3s - loss: 0.2445 - acc: 0.9252 - val_loss: 0.1483 - val_acc: 0.9543
(略)
Epoch 20/20
60000/60000 [==============================] - 1s - loss: 0.0177 - acc: 0.9953 - val_loss: 0.1100 - val_acc: 0.9841
Test loss: 0.110033185067
Test accuracy: 0.9841
CNN版

上記で学習したのは隠れ層が2層のパーセプトロン(MLP)なので、次は畳み込みニューラルネットワーク(CNN)を試します。

python mnist_cnn.py

以下のように結果が表示されます。

Using TensorFlow backend.
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cublas64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cudnn64_5.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library cufft64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library nvcuda.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:135] successfully opened CUDA library curand64_80.dll locally
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "BestSplits" device_type: "CPU"') for unknown op: BestSplits
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "CountExtremelyRandomStats" device_type: "CPU"') for unknown op: CountExtremelyRandomStats
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "FinishedNodes" device_type: "CPU"') for unknown op: FinishedNodes
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "GrowTree" device_type: "CPU"') for unknown op: GrowTree
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ReinterpretStringToFloat" device_type: "CPU"') for unknown op: ReinterpretStringToFloat
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "SampleInputs" device_type: "CPU"') for unknown op: SampleInputs
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "ScatterAddNdim" device_type: "CPU"') for unknown op: ScatterAddNdim
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNInsert" device_type: "CPU"') for unknown op: TopNInsert
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TopNRemove" device_type: "CPU"') for unknown op: TopNRemove
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "TreePredictions" device_type: "CPU"') for unknown op: TreePredictions
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_kernel.cc:943] OpKernel ('op: "UpdateFertileSlots" device_type: "CPU"') for unknown op: UpdateFertileSlots
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 1080
major: 6 minor: 1 memoryClockRate (GHz) 1.8225
pciBusID 0000:01:00.0
Total memory: 8.00GiB
Free memory: 6.63GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1080, pci bus id: 0000:01:00.0)
60000/60000 [==============================] - 6s - loss: 0.3410 - acc: 0.8981 - val_loss: 0.0830 - val_acc: 0.9747
(略)
Epoch 12/12
60000/60000 [==============================] - 5s - loss: 0.0380 - acc: 0.9886 - val_loss: 0.0282 - val_acc: 0.9909
Test loss: 0.0282454267572
Test accuracy: 0.9909

Test accuracy: 0.9909と、MLPの0.9841より精度が上がっています。

サンプルを続けて実行すると、最後に

Exception ignored in: <bound method BaseSession.__del__ of <tensorflow.python.client.session.Session object at 0x00000235B0A0EEB8>>
Traceback (most recent call last):
  File "C:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py", line 582, in __del__
AttributeError: 'NoneType' object has no attribute 'TF_DeleteStatus'

というエラーが出力される場合があります。

実行が終わった後なので特に問題ありませんが、コードの末尾に

import gc; gc.collect()

と記述するとエラーが出なくなるようです。
python - Tensorflow AttributeError: 'NoneType' object has no attribute 'TF_DeleteStatus' - Stack Overflow

Windows(Bash on Windows)でfastTextを使う

word2vecより高速で学習できて精度がよいというfastTextを試してみました。

環境

学習用データの準備

確認用にコンパクトなデータセットとして、Wikipediaの全ページの要約のデータを使用した。

Index of /jawiki/latest/
から、jawiki-latest-abstract.xml をダウンロードする。

XMLファイルからテキストを抽出するため、
GitHub - icoxfog417/fastTextJapaneseTutorial: Tutorial to train fastText with Japanese corpus
こちらのツールを使用させていただいた。

$ git clone https://github.com/icoxfog417/fastTextJapaneseTutorial.git 
$ cd fastTextJapaneseTutorial
$ mkdir source
$ mkdir corpus

sourceディレクトリにダウンロードしたjawiki-latest-abstract.xmlを格納し、

$ python3 parse.py source/jawiki-latest-abstract.xml --extract

corpus/abstracts.txt
に抽出したテキストが保存される。

形態素解析

日本語のテキストはそのままでは使用できないため、MeCabを使用して単語に分割する。

Bash on WindowsMeCabをインストールする。

$ sudo apt-get install mecab libmecab-dev mecab-ipadic
$ sudo aptitude install mecab-ipadic-utf8
$ sudo apt-get install python-mecab

テキストを単語に分割する。

$ mecab corpus/abstracts.txt -O wakati -o data.txt

単語に分割した結果が、data.txtに保存される。

fastTextのインストール

事前に、make、g++をインストールしておく。

適当な作業ディレクトリで、

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

fastTextで学習

$ ./fasttext skipgram -input path/to/data.txt -output model -dim 100

「-dim」オプションに次元を指定する。
小さめのコーパスのため最小の100とした。

model.binとmodel.vecが出力される。

学習済みモデルを使用

Pythonから使用するには、gensimを使用する。
gensimはfastTextのモデルの読み込みにも対応している。

$ sudo pip3 install gensim

で、gensimをインストールする。

pythonで以下のスクリプトを実行する。

from gensim.models.wrappers.fasttext import FastText
model = FastText.load_fasttext_format('model')
model.most_similar(positive = ["王様","女性"], negative = ["男性"], topn = 3)

王様 - 男性 + 女性の結果が表示される。

[('おかえり', 0.6713434457778931), ('恋', 0.6410529613494873), ('おんな', 0.6355608701705933)]

Wikipediaの全ページの要約のデータではあまり期待した結果にはならなかった。。。

強化学習の教科書

昨日の日記で強化学習の勉強を始めたと書いたが、教科書についてまとめておく。

購入した教科書は、昨日の日記で取り上げた

と、TD学習を発案した著者による

この本である。

強化学習を体系的に記述してあり、本格的に学ぶなら後者の本がよいと思う。ただし、内容は難しい。
前者の本はサンプルプログラムも付いているので、動かしながら学べるのが良いと思う。

ちなみに、後者の本は翻訳本で、原書のSecond EditionのDraftのPDFがオンラインで読める。
Sutton & Barto Book: Reinforcement Learning: An Introduction

翻訳本の元の版の内容を全て含んでいる。
英語での表現を知りたければ翻訳本と対比してみるとよいと思う。

Second Editionでは、AlphaGoのRL policy networkの学習で用いられた手法である、REINFORCEアルゴリズムについても「13.4 REINFORCE with Baseline」で取り上げられている。

ホームページのデザイン変更

わりとどうでも良い話ですがホームページのデザインを変更しました。

はてなブログに記事を書き始めてからほとんど更新しなくなっていますが、90年代のようなデザインを直したいと思っていました。

最近CSSフレームワークの存在を知ったので、人気があるらしいBootstrapを適用してみた。

変更前

f:id:TadaoYamaoka:20170415224928p:plain

変更後

f:id:TadaoYamaoka:20170415225147p:plain

ちょっとモダンになった。
内容はまったく変わっていません。。。