In [32]:
#https://orangesrv.dip.jp/wordpress/archives/1063  
#上記記事のコードを実行してみる
In [33]:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from keras.layers.core import RepeatVector
from keras.layers.wrappers import TimeDistributed
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Activation, LSTM,Input
from tensorflow.keras.initializers import glorot_uniform, orthogonal
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import plot_model
In [34]:
# 3桁のランダムな整数を返す
def n(digits=3):
    number = ''
    for i in range(np.random.randint(1, digits + 1)):
        number += np.random.choice(list('0123456789'))
    return int(number)

def padding(chars, maxlen):
    return chars + ' ' * (maxlen - len(chars))

def make_question(a, b, input_digits):
    question = '{}+{}'.format(a, b)
    question = padding(question, input_digits)
    return question

def make_answer(a, b, output_digits):
    answer = str(a + b)
    answer = padding(answer, output_digits)
    return answer
In [35]:
np.random.seed(seed=32)
digits = 3
N = 40000
N_train = 0.9

input_digits = digits * 2 + 1
output_digits = digits + 1
added = set()
questions = []
answers = []
while len(questions) < N:
    a, b = n(), n()
    pair = tuple(sorted((a, b)))
    if pair in added:
        continue
    question = make_question(a, b, input_digits)
    answer = make_answer(a, b, output_digits)
    added.add(pair)
    questions.append(question)
    answers.append(answer)
In [36]:
def translate_onehot(seqs, char_indices, n_chars, n_digits):
    V = np.zeros((len(seqs), n_digits, n_chars), dtype = np.integer)
    for i in range(len(seqs)):
        for t, char in enumerate(seqs[i]):
            V[i, t, char_indices[char]] = 1
    return V
In [37]:
chars = '0123456789+ '
char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars))
n_in = len(chars)
n_out = len(chars)

X = translate_onehot(questions, char_indices, n_in, input_digits)
Y = translate_onehot(answers, char_indices, n_out, output_digits)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, train_size = N_train)
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: DeprecationWarning: Converting `np.integer` or `np.signedinteger` to a dtype is deprecated. The current result is `np.dtype(np.int_)` which is not strictly correct. Note that the result depends on the system. To ensure stable results use may want to use `np.int64` or `np.int32`.
  
In [38]:
n_hidden = 128
In [39]:
def create_model_sequential(seed=10719173):
    model = Sequential()
    # Encoder
    model.add(LSTM(
        n_hidden, 
        input_shape = (input_digits, n_in),
        kernel_initializer=glorot_uniform(seed=seed), 
        recurrent_initializer=orthogonal(gain=1.0, seed=seed)
    ))
                                                
    # Decoder
    model.add(RepeatVector(output_digits))
    model.add(LSTM(
        n_hidden, 
        return_sequences = True,
        kernel_initializer=glorot_uniform(seed=seed), 
        recurrent_initializer=orthogonal(gain=1.0, seed=seed)
    ))
    model.add(TimeDistributed(Dense(n_out,kernel_initializer=glorot_uniform(seed=seed))))
    model.add(Activation('softmax'))
    model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.001, beta_1=0.9, beta_2=0.999), metrics=['accuracy'])
    
    return model
In [40]:
def compare_TV(history):
    # Setting Parameters
    acc = history.history['accuracy']
    val_acc = history.history['val_accuracy']
    epochs = range(len(acc))
    plt.plot(epochs, acc, 'bo' ,label = 'training acc')
    plt.plot(epochs, val_acc, 'b' , label= 'validation acc')
    plt.title('Training and Validation acc')
    plt.legend()
    plt.figure()
    plt.show()
In [41]:
def show_acc(model, batch_size = 300, epochs = 40, verbose = 0, shuffle = False):
    hist = model.fit(X_train, Y_train,
              batch_size=batch_size,
              epochs=epochs,
              validation_split=0.1,
              verbose=verbose,
              shuffle=shuffle
             )
    compare_TV(hist)
In [42]:
model_sequential = create_model_sequential()
plot_model(model_sequential, show_shapes=True,to_file='sequential_training.png')
/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/adam.py:105: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
  super(Adam, self).__init__(name, **kwargs)
Out[42]:
In [43]:
show_acc(model_sequential)
<Figure size 432x288 with 0 Axes>
In [44]:
# 予測してみる
def predict(model, a, b): # 学習済みのmodelを使ってa+bを予測
    sample_question = make_question(a, b, input_digits)
    sample_X = translate_onehot([sample_question], char_indices, n_in, input_digits)
    out = model.predict(sample_X)
    return ''.join([indices_char[np.argmax(v)] for v in out[0]])
In [45]:
predict(model_sequential, 10, 21)
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: DeprecationWarning: Converting `np.integer` or `np.signedinteger` to a dtype is deprecated. The current result is `np.dtype(np.int_)` which is not strictly correct. Note that the result depends on the system. To ensure stable results use may want to use `np.int64` or `np.int32`.
  
Out[45]:
'31  '
In [46]:
predict(model_sequential, 31, 52)
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: DeprecationWarning: Converting `np.integer` or `np.signedinteger` to a dtype is deprecated. The current result is `np.dtype(np.int_)` which is not strictly correct. Note that the result depends on the system. To ensure stable results use may want to use `np.int64` or `np.int32`.
  
Out[46]:
'83  '