毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/09/10【79日目】LSTMでbotをいじってみる

会話データをひとまず100個作りましたので、実装していきたいと思います。 コードはGithub上のものを参考にしています(というよりそのまま)

github.com

01_preprocessing.pyの場所

from pickle import load
from pickle import dump
from numpy.random import rand
from numpy.random import shuffle
from numpy import loadtxt

# load a clean dataset
def load_clean_sentences(filename):
    return load(open(filename, 'rb'))

# save a list of clean sentences to file
def save_clean_data(sentences, filename):
    dump(sentences, open(filename, 'wb'))
    print('Saved: %s' % filename)

# load dataset
a = loadtxt('sample_conversations.csv', delimiter=',', dtype=str)

# reduce dataset size
n_sentences = 29
dataset = a[:n_sentences, :]

# random shuffle
shuffle(dataset)

# split into train/test
train, test = dataset[:29], dataset[29:]

# save
save_clean_data(dataset, 'both.pkl')
save_clean_data(train, 'train.pkl')
save_clean_data(test, 'test.pkl')

02_training.pyのところ。

from pickle import load
from numpy import array
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.utils import to_categorical
from keras.utils.vis_utils import plot_model
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import Embedding
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.callbacks import ModelCheckpoint

# load a clean dataset
def load_clean_sentences(filename):
    return load(open(filename, 'rb'))

# fit a tokenizer
def create_tokenizer(lines):
    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(lines)
    return tokenizer

# max sentence length
def max_length(lines):
    return max(len(line.split()) for line in lines)

# encode and pad sequences
def encode_sequences(tokenizer, length, lines):
    # intereply encode sequences
    X = tokenizer.texts_to_sequences(lines)
    # pad sequences with 0 values
    X = pad_sequences(X, maxlen=length, padding='post')
    return X

# one hot encode target sequence
def encode_output(sequences, vocab_size):
    ylist = list()
    for sequence in sequences:
        encoded = to_categorical(sequence, num_classes=vocab_size)
        ylist.append(encoded)
    y = array(ylist)
    y = y.reshape(sequences.shape[0], sequences.shape[1], vocab_size)
    return y

# define NMT model
def define_model(vocab, timesteps, n_units):
    model = Sequential()
    model.add(Embedding(vocab, n_units, input_length=timesteps, mask_zero=True))
    model.add(LSTM(n_units))
    model.add(RepeatVector(timesteps))
    model.add(LSTM(n_units, return_sequences=True))
    model.add(TimeDistributed(Dense(vocab, activation='softmax')))
    return model

ここを実行すると次のようなエラーが出ます。

numpy.float64' object has no attribute 'lower'

float型なんて渡した覚えがないので、おそらくNaNが入っていそうですね。pritntしてみます。

print(dataset1)
[[ nan]
 [ nan]
 [ nan]
 [ nan]
 [ nan]
 [ nan]
 [ nan]
 [ nan]]

むしろ何も入っていませんでした。 おそらく読み込みのところで間違っていると思いますので、その辺りを調べてみました。stringに関してはpandasで読み込んだ方がいいとのことなので、pandasで読み込んだ後、ndarryに変換したいと思います。

