昨日のコピペしていったコードを見ていきたいと思います。
前処理
まずは必要なライブラリのimportとテキストの読み込みから。
from __future__ import print_function import mxnet as mx from mxnet import nd, autograd import numpy as np mx.random.seed(1) with open("all_kaiseki.txt") as f: text = f.read() print(text[0:500])
実行結果はこんな感じです。
tweet "# アイドル修業中 ♡ 公演 来 て くれ て 、 見 て くれ て 、 ありがとう ござい た ???! ドラフト 3 期生 の # 齋藤 陽 菜 ちゃん ( は ー たん )( 1 枚 目 ) と # 石綿 星 南 ちゃん ( せ な たん )( 2 枚 目 )
character_list = list(set(text)) vocab_size = len(character_list) print(character_list[:-10]) print("Length of vocab: %s" % vocab_size)
単語ごとにリストの中に入れている様子ですね。
['確', '…', '濃', 'k', '葉', '하', '‥', 'ん', '敷', '運', '瞬', '勉', '毎', '礼', '第', '賢', '晴', '연', '肯', '益', '抱', 'A', '員', '経', '!', '라', 'ー', '警', '束', '落', '代', '資', '蔵', '惜', '失', '炎', '⑱', 'ー', '冷', '투', '繋', 'ナ', 'バ', '茂', '容', '尽', 'テ', 'む', '団', '当']
それで次に各文字ごとにIDをふっています。
character_dict = {} for e, char in enumerate(character_list): character_dict[char] = e print(character_dict)
インデックスと文字を辞書にして取り出せるようにしています。
time_numerical = [character_dict[char] for char in text] print(len(time_numerical)) print(time_numerical[:20]) print("".join([character_list[idx] for idx in time_numerical[:50]]))
実行結果。
256514 [933, 1537, 870, 870, 933, 744, 1272, 1240, 744, 1492, 1074, 153, 130, 1594, 1885, 1607, 744, 898, 744, 1679] tweet "# アイドル修業中 ♡ 公演 来 て くれ て 、 見 て くれ て 、 ありがとう
コンピュータが読み込めるようにワンホットエンコーディングを処理してます。
def one_hots(numerical_list, vocab_size=vocab_size): result = nd.zeros((len(numerical_list), vocab_size)) for i, idx in enumerate(numerical_list): result[i, idx] = 1.0 return result print(one_hots(time_numerical))
[[ 0. 0. 0. ..., 0. 0. 0.] [ 0. 0. 0. ..., 0. 0. 0.] [ 0. 0. 0. ..., 0. 0. 0.] ..., [ 0. 0. 0. ..., 0. 0. 0.] [ 0. 0. 0. ..., 0. 0. 0.] [ 0. 0. 0. ..., 0. 0. 0.]] <NDArray 256514x1886 @cpu(0)>
すごい行列数になっていますが0と1に変換できました。 テキストに戻すには次のコード。
def textify(embedding): result = "" indices = nd.argmax(embedding, axis=1).asnumpy() for idx in indices: result += character_list[int(idx)] return result textify(one_hots(time_numerical[:50]))
学習の開始
ここから学習です。 シークエンスの長さはtweetが140なので、140に設定しておきます(正しいかはわかりません)。
seq_length = 140 num_samples = (len(time_numerical) - 1) // seq_length dataset = one_hots(time_numerical[:seq_length*num_samples]).reshape((num_samples, seq_length, vocab_size)) textify(dataset[1])
実行結果
') が 劇場 フル 出演 デビュー でし た ~!✨ 出 て くれ … https :// t . / PuFkSwSEnZ " " 今日 は # 山根 涼 羽 ずん ちゃんと 、 カフェ に 行っ たり お 買い物 し た ☕?? 大切 な 同期 と の 時間 で とっても'
次はbatch_sizeを決めるのですが、batch_sizeって何だって話ですが、どうやら学習させる単位のまとまりだそうです。 どのくらいの数を指定すればいいのかわからないので256を指定します。
batch_size = 256 print('# of sequences in dataset: ', len(dataset)) num_batches = len(dataset) // batch_size print('# of batches: ', num_batches) train_data = dataset[:num_batches*batch_size].reshape((batch_size, num_batches, seq_length, vocab_size)) # swap batch_size and seq_length axis to make later access easier train_data = nd.swapaxes(train_data, 0, 1) train_data = nd.swapaxes(train_data, 1, 2) print('Shape of data set: ', train_data.shape)
# of sequences in dataset: 1832 # of batches: 7 Shape of data set: (7, 140, 256, 1886)
次のコードにいきます。
labels = one_hots(time_numerical[1:seq_length*num_samples+1]) train_label = labels.reshape((batch_size, num_batches, seq_length, vocab_size)) train_label = nd.swapaxes(train_label, 0, 1) train_label = nd.swapaxes(train_label, 1, 2) print(train_label.shape)
数値をいろいろ操作しているようです。nd.swapaxesは軸の入れ替えをしているようです。目的は不明。 実行するとこんな感じになります。
(7, 140, 256, 1886)
次はパラメーターの設定。各パラメータが何を意味しているのか謎です。
num_inputs = vocab_size num_hidden = 256 num_outputs = vocab_size Wxh = nd.random_normal(shape=(num_inputs,num_hidden)) * .01 Whh = nd.random_normal(shape=(num_hidden,num_hidden)) * .01 bh = nd.random_normal(shape=num_hidden) * .01 Why = nd.random_normal(shape=(num_hidden,num_outputs)) * .01 by = nd.random_normal(shape=num_outputs) * .01 params = [Wxh, Whh, bh, Why, by] for param in params: param.attach_grad()__
次にsoftmax関数の作成。これは出力される値を確率に変換する式のことをSoftmaxというらしいです。 ここまできたらやっとrnnの実装。
def simple_rnn(inputs, state, temperature=1.0): outputs = [] h = state for X in inputs: h_linear = nd.dot(X, Wxh) + nd.dot(h, Whh) + bh h = nd.tanh(h_linear) yhat_linear = nd.dot(h, Why) + by yhat = softmax(yhat_linear, temperature=temperature) outputs.append(yhat) return (outputs, h)
思ったよりも楽ではなかったMXnetでした。流れが掴めたのでよしとします。
今日の結果
今日の呟きは82件でした。
'嬉しい': 12, '可愛い': 8, '楽しい': 6, 'よい': 4, '良い': 3, '早い': 2, 'ほしい': 2, 'つらい': 1, '美味しい': 1, 'おしい': 1, 'あざとい': 1, '無い': 1, 'すごい': 1, 'すっごい': 1, 'よろしい': 1, 'いい': 1, 'はやい': 1, 'たのしい': 1, '多い': 1, '新しい': 1, '古い': 1, '遅い': 1, '肌寒い': 1, 'ない': 1 '部': 44, 'アクシュカイ': 43, '名古屋': 36, '今日': 25, 'レーン': 16, '月': 15, '嬉しい': 12, 'さん': 11, '皆さん': 10, 'なごや': 9, '方': 9, '可愛い': 8, '日': 8, '券': 8, 'ちゃん': 7, 'ん': 7, '朝': 7, '当日': 7, '楽しい': 6, 'お願い': 6, 'の': 6, 'たくさん': 6, 'さ': 5, 'みなさん': 5, '個別': 5, '雨': 5, '私服': 5, '握手': 5, '時間': 5 '部': 44, 'アクシュカイ': 43, '名古屋': 36, 'する': 30, '今日': 25, 'くださる': 17, 'レーン': 16, '月': 15, '来る': 15, 'なる': 14, '嬉しい': 12, 'さん': 11, '皆さん': 10, 'てる': 10, 'なごや': 9, '方': 9, '可愛い': 8, '日': 8, '券': 8, 'くれる': 8, 'ちゃん': 7, 'ん': 7, '朝': 7, '当日': 7, 'すぎる': 7, 'いる': 7, '会う': 7,
要約するとこんな感じです。
ポートメッセ 名古屋 握手会 朝 から 来 て くださっ た 方 ありがとう ござい た ☺ ️ ✨ 朝 から な のに いっぱい 来 て くれ て 嬉しかっ た よ ~ 舞台 も いく ね ! って 待っ てる ね ?❤ ️ 9 / 7 の 15 時 〜 の チケット が まだ 沢山 余っ てる ので 皆さん 来 … 今日 は 、 名古屋 握手会 ありがとう ござい た ? 本日 の 握手会 会場 。 薄着 し て た メンバー は 肌寒 さ から ブランケット を 羽織っ たり し て い た の が 、 なぜ か 私 の レーン に は 扇風機 が ! ! 汗 っ かき な の ばれ てる 、 、 ! ( 笑 ) ( 今日 は 出番 は なかっ た が ?