AdventCalendar
DeepLearning
LSTM
TensorFlow

自分のtweetを学習してbotを作りたかった。

ごあいさつ

はじめまして、tensorflowアドベントカレンダー2017の18日目でございます。
残念ながらうまくはいってないです。
余談って書いてあるところは本題に関係ないので流し読み推奨。

背景

もともと深層学習には興味があってちょいちょいCNNを弄ってたのと理論を少々。
最近自然言語処理に興味が出てきたのもあってLSTMとかやりたかった。
んで、ちょうどアドベントカレンダーがあるとのことで見切り発車で登録、せっかくだからLSTMをやろうという試み。

目標

余談

じゃあ何をやるかということで、かねてから自分の言葉を学習して自分と同じように喋るbotとか居たら面白いなと。
ゆくゆくは自分と同じように思考して話す、いわゆるクローンみたいなAIが生み出せたらマッドで素敵じゃん?

さて、兎にも角にも知識がないので調べてみると、LSTMを使って文章を作ろうみたいな試みは割とメジャーっぽい?
だけどそもそも言語が英語だったり、それも単語レベルじゃなくアルファベットレベルでのLSTMだったり
日本語でもいわゆる会話形式のbotだったりでなかなか思うようなものは見つからず。
もっとこう一人で延々とくだらないことを話してほしいのだが...

本題

目下の目標として、ある単語が与えられたときに次にどういう単語が来るのかをLSTMで学習させてみる。
データセットはもちろん自分の黒歴史集発言集ことtwitterから自分の全ツイートを使用することにした。

前処理

余談

twitterというと誰かのツイートを漁るとき、ある一定以上のツイートは読み込まれないようになっている。たぶん今もかな?
だから誰かのツイートで学習させたいときは、今のうちからアカウントを監視して逐一データとして保存していくとよろしい。
URLに直接アクセスとかでは見られるんだけどね。

本題

  • tweetの取得

PCのブラウザからtwitterにアクセスすると、全ツイートをリクエストできる。
Screenshot from 2017-12-17 11-32-17.png
右上の自分のアイコンをクリック、出てきたメニューから設定とプライバシーをクリックすると、ちょうど画像のようになる。
そしたら下の方にあるリクエストボタンをクリックすると、登録してあるメールアドレス宛にメールが来る。
そのメールの内容に従えばダウンロードできるはず。

ダウンロードしたzipを解凍すると中に色々入ってるけど、index.htmlにアクセスすると、今までのツイートを月ごとに見られる。
そこで表示されているツイートデータはdataフォルダの中を漁っていくと見つかる*.jsファイルにjsonデータとして格納されている。
そのjsファイル群を読み込んで使ってもいいんだけど、というか最初そういう風にやったらpython3なのに文字コード関連で死んだ。

よく見ると、解凍したフォルダの一番上にtweets.csvってのが入ってるのでそれを使うととっても楽です。体験談
pythonでcsvファイルをいじる方法は色々あるけど、pandasを使うのが一番幸せになれると思う。

  • tweetの前処理
    ダウンロードしたツイートデータには人によるけどそれなりにノイズが入ってると思う。
    リツイートした他人のツイート、午前惨事の茨城県などのbotツイート、URLを含むツイート、他人へのリプライなどなど
    他人へのリプをノイズとするかは人によるだろうけど、あくまで独り言を呟いてほしいので今回は除外した。
    まぁ、ツイートからついぞ@とリプ先を除去できなかったからってのもあるんだけど
    これらを前処理としてツイートデータからすべて除去した。これでほぼ純粋な自分の独り言集になる。なった。
    これでだいたい5万ツイートから3万ツイートほどへ。こいつ独り言多いな...

  • 形態素解析
    LSTMに文章を食わせる場合、多分二通りの方法があって
    一つが一文字ずつ食わせて単語も学習してもらう?方法
    もう一つが単語を食わせて学習してもらう方法
    今回はなんとなくだけどネット上のやってみた系だと文字ベースだったので、形態素解析して単語を食わせてみた。
    pymecabってのがあったのでそちらを使った。

