SlideShare a Scribd company logo
v1.1
scikit-learnとTensorFlowによる
実践機械学習
14章 再帰型ニューラルネットワーク
説明者:飯塚孝好
2019年2月23日
1
v1.1
自己紹介
• 日立の中央研究所等で約20年間、コンパイラ等の研究開発に従事
– 日立のスパコン用の最適化、自動ベクトル化、自動並列化技術の開発
– 日立の大型ストレージ装置用ソフトウェアの高速化技術の開発
※ 入社時は人工知能希望だったが、同じ研究室の同僚と互い違いの部署に配属... 残念...
• 約10年間、ソフトウェア・サービスの事業企画業務に従事
– 新ソフトウェア・サービスの企画・立上げ
– 海外ビジネス展開、アライアンスの推進、社外発表・広報活動取り纏め
※ プログラミング等の現場からかなり離れた仕事が続いた... 残念...
• 2015/10:クラウド事業(当時担当)の先が見えたため、早期退職
• 2015/10~2016/10:最新のIT技術に飢えており、貪るように勉強
– 勉強内容はブログ(http://itsukara.hateblo.jp/)、github(https://github.com/Itsukara)等で共有
– Alpha GOで人工知能技術の進展を知り、色々本を買ったが読み進まず、輪講会に参加
– DeepMindの強化学習での成果が輪講会に話題になり、当時最難関のゲームの強化学習に挑戦
– 良い結果が出てOpenAI Gymにアップ。OpenAIから面接オファーがあり、サンフランシスコ旅行を楽しむ
• 2016/10:スタッフサービス経由で日立に再就職 (AIとは全く関係ない仕事)
• ~現在: 強化学習の成果を国際学会と国内セミナ(JulyTech)で発表したが、
AI関連の仕事に就くのは難しいことを実感。細々とAIの勉強を継続中。
2
v1.1
• 出力を入力に再帰するタイプのニューラルネットワーク
• 入力データの履歴を記憶し、未来の予測に活用
3
再帰型ニューラルネットワーク(RNN)とは
RNN: Recurrent Neural Network
v1.1
RNNの特徴
• 未来を予測できるタイプのニューラルネットワーク
– 時間と共に次々に生成されるデータから未来を予測
– 株価などの時系列データを分析し、売買時期を予測
– 自動運転システムで、車の軌跡を予測し、衝突回避
• 任意の長さのシーケンス(sequence)を操作可能
• 自然言語処理(NLP: Natural Language Processing)等で活用
– 文章、文書、オーディオ➡自動翻訳、テキスト変換、感情分析等
4
v1.1
RNN適用例
• Magenta https://magenta.tensorflow.org/
– 機械学習を活用して音楽や芸術を作成
– 自動生成音楽例 https://goo.gl/IxIL1V
• 文章自動生成 https://goo.gl/onkPNd
– ポール・グレアム(詩人)、シェークスピア等の文章を学習し、生成
• 写真タイトル自動生成 https://goo.gl/Nwx7Kh
5
v1.1
目次
14.1 再帰ニューロン
14.2 TensorFlowによる初歩的なRNN
14.3 RNNの訓練
14.4 深層RNN
14.5 LSTMセル
14.6 GRUセル
14.7 自然言語処理
付録 RNNに少し関連した最近の動向
6
v1.1
14.1 再帰ニューロン (1)
• 再帰ニューロン:もっとも単純なRNN(Recurrent Neural Network)
• 下図左のように、入力「x」に加え、自分自身の出力「y」も入力とする
• タイムステップ「t」を明示し、時間軸に沿って表現すると下図右になる
• これを時間軸に沿ってネットワークを「アンロールする」という
※ 本ページでは、「x」はベクトル、「y」はスカラ
7
v1.1
14.1 再帰ニューロン (2)
• 再帰ニューロンが複数並んだ層を考え、層単位での再帰を考える
※本ページ以降は、「x」「y」共にベクトル
• 単一インスタンスに対する出力「y(t)」は下記
• ミニバッチの全インスタンスに対する出力「Y(t)」は下記
8
m X(t) Y(t-1)
Wx
b・ +
ni nn
ni
nn
nn
1
nn: ニューロン数
m: ニバッチのインスタンス数
ni: 入力のフィーチャー数
• 「X(t)」は「X(0),X(1) ,X(2) , ...,X(t-1)」の関数となる
※ 「X(t)」は「X(t),Y(t-1)」の関数で、 「Y(t-1)」は「X(t-1),Y(t-2)」の関数で、...
Wy
nn
v1.1
14.1.1 記憶セル
• 再帰ニューロンの出力「X(t)」は全ての過去の入力「X(0),X(1) ,X(2) , ...,X(t-1)」の
関数なので、再帰ニューロンは、一種の記憶を持っていると言える
• そこで、単一の再帰ニューロンを記憶セル(memory cell)/セルと呼ぶ
• タイムステップ「t」でのセルの状態は「h(t)」と書く (hはhiddenの意味)
• 式で表現すると、h(t) = f(h(t-1), x (t))
• もっと複雑なセル(後述)では、 「h(t)」以外の入出力を含むため、式も複雑
9
v1.1
14.1.2 入出力シーケンス
• RNNの入力・出力の繋ぎ方で以下の4つに大分類される
• 左上:入力シーケンスを受け取り、同時に出力シーケンスを生成、利用
株価予測などの時系列データの予測に有用 (各タイムステップで、1日後の株価を出力)。
• 右上:入力シーケンスを受け取り、最後の出力(ベクトル)のみ利用
シーケンスをベクトルに変換。例えば映画の評論文から、文のスコア(好き:1~嫌い:-1)を出力。
• 左下:最初の入力(ベクトル)のみ受取、シーケンスを出力
ベクトルをシーケンスに変換。例えば画像を1つ入力し、その画像のタイトルを複数出力。
• 右下:入力シーケンスをベクトルに変換し(エンコーダ)、ベクトルからシーケンスを生成(デコーダ)
言語翻訳で有用。例えば、ある言語で書かれた文を、エンコーダがベクトルに変換し、
デコーダがベクトルから別の言語の文を生成。エンコーダ-デコーダと呼ばれる。 10
v1.1
14.2 TensorFlowによる初歩的なRNN (1)
• 理解を深めるために、TensorFlowのRNNを使わずに、手作業でRNNを実装
• ネットワーク作成
– 同じ重み「Wx、Wy」とバイアス「 b 」を2つの層で共有
– 各層に入力を与え、各層から出力
11
n_inputs = 3 # 入力のフィーチャー数
n_neurons = 5 # ニューロンの数
X0 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「0」のミニバッチ入力用プレスホルダー
X1 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「1」のミニバッチ入力用プレスホルダー
Wx = tf.Variable(tf.random_normal(shape=[n_inputs, n_neurons],dtype=tf.float32)) # Wx (乱数で初期化)
Wy = tf.Variable(tf.random_normal(shape=[n_neurons,n_neurons],dtype=tf.float32)) # Wy (乱数で初期化)
b = tf.Variable(tf.zeros([1, n_neurons], dtype=tf.float32)) # b (0で初期化)
Y0 = tf.tanh(tf.matmul(X0, Wx) + b) # X0 ・Wx
Y1 = tf.tanh(tf.matmul(Y0, Wy) + tf.matmul(X1, Wx) + b) # Xy ・Wy + X1 ・Wx + b
init = tf.global_variables_initializer()
b・ +
nn
1
nn: ニューロン数
m: ニバッチのインスタンス数
ni: 入力のフィーチャー数
+ ・
m
ni
m X(t) Y(t-1)
Wx
ni
ni nn Wy
nn
nn
nn
v1.1
14.2 TensorFlowによる初歩的なRNN (2)
• 各タイムステップでの入力を準備し、1回実行
• ミニバッチの全インスタンスに対する全ニューロンの出力
• 手動➡タイムステップが大きくなると、作成するグラフも大きくなり作成大変
12
import numpy as np
# ミニバッチ:インスタンス0、インスタンス1、インスタンス2、インスタンス3
X0_batch = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]) # t = 0
X1_batch = np.array([[9, 8, 7], [0, 0, 0], [6, 5, 4], [3, 2, 1]]) # t = 1
with tf.Session() as sess:
init.run()
Y0_val, Y1_val = sess.run([Y0, Y1], feed_dict={X0: X0_batch, X1: X1_batch})
X(0)
3
4
X(1)
3
4
>> print(Y0_val) # t = 0 の時点での出力
[[-0.06640061 0.9625767 0.6810579 0.7091854 -0.89821595] # インスタンス0
[ 0.99777555 -0.71978873 -0.99657613 0.96739244 -0.99989706] # インスタンス1
[ 0.99999785 -0.9989881 -0.99999887 0.9967763 -0.9999999 ] # インスタンス2
[ 1. -1. -1. -0.9981892 0.9995087 ]] # インスタンス3
>> print(Y1_val) # t = 1 の時点での出力
[[ 1. -1. -1. 0.40200272 -0.99999994] # インスタンス0
[-0.12210432 0.62805295 0.96718436 -0.9937122 -0.2583932 ] # インスタンス1
[ 0.99999815 -0.9999994 -0.99999744 -0.8594331 -0.99998796] # インスタンス2
[ 0.99928296 -0.9999981 -0.9999059 0.98579615 -0.9220575 ]] # インスタンス3
Y(0)4
5
Y(0)4
5
v1.1
14.2.1 時系列に沿った静的なアンロール (1)
• TensorFlowのstatic_rnn()関数を用い、前回と同じRNNを作る
• セルファクトリ:関数「__call__()」を呼び出すことで、「num_units」個の再帰
ニューロンから構成されるセル(セル層)を作成するファクトリ
• static_rnn():入力ごと(X0とX1)に1度ずつセルファクトリの「__call__()」を呼び
出して、共通の重みとバイアスを持つセルを2つ作り、手動構築と同様に連
鎖的にグラフを構築する
• output_seqs:個々のタイムステップの出力テンソルを一つにまとめたリスト
• states:ネットワークの最終状態を格納するテンソル
基本セルの場合、最終状態は最後の出力と同じ
• 上記では、タイムステップが50あると、50個の入力プレスホルダーと50個の
出力テンソルを定義しなければならず面倒。次ページでこれを単純化。
13
X0 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「0」のミニバッチ入力用プレスホルダー
X1 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「1」のミニバッチ入力用プレスホルダー
basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) # セルファクトリBasicRNNCellを作成
output_seqs, states = tf.nn.static_rnn(basic_cell, [X0, X1], # セルファクトリと入力テンソルリストを与え、
dtype=tf.float32) # 静的にアンロールされたRNNを作成
Y0, Y1 = output_seqs
v1.1
14.2.1 時系列に沿った静的なアンロール (2)
• タイムステップ数分の入力プレスホルダー(出力テンソル)を1つ(X)に纏める
• 入力を準備し、1回実行
• 実装容易化したがグラフは大きなまま
➡メモリ不足発生要因 (次頁で解決)
14
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) # [ミニバッチサイズ、タイムステップ数、入力フィーチャー数]
X_seqs = tf.unstack(tf.transpose(X, perm=[1, 0, 2])) # タイムステップ数、[ミニバッチサイズ、入力フィーチャー数]
# transpose():転置したテンソルを返す unstack():テンソルから、「1次元低いテンソル」のリストを作成して返す
basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)
output_seqs, states = tf.nn.static_rnn(basic_cell, X_seqs, # X_seqsは[X0, X1]に相当
dtype=tf.float32)
outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2])
# タイムステップ数(リスト)、[ミニバッチサイズ、ニューロン数]という形状の出力を、stack()で1つのテンソルンに纏めた後、
# transpose()で転置し、[ミニバッチサイズ、タイムステップ数、入力フィーチャー数]と形状に変更
X_batch = np.array([
# t = 0 t = 1
[[0, 1, 2], [9, 8, 7]], # instance 0
[[3, 4, 5], [0, 0, 0]], # instance 1
[[6, 7, 8], [6, 5, 4]], # instance 2
[[9, 0, 1], [3, 2, 1]], # instance 3
])
with tf.Session() as sess:
init.run()
outputs_val = outputs.eval(feed_dict={X: X_batch})
実行結果
v1.1
14.2.2 時系列に沿った動的なアンロール
• dynamic_rnn():while_loop()を使い、セルを適切な回数(動的に)実行
– 入力テンソル:[None, n_steps, n_inputs]という形状 (転置不要)
– 出力テンソル:[None, n_steps, n_neurons]という形状 (転置不要)
• dynamic_rnn()を使って前回と同じRNNを作る
• (入力、実行、出力は前回と同じ(形状)のため省略)
15
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
v1.1
14.2.3 可変長入力シーケンスの処理
• 入力シーケンスの長さが一定しない場合(文等)、dynamic_rnn()を呼び出す
ときに、インスタンス毎の入力シーケンスの長さを示す1Dテンソルを
sequence_length引数として渡せばよい
• 入力シーケンス長が短いインスタンスは、0ベクトルでパディングする
• 実行時は、sequence_length引数で渡したseq_lengthに値を渡す
• 入力シーケンスの長さを超えるタイムステップは0ベクトルが出力される
16
seq_length = tf.placeholder(tf.int32, [None]) #インスタンス毎の入力シーケンスの長さを示す1Dテンソル
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32,
sequence_length=seq_length) # sequence_length引数
X_batch = np.array([
# step 0 step 1
[[0, 1, 2], [9, 8, 7]], # instance 0
[[3, 4, 5], [0, 0, 0]], # instance 1 (0ベクトルでパディング)
[[6, 7, 8], [6, 5, 4]], # instance 2
[[9, 0, 1], [3, 2, 1]], # instance 3
])
seq_length_batch = np.array([2, 1, 2, 2])
with tf.Session() as sess:
init.run()
outputs_val, states_val = sess.run(
[outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
v1.1
14.2.4 可変長出力シーケンスの処理
• 出力シーケンスも可変長の場合の対応方法は以下
• 入力シーケンスと同じ長さになる場合は、sequence lengthパラメータを設定
• 上記が同じにならない場合(例えば翻訳後の文の長さは不明)、EOSトークン
(EOS token:End-Of-Sequence token)を出力し、それ以降は無視する
17
v1.1
14.3 RNNの訓練
• RNNの訓練では、時系列に沿ってアンロールし、単純に通常のバックプロ
パゲーションを行う (BPTT: backpropagation through time:通時的逆伝搬)
• 最初、アンロールされたネットワークを前進パスで通り抜ける (破線)
• 次に、無視されない出力を使ったコスト関数(上記ではC(Y(2), Y(3), Y (4) ))を
使って出力を評価し、その勾配を、後退方向に伝えていく (実線)
• 最後に、上記過程で計算した勾配を使ってパラメータを更新する
– 各ステップで同じW、bが使われるので、全タイムステップの勾配をW、bに反映
18
v1.1
14.3.1 シーケンス分類器の訓練 (1)
• RNNでMNISTイメージを分類してみる (なお、イメージ分類はCNNの方が適してる)
19
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
X(0)
X(1)
X(2)
X(3)
X(4)
X(5)
X(6)
X(7)
X(8)
X(9)
X(10)
X(11)
X(12)
X(13)
X(14)
X(15)
X(16)
X(17)
X(18)
X(19)
X(20)
X(21)
X(22)
X(23)
X(24)
X(25)
X(26)
X(27)
150個の再帰ニューロン
n_steps = 28
n_inputs = 28
n_neurons = 150
n_outputs = 10
learning_rate = 0.001
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
y = tf.placeholder(tf.int32, [None])
basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
logits = tf.layers.dense(states, n_outputs)
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y,
logits=logits)
loss = tf.reduce_mean(xentropy)
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(loss)
correct = tf.nn.in_top_k(logits, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
init = tf.global_variables_initializer()
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
X_train = X_train.astype(np.float32).reshape(-1, 28*28) / 255.0
X_test = X_test.astype(np.float32).reshape(-1, 28*28) / 255.0
y_train = y_train.astype(np.int32)
y_test = y_test.astype(np.int32)
X_valid, X_train = X_train[:5000], X_train[5000:]
y_valid, y_train = y_train[:5000], y_train[5000:]
def shuffle_batch(X, y, batch_size):
rnd_idx = np.random.permutation(len(X))
n_batches = len(X) // batch_size
for batch_idx in np.array_split(rnd_idx, n_batches):
X_batch, y_batch = X[batch_idx], y[batch_idx]
yield X_batch, y_batch
X_test = X_test.reshape((-1, n_steps, n_inputs))
※青字部分以外は、CNNとほぼ同じ
※CNNとほぼ同じ
v1.1
14.3.1 シーケンス分類器の訓練 (2)
• RNNでMNISTイメージを訓練する
• 訓練中の出力
• Testデータで98%を超える正確度が得られた。➡悪くない数字
• HeでRNNの重みを初期化、訓練長期化、正規化等でもっと上がるだろう
• RNNの初期化は、ネットワーク構築コードを変数スコープでラップする
20
n_epochs = 100
batch_size = 150
with tf.Session() as sess:
init.run()
for epoch in range(n_epochs):
for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size):
X_batch = X_batch.reshape((-1, n_steps, n_inputs))
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
acc_batch = accuracy.eval(feed_dict={X: X_batch, y: y_batch})
acc_test = accuracy.eval(feed_dict={X: X_test, y: y_test})
print(epoch, "Last batch accuracy:", acc_batch, "Test accuracy:", acc_test)
0 Last batch accuracy: 0.9533333 Test accuracy: 0.9288
1 Last batch accuracy: 0.96 Test accuracy: 0.9471
2 Last batch accuracy: 0.96 Test accuracy: 0.9499
...
98 Last batch accuracy: 0.99333334 Test accuracy: 0.977
99 Last batch accuracy: 0.99333334 Test accuracy: 0.9805
with tf.variable_scope(“rnn”, initializer=variance_scaling_initializer()):
# ネットワーク構築コードを記載
※CNNとほぼ同じ
v1.1
14.3.2 時系列データを予測するための訓練 (1)
• 株価、基本、脳波パタンなどの、時系列データの処理方法を少し見る
• 例として、時系列データから無作為に選出した20個の値で訓練する
• ターゲットシーケンスは、タイムステップを一つ先にずらしたシーケンス
• 各タイムステップで予測値1つのみが
欲しいので、全結合(FC)ラッパーを被せる
• なお、この全結合層は、全て同じ重み、
とバイアスを共有する
21
訓練インスタンス
インスタンス
ターゲット
訓練インスタンス時系列データ
v1.1
14.3.2 時系列データを予測するための訓練 (2)
• MSE(平均2乗誤差)をコスト関数として、以下のようなコード・結果になる
22
n_steps = 20
n_inputs = 1
n_neurons = 100
n_outputs = 1
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
y = tf.placeholder(tf.float32, [None, n_steps, n_outputs])
cell = tf.contrib.rnn.OutputProjectionWrapper(
tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons, activation=tf.nn.relu),
output_size=n_outputs) # 全結合(FC: Full Connect)ラッパー
outputs, states = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
learning_rate = 0.001
loss = tf.reduce_mean(tf.square(outputs - y)) # MSE
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(loss)
init = tf.global_variables_initializer()
saver = tf.train.Saver()
n_iterations = 1500
batch_size = 50
with tf.Session() as sess:
init.run()
for iteration in range(n_iterations):
X_batch, y_batch = next_batch(batch_size, n_steps)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
if iteration % 100 == 0:
mse = loss.eval(feed_dict={X: X_batch, y: y_batch})
print(iteration, "¥tMSE:", mse)
saver.save(sess, "./my_time_series_model") # not shown in the book
0 MSE: 10.261382
100 MSE: 0.3879291
200 MSE: 0.10900871
300 MSE: 0.06135445
400 MSE: 0.059347205
500 MSE: 0.05819268
600 MSE: 0.05220854
700 MSE: 0.047660623
800 MSE: 0.04888802
900 MSE: 0.047597326
1000 MSE: 0.047681753
1100 MSE: 0.046209298
1200 MSE: 0.039961636
1300 MSE: 0.046320174
1400 MSE: 0.041305345
モデルのテスト結果
インスタンス
ターゲット
予測
実行結果
v1.1
14.3.2 時系列データを予測するための訓練 (3)
• 全結合ラッパーよりも、下記の方が効率が良く大幅なスピードアップが可能
 RNNの形状[ステップ数、バッチサイズ、ニューロン数]の出力を、
 積み上げて、形状[ステップ数×バッチサイズ、ニューロン数]のテンソルにリシェープし、
 全結合(FC)層を通した形状[ステップ数×バッチサイズ、1]の出力を
 各ステップでの[バッチサイズ]の出力に展開