df = pd.read_csv('kaiwa.csv',delimiter=',', dtype=str,header=None)
a = df_multi.values
a
[['今日 どう だった?' 'ほんま 楽しかった でぇ〜(笑)']
 ['こんど ライブ いつ?' 'めっちゃ やり そうな 予感!']
 ['前田 敦子 テレビ 出る って' 'ああ ああ 懐か しい']
 ['ライブ 行ったよ' '来て くれて、見て くれて、ありが とう ございました']
 ['7月だね' '今日から7月です。7月も皆さんどうぞよろしくお願いします']
 ['誕生日なんだ' '人生の先輩です!お誕生日おめでとう~~~✨✨!!']

これで良さそうです。 最後に03_chatting.pyのところを実行します。

from pickle import load
from numpy import array
from numpy import argmax
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import load_model
from nltk.translate.bleu_score import corpus_bleu

# load a clean dataset
def load_clean_sentences(filename):
    return load(open(filename, 'rb'))

# fit a tokenizer
def create_tokenizer(lines):
    tokenizer = Tokenizer(char_level=False)
    tokenizer.fit_on_texts(lines)
    return tokenizer

# max sentence length
def max_length(lines):
    return max(len(line.split()) for line in lines)

# map an integer to a word
def word_for_id(integer, tokenizer):
    for word, index in tokenizer.word_index.items():
        if index == integer:
            return word
    return None

# generate target given source sequence
def predict_sequence(model, tokenizer, source):
    prediction = model.predict(source, verbose=0)[0]
    integers = [argmax(vector) for vector in prediction]
    target = list()
    for i in integers:
        word = word_for_id(i, tokenizer)
        if word is None:
            break
        target.append(word)
    return ' '.join(target)

# translate
def translate(model, tokenizer, sources):
    predicted = list()
    for i, source in enumerate(sources):
        # translate encoded source text
        source = source.reshape((1, source.shape[0]))
        translation = predict_sequence(model, all_tokenizer, source)
        print('ANSWER: %s' % (translation))
        predicted.append(translation.split())

# load datasets
dataset = load_clean_sentences('both.pkl')
dataset1=dataset.reshape(-1,1)

# prepare tokenizer
all_tokenizer = create_tokenizer(dataset1[:,0])
all_vocab_size = len(all_tokenizer.word_index) + 1
all_length = max_length(dataset1[:, 0])

# load model
model = load_model('model1.h5')

# Setting up the chat
while(True):
    q = (input(str("YOU: ")))
    if q == 'bye':
        break
    q = q.strip().split('\n')

    #we tokenize
    X = all_tokenizer.texts_to_sequences(q)
    X = pad_sequences(X, maxlen=all_length, padding='post')
        
    # find reply and print it out
    translate(model, all_tokenizer, X)
YOU: おつかれ
ANSWER: 最後の最後に(
YOU: 元気?
ANSWER: 最後の最後に(
YOU: いま何してるの?
ANSWER: 最後の最後に(
YOU: おはよう
ANSWER: 最後の最後に(

全然ダメですね笑「最後の最後に(」ってなんなんですかね?

今日の結果

今日のAKBの呟きは50件でした。

要約するとこんな感じです。

よろしくお願いします(๑°꒵°๑)・*♡""今日の公演もありが田口でした!!アイコンタクトできたかなー??#安田叶""みてねー!!?"
"映画、僕のヒーローアカデミアを見てきました✨ヒロアカ好きの友達といったんだけど、推しキャラも一緒だからかっこよすぎてため息つく瞬間も同じだったしかっこよすぎて思わず口塞いじゃう瞬間も一緒だったし最高な時間すぎた!!好…""私の大切な大切なJKT481期生の同期のみんな。ただのわがままな子供だった頃からいっぱい守ってもらって、ずっと気にかけてくれて、、、、…""シアターの女神公演オンデマンド配信今日から高画質がみれる✨✨毎回綺麗さにびっくりする…それぞれのメンバーの表情にダンスにほうほうと学びが多いなぁ。。ペアで見合うの好き?
初めて2人でご飯行ったんです!楽しかったし、とにかくびーちゃんがいい子すぎました?❤️また行こうねっ!""美優ちゃんと2人で?❤️ぜひみてくださいね!""タイ行ってきまーす?
'可愛い': 4, 'かわいい': 3, '嬉しい': 3, '美味しい': 2, 'いい': 2, 'かっこよい': 2, 'あおい': 1, 'ない': 1, '多い': 1, 'すごい': 1, '楽しい': 1, '寒い': 1
'今日': 8, 'ご飯': 5, 'の': 5, 'ちゃん': 5, '公演': 5, '可愛い': 4, '私': 4, '時間': 4, '人': 4, '方': 4, 'お願い': 4, 'かわいい': 3, '嬉しい': 3, '時': 3, '写真': 3, '大人': 3, 'さ': 3, '大切': 3, '位': 3, '皆さん': 3, '出演': 3, '配信': 3, 'タイ': 3, '一緒': 3, '前田': 3, '彩佳': 3, 'レス': 3, 
'する': 24, 'くださる': 9, '今日': 8, '見る': 7, 'すぎる': 7, 'ご飯': 5, 'の': 5, 'ちゃん': 5, '公演': 5, 'てる': 5, 'ある': 5, 'なる': 5, '可愛い': 4, '私': 4, '時間': 4, '人': 4, '方': 4, 'お願い': 4, 'せる': 4, 'おる': 4, '頑張る': 4, '行く': 4, 'みる': 4, 

f:id:rimt:20180915011123p:plain

f:id:rimt:20180915011141p:plain