mecab.py
from pymecab.pymecab import PyMecab
from readTweets import Read_Tweets


class Mecab:

    def write_tokens(self, tokens_list):
        with open('mecab_tweets.txt', 'w') as f:
            for tokens in tokens_list:
                text = [token.surface for token in tokens]
                text = ' '.join(text)
                f.write(text)
                f.write('\n')


    def do_mecab(self, tweets):
        mecab = PyMecab()
        tokens_list = [mecab.tokenize(tweet) for tweet in tweets]
        self.write_tokens(tokens_list)


def main():
    reader = Read_Tweets()
    tweets = reader.read_tweets('./tweets.csv')
    mecab = Mecab()
    mecab.do_mecab(tweets)


if __name__ == '__main__':
    main()

毎回形態素解析させるのもアホくさいので一旦これをテキストファイルに書き出して後ほど利用するようにした。

とりあえず前処理に関しては以上。

学習

実際にできたデータを食わせて学習させていくわけだけど、一体何をデータとして与えればいいかわからない。
やってみた系の記事を見ると、文章を渡すとその続きを書いてくれるらしいけど何か思ったのと違う...
ということでとりあえず何かしらの文章ができればいいやってことで、2つの連続する単語を渡すとその続きをどんどん書いていくようなものにしてみる。
具体的には学習データが単語1と単語2、ラベルデータが単語3としてみた。
多分このままだと全体としては支離滅裂になるだろうけど、部分的に繋がればいいやって感じで。
何かうまいツイート生成の学習方法なないだろうか...

データを作る部分に関しては以下のようにした。

train.py
def create_zero_vectors(tweet, strings):
    X = np.zeros((len(tweet), len(strings), len(strings)), dtype=np.bool)
    y = np.zeros((len(tweet), len(strings)), dtype=np.bool)
    return X, y

def vectorize(tweet, strings, index):
    X, y = create_zero_vectors(tweet, strings)
    for i in range(0, len(tweet)-2):
        X[i, index[tweet[i]], index[tweet[i+1]]] = 1
        y[i, index[tweet[i+2]]] = 1
    return X, y

def create_data(tweet, strings, index):
    X, y = vectorize(tweet, strings, index)
    return X, y

これに1ツイートずつ入れていく。
一気に大量のツイートを入れると圧倒的メモリ不足に陥るので、学習する際に毎回この流れでテンソルを作っていくようにした。

LSTMに関してはkerasを作ってサクッと層を作った。

train.py
model = Sequential()
model.add(LSTM(32, input_shape=(len(strings), len(strings))))
model.add(Dense(len(strings)))
model.add(Activation('softmax'))

とても楽、というかtensorflowでLSTMを作るのがよくわからなかった。

結果

こんな具合で学習を進めたかったけど、結果的にはうまくいかなかった。
というかそもそもまともに学習が進まなかった。
まず、データが重すぎてメモリ不足に陥った。
なんとかいろいろ削ってとりあえず動く状態にはなったけど、絶賛稼働中...

考察

まず単語ベクトルの要素数が多すぎる。
約23000次元
おそらく形態素解析の結果をそのままぶちこんだのがまずかった。
ディープラーニングとか自然言語処理に詳しい人に話を聞いてみるといろいろテクニックがあったりするらしい。
多分何かしらの方法で次元を減らす必要があると思う。
というかツイート数3万でひとつあたりのツイートが平均30文字と仮定すると、学習データが圧倒的に足りない気がする。

結論

圧倒的準備不足勉強不足だった。
けど前々からやってみたかったことなので、これからいろいろ知識を付けていきたい。
同じLSTMでも文字レベルでやったり、GANで文章生成する方法もあるらしいのでそっちをやってみたりしたい。

最後に

誰かツイートの学習をやってみてほしい。

一応ソースコードはこちら
https://github.com/coil398/tweetslstm