23
v1.1
14.3.3 独創的RNN
• 訓練結果を基に、独創的なシーケンスを生成
• n_steps個の初期値(例えば0)を与え、これを種に、時系列データを生成
• 具体的には、1回毎に1個、1ステップ先のデータを生成し、
これを入力シーケンスに加え、最新n_stepsのシーケンスで処理を繰り返す
• 結果例は下記(赤枠部分が、それぞれの初期シーケンス)
24
sequence = [0.] * n_steps
for iteration in range(300):
X_batch = np.array(sequence[-n_steps:]).reshape(1, n_steps, 1) # 最新のn_stepsのシーケンスを取り出す
y_pred = sess.run(outputs, feed_dict={X: X_batch})
sequence.append(y_pred[0, -1, 0]) # 予測シーケンスの最後のデータを入力シーケンスに追加
(注) 初期シーケンスが同じでも、訓練結果によって、独創的シーケンスの内容は変わり、上記と別の結果になる
v1.1
14.4 深層RNN
• 通常NN同様にセルを積み上げたものが深層RNN
• Tensorflowでは、MultiRNNCellで構築可能
25
n_neurons = 100
n_layers = 3
layers = [tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) for layer in range(n_layers)] # セルのリスト
multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(layers) # 深層RNNのセル
outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32) # 深層RNN
深層RNN
時系列に沿って深層RNNをアンロールしたもの
v1.1
14.4.1 複数のGPUによる深層RNNの分散処理
• 深層RNNを複数GPUで分散処理するには、工夫が必要
– BasicRNNCellがセルそのものではないため、BasicRNNCell作成時にGPUを指定できない
– MultiRNNCellがBasicRNNCellを呼び出してセルを作るが、デバイスを指定できない
• 下記の様に、独自のラッパセルを作ることで、処理を複数GPUに分散可能
26
class DeviceCellWrapper(tf.nn.rnn_cell.RNNCell):
def __init__(self, device, cell):
self._cell = cell
self._device = device
@property
def state_size(self):
return self._cell.state_size
@property
def output_size(self):
return self._cell.output_size
def __call__(self, inputs, state, scope=None): # 実セル作成時に呼び出される
with tf.device(self._device): # セルの処理をデバイスに割り当てる
return self._cell(inputs, state, scope)
devices = ["/gpu:0", "/gpu:1", "/cpu:0"]
cells = [DeviceCellWrapper(dev,tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons))
for dev in devices]
multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(cells)
outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)
v1.1
14.4.2 ドロップアウトの適用
• RNNの層間でドロップアウトを適用するにはDropoutWrapperを使う
• keep_probは、訓練中は好きな値(通常0.5)、テスト時はデフォルト(1.0)にする
27
keep_prob = tf.placeholder_with_default(1.0, shape=())
cells = [tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)
for layer in range(n_layers)]
cells_drop = [tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=keep_prob)
for cell in cells]
multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(cells_drop)
rnn_outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)
# 訓練中
train_keep_prob = 0.5
with tf.Session() as sess:
init.run()
for iteration in range(n_iterations):
X_batch, y_batch = next_batch(batch_size, n_steps)
_, mse = sess.run([training_op, loss],
feed_dict={X: X_batch, y: y_batch, keep_prob: train_keep_prob})
saver.save(sess, "./my_dropout_time_series_model")
# テスト時
with tf.Session() as sess:
saver.restore(sess, "./my_dropout_time_series_model")
X_new = time_series(np.array(t_instance[:-1].reshape(-1, n_steps, n_inputs)))
# keep_prob未指定なので、変数定義時のデフォルト値(1.0)になる
y_pred = sess.run(outputs, feed_dict={X: X_new})
v1.1
14.4.3 多数のタイムステップによる訓練の難しさ
• 長いシーケンスに対するRNNは、ステップ(横)方向に深いネットワークになる
• そのため、深層NNの常として、勾配消失/爆発問題の影響を受ける
• 対策として、パラメータの良い初期化方法、飽和を起こさない活性化関数、
バッチ正規化、勾配クリップなどは、RNNでも使える
• しかし、少し長いシーケンスでも100個程度になり、訓練が遅くなりがち
• 良く使われる対策は、時系列に沿ったバックプロパゲーションの途中打ち切
り (訓練中は、入力シーケンスを途中で切ってしまう)だが、色々と副作用あり
• また、長いRNNは、最初の入力の記憶が次第に消えるという問題もあり
– 最初のステップの入力の痕跡が、後の方のステップでは殆ど無くなる
– 文章の最初に結論を言って、後から情報を追加すると、結論が忘れられる可能性あり
• 記憶が消える問題への対策として、長期記憶を持つ各種セルが考案された
– 長期記憶を持つセルは効果が、その効果が実証されている
• 以下では、長期記憶セルとして人気のあるLSTMとGRUを見ていく
28
v1.1
14.5 LSTMセル (1)
• LSTM(長期短期記憶:long short-term memory)は、Sepp Hochreiter他が
1997年に提案し、多くの人々が研究に少しずつ改良し、現在の形になった
• 基本セルの代わりにLSTMを使うだけで、訓練は短時間で収束し、データ内
の長期的な依存関係を検出できる、非常の性能の良いRNNになる
• 短期的な記憶「h(t)」に加え、長期的な記憶「c(t)」を入力・出力する
• 長期記憶から捨てるべき要素(忘却)、長期的記憶に格納すべき要素(入力)、
短期記憶/出力で読み取るべき要素(出力)を、3つのゲートコントローラ(下記
のf(t)、i(t)、o(t))で制御し、最適なゲートコントローラを学習できることが特徴
29
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=n_neurons)
前ステップの長期記憶
前ステップの短期記憶
出力長期記憶
出力短期記憶
忘却ゲート
入力ゲート
出力ゲート 要素毎の乗算
要素毎の加算
出力は0~1の範囲
v1.1
14.5 LSTMセル (2)
30
式14-3 LSTMの計算式
v1.1
14.5.1 ピープホール接続
• 基本LSTMセルでは、各ゲートのコントローラ(全結合層)は、「x(t)」と直前の
短期記憶「h(t-1)」を入力しているが、長期記憶「c(t)」を入力に加えることを、
ピープホール接続と呼ぶ (Felix他が2000年に提案)
• TensorFlowでピープホール接続を実装するには、BasicLSTMCellでなく、
LSTMCellを使い、use_peepholes=Trueを指定すればよい
• LSTMセルには、ほかにも多数の変種がある
その中で特に人気のあるGRUセルを次に紹介する
31
lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=n_neurons, use_peepholes=True)
v1.1
14.6 GRUセル
• GRU (Gated Recurrent Unit)は、Kyunghyun Chao等が2014年提案
• LSTMを単純化したものであり、LSTMとほぼ同様に機能する
– 長期記憶と短期記憶が結合されて、一つのベクトル「h(t)」になっている
– 一つのゲートコントローラ「z(t)」で、忘却ゲートと入力ゲートの両方を制御
• 値が1の場合忘却ゲートが開き、入力ゲートが閉じる。値が0の場合はその逆
– 出力ゲートが無い。代わりに、直前の状態のどの部分をメイン層で用いるかを制御す
る新しいゲートコントローラ「r(t)」が追加されている
32
式14-4 GRUの計算式
• LSTM、GRUセルは、RNN成功の理由であり、自然言語処理でも応用されている
v1.1
14.7 自然言語処理
• 機械翻訳、自動要約、構文解析、感情分析などの最先端の自然言語処理
(NLP: Natural Language Processing)の多くは、RNNを基礎としている
• 以下では、機械翻訳のモデルがどのようになっているかを簡単に紹介
• 詳細は、以下で説明されている
– Word2Vec: https://www.tensorflow.org/tutorials/representation/word2vec
– Seq2Seq: https://github.com/tensorflow/nmt
33
v1.1
14.7.1 単語の埋め込み
• 自然言語処理の入口として、まずは、単語の表現方法を選ぶ必要がある
• 単語間の関係は当初不明なので、ワンホットベクトル表現が考えられる
– ワンホットベクトルの例: (0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...,0)
– 語彙集が5万語含むとき、1要素が1、他は0の疎な表現になり、メモリ効率が非常に悪い
• もっとも一般的な買いは、埋め込みと呼ばれる手法であり、単語を小さく密な
ベクトル空間(150次元程度)に埋め込み、NNで単語のベクトル値を学習する
• 訓練開始時は、埋め込みベクトルの値は無作為だが、訓練中にバックプロパ
ゲーションによって、埋め込みベクトルの値を自動的に書き換えていく
– 文章の途中までの単語列を入力シーケンスにし、次の単語を予測するようNNを訓練
• 訓練で、類似する単語は互いに近づき、かなり意味のある形で組織される
34
woman – man ≒ queen - king walked – walking ≒ swam - swimming 首都 – 国は、ほぼ同じベクトル
v1.1
14.7.2 機械翻訳のためのエンコーダ-デコーダネットワーク (1)
• 英語の文をフランス語に翻訳する簡単な機械翻訳モデルを見てみる
※ seq2seqサイト(https://github.com/tensorflow/nmt) の内容を記載(入力文の語順は元のまま)
• エンコーダが入力文を意味ベクトルに変換、デコーダが意味ベクトルから翻訳文を生成
• エンコーダとデコーダは深層RNN(下図は2層)で、前段に埋め込み層を持つ
35
入力は単語の語彙辞書内番号の列
例えば、[12, 47, 7, 834]
各単語が150次元ベクトル空間に埋め込まれる
深層RNN (2層)
各ステップの出力を出力辞書長のロジットに変換
(完全結合)
ロスとして、ターゲット文と翻訳文の差異を計算
(sparse_softmax_cross_entropy_with_logits)
v1.1
14.7.2 機械翻訳のためのエンコーダ-デコーダネットワーク (2)
• 下記、英独翻訳の訓練済みデータを含む、各種DLモデルが公開されている
– https://github.com/tensorflow/tensor2tensor
– Google Colaboratoryで、英独翻訳の訓練済みデータを試せる
• https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb
36
入力と出力の例
v1.1
付録 RNNに少し関連した最近の動向(1)
• 2018/11/2、Googleが言語表現事前訓練手法「BERT」をオープンソース公開
– 世界最高レベルの訓練手法であり、事前学習済モデルも一緒に公開されている
– Google曰く:『世界の誰もが、「単一Cloud TPUなら約30分」「単一GPUなら約数時間」で、独
自の「最新の質問応答システム」や「その他のさまざまなモデル」を訓練できる』
– BERTを使った例が、Google Colaboratoryノートブックで公開されている
• https://colab.research.google.com/github/google-
research/bert/blob/master/predicting_movie_reviews_with_bert_on_tf_hub.ipynb
• 2018/12/4、NIPSで、時系列データの全く新しい分析手法(ODE)が提案された
– 時系列データに欠損値があったり、入力データ感覚が不揃いな場合に対応できる
– ResNetの層構造の式が、常微分方程式(ODE)の解法(オイラー法)に似ていることに着想
– ODEなら、賢いODE SOlverを活用でき、また、離散化された層構造に縛られない
– MNISTでの試行結果:RestNetと同じ精度だが、パラメータ・メモリ使用量が少ない
– 紹介記事:https://www.slideshare.net/DeepLearningJP2016/dlneural-ordinary-differential-equations
37
BERT:Bidirectional Encoder Representations from Transformers
v1.1
付録 RNNに少し関連した最近の動向 (2)
• 2019/2/19、OpenAIが本物と見分けがつかないフェイクニュースを自動生成
– https://gigazine.net/news/20190216-ai-fake-text-generator-dangerous-release/
38
入力 出力
自動生成

More Related Content

PDF
TensorFlowの使い方(in Japanese)
Toshihiko Yamakami
 
PDF
フーリエ変換と画像圧縮の仕組み
yuichi takeda
 
PDF
TensorflowとKerasによる深層学習のプログラム実装実践講座
Ruo Ando
 
PDF
2018年01月27日 TensorFlowの計算グラフの理解
aitc_jp
 
PPTX
Deep Learning基本理論とTensorFlow
Tadaichiro Nakano
 
PDF
TensorFlow計算グラフ最適化処理
Atsushi Nukariya
 
PDF
PoisoningAttackSVM (ICMLreading2012)
Hidekazu Oiwa
 
PDF
FOBOS
Hidekazu Oiwa
 
TensorFlowの使い方(in Japanese)
Toshihiko Yamakami
 
フーリエ変換と画像圧縮の仕組み
yuichi takeda
 
TensorflowとKerasによる深層学習のプログラム実装実践講座
Ruo Ando
 
2018年01月27日 TensorFlowの計算グラフの理解
aitc_jp
 
Deep Learning基本理論とTensorFlow
Tadaichiro Nakano
 
TensorFlow計算グラフ最適化処理
Atsushi Nukariya
 
PoisoningAttackSVM (ICMLreading2012)
Hidekazu Oiwa
 

Similar to Scikit-learn and TensorFlow Chap-14 RNN (v1.1) (20)

PDF
[第2版]Python機械学習プログラミング 第16章
Haruki Eguchi
 
PPTX
Tf勉強会(5)
tak9029
 
PDF
[第2版]Python機械学習プログラミング 第14章
Haruki Eguchi
 
PDF
RNN-based Translation Models (Japanese)
NAIST Machine Translation Study Group
 
PDF
Deep Learningの基礎と応用
Seiya Tokui
 
PDF
[第2版]Python機械学習プログラミング 第13章
Haruki Eguchi
 
PDF
Chainerの使い方と自然言語処理への応用
Seiya Tokui
 
PDF
[DL Hacks] Deterministic Variational Inference for RobustBayesian Neural Netw...
Deep Learning JP
 
PPTX
「機械学習とは?」から始める Deep learning実践入門
Hideto Masuoka
 
PDF
[第2版]Python機械学習プログラミング 第15章
Haruki Eguchi
 
PDF
Recurrent Neural Networks
Seiya Tokui
 
DOCX
深層学習 Day1レポート
taishimotoda
 
PDF
「深層学習」勉強会LT資料 "Chainer使ってみた"
Ken'ichi Matsui
 
PDF
Efficient Neural Architecture Searchvia Parameter Sharing
Taichi Itoh
 
PPTX
ラビットチャレンジレポート 深層学習 Day1
ssuserf4860b
 
DOCX
レポート深層学習Day3
ssuser9d95b3
 
PDF
dl-with-python01_handout
Shin Asakawa
 
PPTX
Tfug#4
tak9029
 
PDF
[DL輪読会]Pervasive Attention: 2D Convolutional Neural Networks for Sequence-to-...
Deep Learning JP
 
PPTX
Long short-term memory (LSTM)
Kenta Ishii
 
[第2版]Python機械学習プログラミング 第16章
Haruki Eguchi
 
Tf勉強会(5)
tak9029
 
[第2版]Python機械学習プログラミング 第14章
Haruki Eguchi
 
RNN-based Translation Models (Japanese)
NAIST Machine Translation Study Group
 
Deep Learningの基礎と応用
Seiya Tokui
 
[第2版]Python機械学習プログラミング 第13章
Haruki Eguchi
 
Chainerの使い方と自然言語処理への応用
Seiya Tokui
 
[DL Hacks] Deterministic Variational Inference for RobustBayesian Neural Netw...
Deep Learning JP
 
「機械学習とは?」から始める Deep learning実践入門
Hideto Masuoka
 
[第2版]Python機械学習プログラミング 第15章
Haruki Eguchi
 
Recurrent Neural Networks
Seiya Tokui
 
深層学習 Day1レポート
taishimotoda
 
「深層学習」勉強会LT資料 "Chainer使ってみた"
Ken'ichi Matsui
 
Efficient Neural Architecture Searchvia Parameter Sharing
Taichi Itoh
 
ラビットチャレンジレポート 深層学習 Day1
ssuserf4860b
 
レポート深層学習Day3
ssuser9d95b3
 
dl-with-python01_handout
Shin Asakawa
 
Tfug#4
tak9029
 
[DL輪読会]Pervasive Attention: 2D Convolutional Neural Networks for Sequence-to-...
Deep Learning JP
 
Long short-term memory (LSTM)
Kenta Ishii
 
Ad

Recently uploaded (11)

PDF
FeNO呼気分析装置市場、CAGR13.90%で成長し、2031年には290百万米ドル規模に
yhresearch
 
PPTX
20250729_TechTalk_QlikTalendCloud_データ品質とデータガバナンス
QlikPresalesJapan
 
PDF
ダイヤモンドスラリー市場規模の成長見通し:2031年には193百万米ドルに到達へ
yhresearch
 
PDF
RV車市場、CAGR2.60%で成長し、2031年には37640百万米ドル規模に
yhresearch
 
PPTX
PRESENTASI IZIN OPERASIONAL SMK ISLAM KARYA MANDIRI
BAHRULALAM27
 
PPTX
BEIS ORIENTATION FOR S.Y2024 - 2025.pptx
AsmiraCo2
 
PDF
埋め込み型ドラッグデリバリーデバイスの成長予測:2031年には751百万米ドルに到達へ
2418867459
 
PDF
世界mPOSデバイス市場のサプライチェーン解析:上流、下流、収益モデル分析2025-2031
yhresearch
 
PDF
セットトップボックス市場:世界の産業現状、競合分析、シェア、規模、動向2025-2031年の予測
snow326214
 
PDF
工業用ミストシステム調査レポート:市場規模、シェア、産業分析データ、最新動向2025-2031 YH Research
2418867459
 
PPTX
【Qlik 医療データ活用勉強会】第50回 日本医療マネジメント学会参加報告、DPCデータの活用等
QlikPresalesJapan
 
FeNO呼気分析装置市場、CAGR13.90%で成長し、2031年には290百万米ドル規模に
yhresearch
 
20250729_TechTalk_QlikTalendCloud_データ品質とデータガバナンス
QlikPresalesJapan
 
ダイヤモンドスラリー市場規模の成長見通し:2031年には193百万米ドルに到達へ
yhresearch
 
RV車市場、CAGR2.60%で成長し、2031年には37640百万米ドル規模に
yhresearch
 
PRESENTASI IZIN OPERASIONAL SMK ISLAM KARYA MANDIRI
BAHRULALAM27
 
BEIS ORIENTATION FOR S.Y2024 - 2025.pptx
AsmiraCo2
 
埋め込み型ドラッグデリバリーデバイスの成長予測:2031年には751百万米ドルに到達へ
2418867459
 
世界mPOSデバイス市場のサプライチェーン解析:上流、下流、収益モデル分析2025-2031
yhresearch
 
セットトップボックス市場:世界の産業現状、競合分析、シェア、規模、動向2025-2031年の予測
snow326214
 
工業用ミストシステム調査レポート:市場規模、シェア、産業分析データ、最新動向2025-2031 YH Research
2418867459
 
【Qlik 医療データ活用勉強会】第50回 日本医療マネジメント学会参加報告、DPCデータの活用等
QlikPresalesJapan
 
Ad

Scikit-learn and TensorFlow Chap-14 RNN (v1.1)

  • 2. v1.1 自己紹介 • 日立の中央研究所等で約20年間、コンパイラ等の研究開発に従事 – 日立のスパコン用の最適化、自動ベクトル化、自動並列化技術の開発 – 日立の大型ストレージ装置用ソフトウェアの高速化技術の開発 ※ 入社時は人工知能希望だったが、同じ研究室の同僚と互い違いの部署に配属... 残念... • 約10年間、ソフトウェア・サービスの事業企画業務に従事 – 新ソフトウェア・サービスの企画・立上げ – 海外ビジネス展開、アライアンスの推進、社外発表・広報活動取り纏め ※ プログラミング等の現場からかなり離れた仕事が続いた... 残念... • 2015/10:クラウド事業(当時担当)の先が見えたため、早期退職 • 2015/10~2016/10:最新のIT技術に飢えており、貪るように勉強 – 勉強内容はブログ(http://itsukara.hateblo.jp/)、github(https://github.com/Itsukara)等で共有 – Alpha GOで人工知能技術の進展を知り、色々本を買ったが読み進まず、輪講会に参加 – DeepMindの強化学習での成果が輪講会に話題になり、当時最難関のゲームの強化学習に挑戦 – 良い結果が出てOpenAI Gymにアップ。OpenAIから面接オファーがあり、サンフランシスコ旅行を楽しむ • 2016/10:スタッフサービス経由で日立に再就職 (AIとは全く関係ない仕事) • ~現在: 強化学習の成果を国際学会と国内セミナ(JulyTech)で発表したが、 AI関連の仕事に就くのは難しいことを実感。細々とAIの勉強を継続中。 2
  • 4. v1.1 RNNの特徴 • 未来を予測できるタイプのニューラルネットワーク – 時間と共に次々に生成されるデータから未来を予測 – 株価などの時系列データを分析し、売買時期を予測 – 自動運転システムで、車の軌跡を予測し、衝突回避 • 任意の長さのシーケンス(sequence)を操作可能 • 自然言語処理(NLP: Natural Language Processing)等で活用 – 文章、文書、オーディオ➡自動翻訳、テキスト変換、感情分析等 4
  • 5. v1.1 RNN適用例 • Magenta https://magenta.tensorflow.org/ – 機械学習を活用して音楽や芸術を作成 – 自動生成音楽例 https://goo.gl/IxIL1V • 文章自動生成 https://goo.gl/onkPNd – ポール・グレアム(詩人)、シェークスピア等の文章を学習し、生成 • 写真タイトル自動生成 https://goo.gl/Nwx7Kh 5
  • 6. v1.1 目次 14.1 再帰ニューロン 14.2 TensorFlowによる初歩的なRNN 14.3 RNNの訓練 14.4 深層RNN 14.5 LSTMセル 14.6 GRUセル 14.7 自然言語処理 付録 RNNに少し関連した最近の動向 6
  • 7. v1.1 14.1 再帰ニューロン (1) • 再帰ニューロン:もっとも単純なRNN(Recurrent Neural Network) • 下図左のように、入力「x」に加え、自分自身の出力「y」も入力とする • タイムステップ「t」を明示し、時間軸に沿って表現すると下図右になる • これを時間軸に沿ってネットワークを「アンロールする」という ※ 本ページでは、「x」はベクトル、「y」はスカラ 7
  • 8. v1.1 14.1 再帰ニューロン (2) • 再帰ニューロンが複数並んだ層を考え、層単位での再帰を考える ※本ページ以降は、「x」「y」共にベクトル • 単一インスタンスに対する出力「y(t)」は下記 • ミニバッチの全インスタンスに対する出力「Y(t)」は下記 8 m X(t) Y(t-1) Wx b・ + ni nn ni nn nn 1 nn: ニューロン数 m: ニバッチのインスタンス数 ni: 入力のフィーチャー数 • 「X(t)」は「X(0),X(1) ,X(2) , ...,X(t-1)」の関数となる ※ 「X(t)」は「X(t),Y(t-1)」の関数で、 「Y(t-1)」は「X(t-1),Y(t-2)」の関数で、... Wy nn
  • 9. v1.1 14.1.1 記憶セル • 再帰ニューロンの出力「X(t)」は全ての過去の入力「X(0),X(1) ,X(2) , ...,X(t-1)」の 関数なので、再帰ニューロンは、一種の記憶を持っていると言える • そこで、単一の再帰ニューロンを記憶セル(memory cell)/セルと呼ぶ • タイムステップ「t」でのセルの状態は「h(t)」と書く (hはhiddenの意味) • 式で表現すると、h(t) = f(h(t-1), x (t)) • もっと複雑なセル(後述)では、 「h(t)」以外の入出力を含むため、式も複雑 9
  • 10. v1.1 14.1.2 入出力シーケンス • RNNの入力・出力の繋ぎ方で以下の4つに大分類される • 左上:入力シーケンスを受け取り、同時に出力シーケンスを生成、利用 株価予測などの時系列データの予測に有用 (各タイムステップで、1日後の株価を出力)。 • 右上:入力シーケンスを受け取り、最後の出力(ベクトル)のみ利用 シーケンスをベクトルに変換。例えば映画の評論文から、文のスコア(好き:1~嫌い:-1)を出力。 • 左下:最初の入力(ベクトル)のみ受取、シーケンスを出力 ベクトルをシーケンスに変換。例えば画像を1つ入力し、その画像のタイトルを複数出力。 • 右下:入力シーケンスをベクトルに変換し(エンコーダ)、ベクトルからシーケンスを生成(デコーダ) 言語翻訳で有用。例えば、ある言語で書かれた文を、エンコーダがベクトルに変換し、 デコーダがベクトルから別の言語の文を生成。エンコーダ-デコーダと呼ばれる。 10
  • 11. v1.1 14.2 TensorFlowによる初歩的なRNN (1) • 理解を深めるために、TensorFlowのRNNを使わずに、手作業でRNNを実装 • ネットワーク作成 – 同じ重み「Wx、Wy」とバイアス「 b 」を2つの層で共有 – 各層に入力を与え、各層から出力 11 n_inputs = 3 # 入力のフィーチャー数 n_neurons = 5 # ニューロンの数 X0 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「0」のミニバッチ入力用プレスホルダー X1 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「1」のミニバッチ入力用プレスホルダー Wx = tf.Variable(tf.random_normal(shape=[n_inputs, n_neurons],dtype=tf.float32)) # Wx (乱数で初期化) Wy = tf.Variable(tf.random_normal(shape=[n_neurons,n_neurons],dtype=tf.float32)) # Wy (乱数で初期化) b = tf.Variable(tf.zeros([1, n_neurons], dtype=tf.float32)) # b (0で初期化) Y0 = tf.tanh(tf.matmul(X0, Wx) + b) # X0 ・Wx Y1 = tf.tanh(tf.matmul(Y0, Wy) + tf.matmul(X1, Wx) + b) # Xy ・Wy + X1 ・Wx + b init = tf.global_variables_initializer() b・ + nn 1 nn: ニューロン数 m: ニバッチのインスタンス数 ni: 入力のフィーチャー数 + ・ m ni m X(t) Y(t-1) Wx ni ni nn Wy nn nn nn
  • 12. v1.1 14.2 TensorFlowによる初歩的なRNN (2) • 各タイムステップでの入力を準備し、1回実行 • ミニバッチの全インスタンスに対する全ニューロンの出力 • 手動➡タイムステップが大きくなると、作成するグラフも大きくなり作成大変 12 import numpy as np # ミニバッチ:インスタンス0、インスタンス1、インスタンス2、インスタンス3 X0_batch = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]) # t = 0 X1_batch = np.array([[9, 8, 7], [0, 0, 0], [6, 5, 4], [3, 2, 1]]) # t = 1 with tf.Session() as sess: init.run() Y0_val, Y1_val = sess.run([Y0, Y1], feed_dict={X0: X0_batch, X1: X1_batch}) X(0) 3 4 X(1) 3 4 >> print(Y0_val) # t = 0 の時点での出力 [[-0.06640061 0.9625767 0.6810579 0.7091854 -0.89821595] # インスタンス0 [ 0.99777555 -0.71978873 -0.99657613 0.96739244 -0.99989706] # インスタンス1 [ 0.99999785 -0.9989881 -0.99999887 0.9967763 -0.9999999 ] # インスタンス2 [ 1. -1. -1. -0.9981892 0.9995087 ]] # インスタンス3 >> print(Y1_val) # t = 1 の時点での出力 [[ 1. -1. -1. 0.40200272 -0.99999994] # インスタンス0 [-0.12210432 0.62805295 0.96718436 -0.9937122 -0.2583932 ] # インスタンス1 [ 0.99999815 -0.9999994 -0.99999744 -0.8594331 -0.99998796] # インスタンス2 [ 0.99928296 -0.9999981 -0.9999059 0.98579615 -0.9220575 ]] # インスタンス3 Y(0)4 5 Y(0)4 5
  • 13. v1.1 14.2.1 時系列に沿った静的なアンロール (1) • TensorFlowのstatic_rnn()関数を用い、前回と同じRNNを作る • セルファクトリ:関数「__call__()」を呼び出すことで、「num_units」個の再帰 ニューロンから構成されるセル(セル層)を作成するファクトリ • static_rnn():入力ごと(X0とX1)に1度ずつセルファクトリの「__call__()」を呼び 出して、共通の重みとバイアスを持つセルを2つ作り、手動構築と同様に連 鎖的にグラフを構築する • output_seqs:個々のタイムステップの出力テンソルを一つにまとめたリスト • states:ネットワークの最終状態を格納するテンソル 基本セルの場合、最終状態は最後の出力と同じ • 上記では、タイムステップが50あると、50個の入力プレスホルダーと50個の 出力テンソルを定義しなければならず面倒。次ページでこれを単純化。 13 X0 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「0」のミニバッチ入力用プレスホルダー X1 = tf.placeholder(tf.float32, [None, n_inputs]) # タイムステップ「1」のミニバッチ入力用プレスホルダー basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) # セルファクトリBasicRNNCellを作成 output_seqs, states = tf.nn.static_rnn(basic_cell, [X0, X1], # セルファクトリと入力テンソルリストを与え、 dtype=tf.float32) # 静的にアンロールされたRNNを作成 Y0, Y1 = output_seqs
  • 14. v1.1 14.2.1 時系列に沿った静的なアンロール (2) • タイムステップ数分の入力プレスホルダー(出力テンソル)を1つ(X)に纏める • 入力を準備し、1回実行 • 実装容易化したがグラフは大きなまま ➡メモリ不足発生要因 (次頁で解決) 14 X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) # [ミニバッチサイズ、タイムステップ数、入力フィーチャー数] X_seqs = tf.unstack(tf.transpose(X, perm=[1, 0, 2])) # タイムステップ数、[ミニバッチサイズ、入力フィーチャー数] # transpose():転置したテンソルを返す unstack():テンソルから、「1次元低いテンソル」のリストを作成して返す basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) output_seqs, states = tf.nn.static_rnn(basic_cell, X_seqs, # X_seqsは[X0, X1]に相当 dtype=tf.float32) outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2]) # タイムステップ数(リスト)、[ミニバッチサイズ、ニューロン数]という形状の出力を、stack()で1つのテンソルンに纏めた後、 # transpose()で転置し、[ミニバッチサイズ、タイムステップ数、入力フィーチャー数]と形状に変更 X_batch = np.array([ # t = 0 t = 1 [[0, 1, 2], [9, 8, 7]], # instance 0 [[3, 4, 5], [0, 0, 0]], # instance 1 [[6, 7, 8], [6, 5, 4]], # instance 2 [[9, 0, 1], [3, 2, 1]], # instance 3 ]) with tf.Session() as sess: init.run() outputs_val = outputs.eval(feed_dict={X: X_batch}) 実行結果
  • 15. v1.1 14.2.2 時系列に沿った動的なアンロール • dynamic_rnn():while_loop()を使い、セルを適切な回数(動的に)実行 – 入力テンソル:[None, n_steps, n_inputs]という形状 (転置不要) – 出力テンソル:[None, n_steps, n_neurons]という形状 (転置不要) • dynamic_rnn()を使って前回と同じRNNを作る • (入力、実行、出力は前回と同じ(形状)のため省略) 15 X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
  • 16. v1.1 14.2.3 可変長入力シーケンスの処理 • 入力シーケンスの長さが一定しない場合(文等)、dynamic_rnn()を呼び出す ときに、インスタンス毎の入力シーケンスの長さを示す1Dテンソルを sequence_length引数として渡せばよい • 入力シーケンス長が短いインスタンスは、0ベクトルでパディングする • 実行時は、sequence_length引数で渡したseq_lengthに値を渡す • 入力シーケンスの長さを超えるタイムステップは0ベクトルが出力される 16 seq_length = tf.placeholder(tf.int32, [None]) #インスタンス毎の入力シーケンスの長さを示す1Dテンソル outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32, sequence_length=seq_length) # sequence_length引数 X_batch = np.array([ # step 0 step 1 [[0, 1, 2], [9, 8, 7]], # instance 0 [[3, 4, 5], [0, 0, 0]], # instance 1 (0ベクトルでパディング) [[6, 7, 8], [6, 5, 4]], # instance 2 [[9, 0, 1], [3, 2, 1]], # instance 3 ]) seq_length_batch = np.array([2, 1, 2, 2]) with tf.Session() as sess: init.run() outputs_val, states_val = sess.run( [outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
  • 17. v1.1 14.2.4 可変長出力シーケンスの処理 • 出力シーケンスも可変長の場合の対応方法は以下 • 入力シーケンスと同じ長さになる場合は、sequence lengthパラメータを設定 • 上記が同じにならない場合(例えば翻訳後の文の長さは不明)、EOSトークン (EOS token:End-Of-Sequence token)を出力し、それ以降は無視する 17
  • 18. v1.1 14.3 RNNの訓練 • RNNの訓練では、時系列に沿ってアンロールし、単純に通常のバックプロ パゲーションを行う (BPTT: backpropagation through time:通時的逆伝搬) • 最初、アンロールされたネットワークを前進パスで通り抜ける (破線) • 次に、無視されない出力を使ったコスト関数(上記ではC(Y(2), Y(3), Y (4) ))を 使って出力を評価し、その勾配を、後退方向に伝えていく (実線) • 最後に、上記過程で計算した勾配を使ってパラメータを更新する – 各ステップで同じW、bが使われるので、全タイムステップの勾配をW、bに反映 18
  • 19. v1.1 14.3.1 シーケンス分類器の訓練 (1) • RNNでMNISTイメージを分類してみる (なお、イメージ分類はCNNの方が適してる) 19 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) 150個の再帰ニューロン n_steps = 28 n_inputs = 28 n_neurons = 150 n_outputs = 10 learning_rate = 0.001 X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) y = tf.placeholder(tf.int32, [None]) basic_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32) logits = tf.layers.dense(states, n_outputs) xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits) loss = tf.reduce_mean(xentropy) optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) training_op = optimizer.minimize(loss) correct = tf.nn.in_top_k(logits, y, 1) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) init = tf.global_variables_initializer() (X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data() X_train = X_train.astype(np.float32).reshape(-1, 28*28) / 255.0 X_test = X_test.astype(np.float32).reshape(-1, 28*28) / 255.0 y_train = y_train.astype(np.int32) y_test = y_test.astype(np.int32) X_valid, X_train = X_train[:5000], X_train[5000:] y_valid, y_train = y_train[:5000], y_train[5000:] def shuffle_batch(X, y, batch_size): rnd_idx = np.random.permutation(len(X)) n_batches = len(X) // batch_size for batch_idx in np.array_split(rnd_idx, n_batches): X_batch, y_batch = X[batch_idx], y[batch_idx] yield X_batch, y_batch X_test = X_test.reshape((-1, n_steps, n_inputs)) ※青字部分以外は、CNNとほぼ同じ ※CNNとほぼ同じ
  • 20. v1.1 14.3.1 シーケンス分類器の訓練 (2) • RNNでMNISTイメージを訓練する • 訓練中の出力 • Testデータで98%を超える正確度が得られた。➡悪くない数字 • HeでRNNの重みを初期化、訓練長期化、正規化等でもっと上がるだろう • RNNの初期化は、ネットワーク構築コードを変数スコープでラップする 20 n_epochs = 100 batch_size = 150 with tf.Session() as sess: init.run() for epoch in range(n_epochs): for X_batch, y_batch in shuffle_batch(X_train, y_train, batch_size): X_batch = X_batch.reshape((-1, n_steps, n_inputs)) sess.run(training_op, feed_dict={X: X_batch, y: y_batch}) acc_batch = accuracy.eval(feed_dict={X: X_batch, y: y_batch}) acc_test = accuracy.eval(feed_dict={X: X_test, y: y_test}) print(epoch, "Last batch accuracy:", acc_batch, "Test accuracy:", acc_test) 0 Last batch accuracy: 0.9533333 Test accuracy: 0.9288 1 Last batch accuracy: 0.96 Test accuracy: 0.9471 2 Last batch accuracy: 0.96 Test accuracy: 0.9499 ... 98 Last batch accuracy: 0.99333334 Test accuracy: 0.977 99 Last batch accuracy: 0.99333334 Test accuracy: 0.9805 with tf.variable_scope(“rnn”, initializer=variance_scaling_initializer()): # ネットワーク構築コードを記載 ※CNNとほぼ同じ
  • 21. v1.1 14.3.2 時系列データを予測するための訓練 (1) • 株価、基本、脳波パタンなどの、時系列データの処理方法を少し見る • 例として、時系列データから無作為に選出した20個の値で訓練する • ターゲットシーケンスは、タイムステップを一つ先にずらしたシーケンス • 各タイムステップで予測値1つのみが 欲しいので、全結合(FC)ラッパーを被せる • なお、この全結合層は、全て同じ重み、 とバイアスを共有する 21 訓練インスタンス インスタンス ターゲット 訓練インスタンス時系列データ
  • 22. v1.1 14.3.2 時系列データを予測するための訓練 (2) • MSE(平均2乗誤差)をコスト関数として、以下のようなコード・結果になる 22 n_steps = 20 n_inputs = 1 n_neurons = 100 n_outputs = 1 X = tf.placeholder(tf.float32, [None, n_steps, n_inputs]) y = tf.placeholder(tf.float32, [None, n_steps, n_outputs]) cell = tf.contrib.rnn.OutputProjectionWrapper( tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons, activation=tf.nn.relu), output_size=n_outputs) # 全結合(FC: Full Connect)ラッパー outputs, states = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32) learning_rate = 0.001 loss = tf.reduce_mean(tf.square(outputs - y)) # MSE optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) training_op = optimizer.minimize(loss) init = tf.global_variables_initializer() saver = tf.train.Saver() n_iterations = 1500 batch_size = 50 with tf.Session() as sess: init.run() for iteration in range(n_iterations): X_batch, y_batch = next_batch(batch_size, n_steps) sess.run(training_op, feed_dict={X: X_batch, y: y_batch}) if iteration % 100 == 0: mse = loss.eval(feed_dict={X: X_batch, y: y_batch}) print(iteration, "¥tMSE:", mse) saver.save(sess, "./my_time_series_model") # not shown in the book 0 MSE: 10.261382 100 MSE: 0.3879291 200 MSE: 0.10900871 300 MSE: 0.06135445 400 MSE: 0.059347205 500 MSE: 0.05819268 600 MSE: 0.05220854 700 MSE: 0.047660623 800 MSE: 0.04888802 900 MSE: 0.047597326 1000 MSE: 0.047681753 1100 MSE: 0.046209298 1200 MSE: 0.039961636 1300 MSE: 0.046320174 1400 MSE: 0.041305345 モデルのテスト結果 インスタンス ターゲット 予測 実行結果
  • 23. v1.1 14.3.2 時系列データを予測するための訓練 (3) • 全結合ラッパーよりも、下記の方が効率が良く大幅なスピードアップが可能  RNNの形状[ステップ数、バッチサイズ、ニューロン数]の出力を、  積み上げて、形状[ステップ数×バッチサイズ、ニューロン数]のテンソルにリシェープし、  全結合(FC)層を通した形状[ステップ数×バッチサイズ、1]の出力を  各ステップでの[バッチサイズ]の出力に展開 23
  • 24. v1.1 14.3.3 独創的RNN • 訓練結果を基に、独創的なシーケンスを生成 • n_steps個の初期値(例えば0)を与え、これを種に、時系列データを生成 • 具体的には、1回毎に1個、1ステップ先のデータを生成し、 これを入力シーケンスに加え、最新n_stepsのシーケンスで処理を繰り返す • 結果例は下記(赤枠部分が、それぞれの初期シーケンス) 24 sequence = [0.] * n_steps for iteration in range(300): X_batch = np.array(sequence[-n_steps:]).reshape(1, n_steps, 1) # 最新のn_stepsのシーケンスを取り出す y_pred = sess.run(outputs, feed_dict={X: X_batch}) sequence.append(y_pred[0, -1, 0]) # 予測シーケンスの最後のデータを入力シーケンスに追加 (注) 初期シーケンスが同じでも、訓練結果によって、独創的シーケンスの内容は変わり、上記と別の結果になる
  • 25. v1.1 14.4 深層RNN • 通常NN同様にセルを積み上げたものが深層RNN • Tensorflowでは、MultiRNNCellで構築可能 25 n_neurons = 100 n_layers = 3 layers = [tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) for layer in range(n_layers)] # セルのリスト multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(layers) # 深層RNNのセル outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32) # 深層RNN 深層RNN 時系列に沿って深層RNNをアンロールしたもの
  • 26. v1.1 14.4.1 複数のGPUによる深層RNNの分散処理 • 深層RNNを複数GPUで分散処理するには、工夫が必要 – BasicRNNCellがセルそのものではないため、BasicRNNCell作成時にGPUを指定できない – MultiRNNCellがBasicRNNCellを呼び出してセルを作るが、デバイスを指定できない • 下記の様に、独自のラッパセルを作ることで、処理を複数GPUに分散可能 26 class DeviceCellWrapper(tf.nn.rnn_cell.RNNCell): def __init__(self, device, cell): self._cell = cell self._device = device @property def state_size(self): return self._cell.state_size @property def output_size(self): return self._cell.output_size def __call__(self, inputs, state, scope=None): # 実セル作成時に呼び出される with tf.device(self._device): # セルの処理をデバイスに割り当てる return self._cell(inputs, state, scope) devices = ["/gpu:0", "/gpu:1", "/cpu:0"] cells = [DeviceCellWrapper(dev,tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons)) for dev in devices] multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(cells) outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)
  • 27. v1.1 14.4.2 ドロップアウトの適用 • RNNの層間でドロップアウトを適用するにはDropoutWrapperを使う • keep_probは、訓練中は好きな値(通常0.5)、テスト時はデフォルト(1.0)にする 27 keep_prob = tf.placeholder_with_default(1.0, shape=()) cells = [tf.nn.rnn_cell.BasicRNNCell(num_units=n_neurons) for layer in range(n_layers)] cells_drop = [tf.nn.rnn_cell.DropoutWrapper(cell, input_keep_prob=keep_prob) for cell in cells] multi_layer_cell = tf.nn.rnn_cell.MultiRNNCell(cells_drop) rnn_outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32) # 訓練中 train_keep_prob = 0.5 with tf.Session() as sess: init.run() for iteration in range(n_iterations): X_batch, y_batch = next_batch(batch_size, n_steps) _, mse = sess.run([training_op, loss], feed_dict={X: X_batch, y: y_batch, keep_prob: train_keep_prob}) saver.save(sess, "./my_dropout_time_series_model") # テスト時 with tf.Session() as sess: saver.restore(sess, "./my_dropout_time_series_model") X_new = time_series(np.array(t_instance[:-1].reshape(-1, n_steps, n_inputs))) # keep_prob未指定なので、変数定義時のデフォルト値(1.0)になる y_pred = sess.run(outputs, feed_dict={X: X_new})
  • 28. v1.1 14.4.3 多数のタイムステップによる訓練の難しさ • 長いシーケンスに対するRNNは、ステップ(横)方向に深いネットワークになる • そのため、深層NNの常として、勾配消失/爆発問題の影響を受ける • 対策として、パラメータの良い初期化方法、飽和を起こさない活性化関数、 バッチ正規化、勾配クリップなどは、RNNでも使える • しかし、少し長いシーケンスでも100個程度になり、訓練が遅くなりがち • 良く使われる対策は、時系列に沿ったバックプロパゲーションの途中打ち切 り (訓練中は、入力シーケンスを途中で切ってしまう)だが、色々と副作用あり • また、長いRNNは、最初の入力の記憶が次第に消えるという問題もあり – 最初のステップの入力の痕跡が、後の方のステップでは殆ど無くなる – 文章の最初に結論を言って、後から情報を追加すると、結論が忘れられる可能性あり • 記憶が消える問題への対策として、長期記憶を持つ各種セルが考案された – 長期記憶を持つセルは効果が、その効果が実証されている • 以下では、長期記憶セルとして人気のあるLSTMとGRUを見ていく 28
  • 29. v1.1 14.5 LSTMセル (1) • LSTM(長期短期記憶:long short-term memory)は、Sepp Hochreiter他が 1997年に提案し、多くの人々が研究に少しずつ改良し、現在の形になった • 基本セルの代わりにLSTMを使うだけで、訓練は短時間で収束し、データ内 の長期的な依存関係を検出できる、非常の性能の良いRNNになる • 短期的な記憶「h(t)」に加え、長期的な記憶「c(t)」を入力・出力する • 長期記憶から捨てるべき要素(忘却)、長期的記憶に格納すべき要素(入力)、 短期記憶/出力で読み取るべき要素(出力)を、3つのゲートコントローラ(下記 のf(t)、i(t)、o(t))で制御し、最適なゲートコントローラを学習できることが特徴 29 lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=n_neurons) 前ステップの長期記憶 前ステップの短期記憶 出力長期記憶 出力短期記憶 忘却ゲート 入力ゲート 出力ゲート 要素毎の乗算 要素毎の加算 出力は0~1の範囲
  • 31. v1.1 14.5.1 ピープホール接続 • 基本LSTMセルでは、各ゲートのコントローラ(全結合層)は、「x(t)」と直前の 短期記憶「h(t-1)」を入力しているが、長期記憶「c(t)」を入力に加えることを、 ピープホール接続と呼ぶ (Felix他が2000年に提案) • TensorFlowでピープホール接続を実装するには、BasicLSTMCellでなく、 LSTMCellを使い、use_peepholes=Trueを指定すればよい • LSTMセルには、ほかにも多数の変種がある その中で特に人気のあるGRUセルを次に紹介する 31 lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=n_neurons, use_peepholes=True)
  • 32. v1.1 14.6 GRUセル • GRU (Gated Recurrent Unit)は、Kyunghyun Chao等が2014年提案 • LSTMを単純化したものであり、LSTMとほぼ同様に機能する – 長期記憶と短期記憶が結合されて、一つのベクトル「h(t)」になっている – 一つのゲートコントローラ「z(t)」で、忘却ゲートと入力ゲートの両方を制御 • 値が1の場合忘却ゲートが開き、入力ゲートが閉じる。値が0の場合はその逆 – 出力ゲートが無い。代わりに、直前の状態のどの部分をメイン層で用いるかを制御す る新しいゲートコントローラ「r(t)」が追加されている 32 式14-4 GRUの計算式 • LSTM、GRUセルは、RNN成功の理由であり、自然言語処理でも応用されている
  • 33. v1.1 14.7 自然言語処理 • 機械翻訳、自動要約、構文解析、感情分析などの最先端の自然言語処理 (NLP: Natural Language Processing)の多くは、RNNを基礎としている • 以下では、機械翻訳のモデルがどのようになっているかを簡単に紹介 • 詳細は、以下で説明されている – Word2Vec: https://www.tensorflow.org/tutorials/representation/word2vec – Seq2Seq: https://github.com/tensorflow/nmt 33
  • 34. v1.1 14.7.1 単語の埋め込み • 自然言語処理の入口として、まずは、単語の表現方法を選ぶ必要がある • 単語間の関係は当初不明なので、ワンホットベクトル表現が考えられる – ワンホットベクトルの例: (0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...,0) – 語彙集が5万語含むとき、1要素が1、他は0の疎な表現になり、メモリ効率が非常に悪い • もっとも一般的な買いは、埋め込みと呼ばれる手法であり、単語を小さく密な ベクトル空間(150次元程度)に埋め込み、NNで単語のベクトル値を学習する • 訓練開始時は、埋め込みベクトルの値は無作為だが、訓練中にバックプロパ ゲーションによって、埋め込みベクトルの値を自動的に書き換えていく – 文章の途中までの単語列を入力シーケンスにし、次の単語を予測するようNNを訓練 • 訓練で、類似する単語は互いに近づき、かなり意味のある形で組織される 34 woman – man ≒ queen - king walked – walking ≒ swam - swimming 首都 – 国は、ほぼ同じベクトル
  • 35. v1.1 14.7.2 機械翻訳のためのエンコーダ-デコーダネットワーク (1) • 英語の文をフランス語に翻訳する簡単な機械翻訳モデルを見てみる ※ seq2seqサイト(https://github.com/tensorflow/nmt) の内容を記載(入力文の語順は元のまま) • エンコーダが入力文を意味ベクトルに変換、デコーダが意味ベクトルから翻訳文を生成 • エンコーダとデコーダは深層RNN(下図は2層)で、前段に埋め込み層を持つ 35 入力は単語の語彙辞書内番号の列 例えば、[12, 47, 7, 834] 各単語が150次元ベクトル空間に埋め込まれる 深層RNN (2層) 各ステップの出力を出力辞書長のロジットに変換 (完全結合) ロスとして、ターゲット文と翻訳文の差異を計算 (sparse_softmax_cross_entropy_with_logits)
  • 36. v1.1 14.7.2 機械翻訳のためのエンコーダ-デコーダネットワーク (2) • 下記、英独翻訳の訓練済みデータを含む、各種DLモデルが公開されている – https://github.com/tensorflow/tensor2tensor – Google Colaboratoryで、英独翻訳の訓練済みデータを試せる • https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb 36 入力と出力の例
  • 37. v1.1 付録 RNNに少し関連した最近の動向(1) • 2018/11/2、Googleが言語表現事前訓練手法「BERT」をオープンソース公開 – 世界最高レベルの訓練手法であり、事前学習済モデルも一緒に公開されている – Google曰く:『世界の誰もが、「単一Cloud TPUなら約30分」「単一GPUなら約数時間」で、独 自の「最新の質問応答システム」や「その他のさまざまなモデル」を訓練できる』 – BERTを使った例が、Google Colaboratoryノートブックで公開されている • https://colab.research.google.com/github/google- research/bert/blob/master/predicting_movie_reviews_with_bert_on_tf_hub.ipynb • 2018/12/4、NIPSで、時系列データの全く新しい分析手法(ODE)が提案された – 時系列データに欠損値があったり、入力データ感覚が不揃いな場合に対応できる – ResNetの層構造の式が、常微分方程式(ODE)の解法(オイラー法)に似ていることに着想 – ODEなら、賢いODE SOlverを活用でき、また、離散化された層構造に縛られない – MNISTでの試行結果:RestNetと同じ精度だが、パラメータ・メモリ使用量が少ない – 紹介記事:https://www.slideshare.net/DeepLearningJP2016/dlneural-ordinary-differential-equations 37 BERT:Bidirectional Encoder Representations from Transformers
  • 38. v1.1 付録 RNNに少し関連した最近の動向 (2) • 2019/2/19、OpenAIが本物と見分けがつかないフェイクニュースを自動生成 – https://gigazine.net/news/20190216-ai-fake-text-generator-dangerous-release/ 38 入力 出力 自動生成