SlideShare a Scribd company logo
深層学習後半
Tatsunori Ueno
深層学習DAY3
2021/7/17
Section1:再帰型ニューラルネットワークの
概念
◦ 時系列データに対応可能なニュートラルネットワーク。
◦ 時系列データとは、音声データ、株価データ、テキストデータなどがある。
◦ RNN(Reccurent Neural Netowrk)
◦ RNNの数学的記述
◦ RNNの特徴(再帰的構造)
◦ BPTTとは、RNNにおいてのパラメータ調整方法の一種である。
◦ t時間目とt-1時間目には関係がある事が見てとれる。
◦ パラメータの更新式
◦ RNNが過去の時間を再帰的にたくわえている事を示している。
Section1:再帰型ニューラルネットワークの概念
import numpy as np
from common import functions
import matplotlib.pyplot as plt
def d_tanh(x):
sinh = (np.exp(x) - np.exp(-x)) / 2
cosh = (np.exp(x) + np.exp(-x)) / 2
return (cosh**2 - sinh**2) / cosh**2
# データを用意
# 2進数の桁数
binary_dim = 8
# 最大値 + 1
largest_number = pow(2, binary_dim)
# largest_numberまで2進数を用意
binary = np.unpackbits(np.array([range(largest_number)],dtype=np.uint8).T,axis=1)
input_layer_size = 2
hidden_layer_size = 16 #16
output_layer_size = 1
weight_init_std = 1
learning_rate = 0.1 #0.1
iters_num = 10000
plot_interval = 100
# ウェイト初期化 (バイアスは簡単のため省略)
W_in = weight_init_std * np.random.randn(input_layer_size, hidden_layer_size)
W_out = weight_init_std * np.random.randn(hidden_layer_size, output_layer_size)
W = weight_init_std * np.random.randn(hidden_layer_size, hidden_layer_size)
# Xavier
W_in = np.random.randn(input_layer_size, hidden_layer_size) / (np.sqrt(input_layer_size))
W_out = np.random.randn(hidden_layer_size, output_layer_size) / (np.sqrt(hidden_layer_size))
W = np.random.randn(hidden_layer_size, hidden_layer_size) / (np.sqrt(hidden_layer_size))
# He
# W_in = np.random.randn(input_layer_size, hidden_layer_size) / np.sqrt(input_layer_size) *
np.sqrt(2)
# W_out = np.random.randn(hidden_layer_size, output_layer_size) / np.sqrt(hidden_layer_size) *
np.sqrt(2)
# W = np.random.randn(hidden_layer_size, hidden_layer_size) / np.sqrt(hidden_layer_size) *
np.sqrt(2)
# 勾配
W_in_grad = np.zeros_like(W_in)
W_out_grad = np.zeros_like(W_out)
W_grad = np.zeros_like(W)
u = np.zeros((hidden_layer_size, binary_dim + 1))
z = np.zeros((hidden_layer_size, binary_dim + 1))
y = np.zeros((output_layer_size, binary_dim))
delta_out = np.zeros((output_layer_size, binary_dim))
delta = np.zeros((hidden_layer_size, binary_dim + 1))
all_losses = []
for i in range(iters_num):
# A, B初期化 (a + b = d)
a_int = np.random.randint(largest_number/2)
a_bin = binary[a_int] # binary encoding
b_int = np.random.randint(largest_number/2)
b_bin = binary[b_int] # binary encoding
# 正解データ
d_int = a_int + b_int
d_bin = binary[d_int]
# 出力バイナリ
out_bin = np.zeros_like(d_bin)
# 時系列全体の誤差
all_loss = 0
# 時系列ループ
for t in range(binary_dim):
# 入力値
X = np.array([a_bin[ - t - 1], b_bin[ - t - 1]]).reshape(1, -1)
# 時刻tにおける正解データ
dd = np.array([d_bin[binary_dim - t - 1]])
u[:,t+1] = np.dot(X, W_in) + np.dot(z[:,t].reshape(1, -1), W)
z[:,t+1] = functions.sigmoid(u[:,t+1])
y[:,t] = functions.sigmoid(np.dot(z[:,t+1].reshape(1, -1), W_out))
#誤差
loss = functions.mean_squared_error(dd, y[:,t])
delta_out[:,t] = functions.d_mean_squared_error(dd, y[:,t]) * functions.d_sigmoid(y[:,t])
all_loss += loss
out_bin[binary_dim - t - 1] = np.round(y[:,t])
for t in range(binary_dim)[::-1]:
X = np.array([a_bin[-t-1],b_bin[-t-1]]).reshape(1, -1)
delta[:,t] = (np.dot(delta[:,t+1].T, W.T) + np.dot(delta_out[:,t].T, W_out.T)) * functions.d_sigmoid(u[:,t+1])
# 勾配更新
W_out_grad += np.dot(z[:,t+1].reshape(-1,1), delta_out[:,t].reshape(-1,1))
W_grad += np.dot(z[:,t].reshape(-1,1), delta[:,t].reshape(1,-1))
W_in_grad += np.dot(X.T, delta[:,t].reshape(1,-1))
# 勾配適用
W_in -= learning_rate * W_in_grad
W_out -= learning_rate * W_out_grad
W -= learning_rate * W_grad
W_in_grad *= 0
W_out_grad *= 0
W_grad *= 0
if(i % plot_interval == 0):
all_losses.append(all_loss)
print("iters:" + str(i))
print("Loss:" + str(all_loss))
print("Pred:" + str(out_bin))
print("True:" + str(d_bin))
out_int = 0
for index,x in enumerate(reversed(out_bin)):
out_int += x * pow(2, index)
print(str(a_int) + " + " + str(b_int) + " = " + str(out_int))
print("------------")
lists = range(0, iters_num, plot_interval)
plt.plot(lists, all_losses, label="loss")
plt.show()
中間層の活性化関数
をtanhに変更し
モデルに合った活性化関数を使うことが大切である。
確認テスト
◦ 1. RNNのネットワークには大きくわけて3つの重みがある。1つは入力から現在の中間層を定義する際にかけられる重み、1つは中間
層から出力を定義する際にかけられる重みである。残り1つの重みについて説明せよ。
◦ 2.連鎖率の原理を使い、dz/dx を求めよ。
◦ 3.下図を数式で表せ。※バイアスは任意の文字で定義せよ。
◦ ※また中間層の出力にシグモイド関数g(x)を作用させよ。
解答:
中間層から中間層へ至るところの重み。前の中間層からの重み。
𝜕𝑧
𝜕𝑡
= 2𝑡
𝜕𝑡
𝜕𝑥
= 1
𝜕𝑧
𝜕𝑡
𝜕𝑡
𝜕𝑥
= 2𝑡
𝜕𝑧
𝜕𝑥
= 2(𝑥 + 𝑦)
Section2:LSTM
◦ RNNの課題の解決:これまでに触れた勾配消失の解決方法(tanh等の勾配消失問題に強い活性化関数を用いる、あるいは正
則化を用いる等)とは別に、構造自体を変えて解決したものがLSTM。
◦ 勾配消失問題:誤差逆伝播法が下位層に進んで行くに連れて、勾配がどんどん緩やかになっていく。そのため、勾配降下法による更新では、
下位層のパラメータはほとんど変わらず、訓練は最適解に収束しなくなる。(例)シグモイド関数
◦ 勾配爆発:勾配が層を逆伝播するごとに指数関数的に大きくなっていく⇒勾配クリッピング
◦ LSTMの全体図
◦ CEC(Constant Error Carousel)記憶機能だけを持つもの
◦ CECの課題:入力データについて、時間依存に関係なく一律である(ニューラルネットワークの学習特性が無いという事)
◦ 入力ゲートと出力ゲートを追加する事で、それぞれのゲートへの入力値の重みを、重み行列で可変とする(CECの課題を解決)
◦ LSTMの現状
◦ CECには過去の情報が全て保管されている。
◦ LSTMブロックの課題:過去の情報が要らなくなった場合、そのタイミングで情報を忘却する機能が必要⇒忘却ゲート
◦ 覗き穴結合:CEC自身の値に重み行列を介して伝播可能にした構造(実際にはあまり大きな効果の改善は見られない。)
Section2:LSTM
from keras.utils import np_utils # keras.utilsからnp_utilsをイン
ポート
from keras.datasets import mnist # MNISTデータセットをイン
ポート
# MNISTデータセットの読み込み
(x_trains, y_trains), (x_tests, y_tests) = mnist.load_data()
# 訓練データ
x_trains = x_trains.astype('float32') # float32型に変換
x_trains /= 255 # 0から1.0の範囲に変換
# 正解ラベルをワンホット表現に変換
correct = 10 # 正解ラベルの数
y_trains = np_utils.to_categorical(y_trains, correct)
# テストデータ
x_tests = x_tests.astype('float32') # float32型に変換
x_tests /= 255 # 0から1.0の範囲に変換
# 正解ラベルをワンホット表現に変換
y_tests = np_utils.to_categorical(y_tests, correct)
print(x_trains.shape) # 訓練データの形状を出力
print(x_tests.shape) # テストデータの形状を出力
# RNNの構築
from keras.models import Sequential
from keras.layers import InputLayer, Dense
from keras.layers.recurrent import LSTM
from keras import optimizers,regularizers
# Sequentialオブジェクトを生成
model = Sequential()
## 入力層
# 入力データの形状は(28, 28)
model.add(
InputLayer(input_shape=(28,28))
)
## 中間層
# LSTMブロック(ユニット数=128)
weight_decay = 1e-4 # ハイパーパラメーター
model.add(LSTM(units=128, dropout=0.25, return_sequences=True))
model.add(LSTM(units=128, dropout=0.25, return_sequences=True))
model.add(LSTM(units=128, dropout=0.25, return_sequences=False,
kernel_regularizer=regularizers.l2(weight_decay)) # 正則化
)
## 出力層
model.add(
Dense(units=10, # 出力層のニューロン数は10
activation='softmax') # 活性化はシグモイド関数
)
# Squentialオブジェクをコンパイル
model.compile(
loss='categorical_crossentropy', # 誤差関数はクロスエントロピー
optimizer=optimizers.Adam(), # Adamオプティマイザー
metrics=['accuracy'] # 学習評価として正解率を指定
)
model.summary() # RNNのサマリ(概要)を出力
# 学習を開始
history = model.fit(x_trains, y_trains, # 訓練データ、正
解ラベル
batch_size=100, # ミニバッチのサイズ
epochs=10, # 学習回数
verbose=1, # 学習の進捗状況を出力す
る
validation_data=( # テストデータの指定
x_tests, y_tests)
)
# 損失と正解率をグラフにする
%matplotlib inline
import matplotlib.pyplot as plt
# プロット図のサイズを設定
plt.figure(figsize=(15, 6))
# プロット図を縮小して図の間のスペースを空ける
plt.subplots_adjust(wspace=0.2)
# 1×2のグリッドの左(1,2,1)の領域にプロット
plt.subplot(1, 2, 1)
# 訓練データの損失(誤り率)をプロット
plt.plot(history.history['loss'],
label='training',
color='black')
# テストデータの損失(誤り率)をプロット
plt.plot(history.history['val_loss'],
label='test',
color='red')
plt.ylim(0, 1) # y軸の範囲
plt.legend() # 凡例を表示
plt.grid() # グリッド表示
plt.xlabel('epoch') # x軸ラベル
plt.ylabel('loss') # y軸ラベル
# 1×2のグリッドの右(1,2,21)の領域にプロット
plt.subplot(1, 2, 2)
# 訓練データの正解率をプロット
plt.plot(history.history['acc'],
label='training',
color='black')
# テストデータの正解率をプロット
plt.plot(history.history['val_acc'],
label='test',
color='red')
plt.ylim(0.5, 1) # y軸の範囲
plt.legend() # 凡例を表示
plt.grid() # グリッド表示
plt.xlabel('epoch') # x軸ラベル
plt.ylabel('acc') # y軸ラベル
plt.show()
時間がかかった。
結果は良かった。
確認テスト
◦ 1.シグモイド関数を微分した時、入力値が0の時に最大値をとる。その値として正しいものを選択肢から選べ。
1. 0.15
2. 0.25
3. 0.35
4. 0.45
◦ 2.以下の文章をLSTMに入力し空欄に当てはまる単語を予測したいとする。
文中の「とても」という言葉は空欄の予測においてなくなっても影響を及ぼさないと考えられる。
このような場合、どのゲートが作用すると考えられるか。
◦ 「映画おもしろかったね。ところで、とてもお腹が空いたから何か_____。」
解答:2
解答:忘却ゲート
Section3:GRU
◦ GRU(Gated Recurrent Unit)
◦ リセットゲートと更新ゲートがある。
◦ LSTMの改良版である
◦ LSTMでは、パラメータ数が多く、計算負荷が高くなる問題があった。
◦ GRUはパラメータを大幅に削減し(計算負荷が低い)、精度は同等またはそれ以上が望める様になった構造を持つ。
◦ Leaky integrationだけを使ってメモリを公開する。
Section3:GRU
import tensorflow as tf
import numpy as np
import re
import glob
import collections
import random
import pickle
import time
import datetime
import os
# logging levelを変更
tf.logging.set_verbosity(tf.logging.ERROR)
class Corpus:
def __init__(self):
self.unknown_word_symbol = "<???>" # 出現回数の少ない単語は未知語として定義しておく
self.unknown_word_threshold = 3 # 未知語と定義する単語の出現回数の閾値
self.corpus_file = "./corpus/**/*.txt"
self.corpus_encoding = "utf-8"
self.dictionary_filename = "./data_for_predict/word_dict.dic"
self.chunk_size = 5
self.load_dict()
words = []
for filename in glob.glob(self.corpus_file, recursive=True):
with open(filename, "r", encoding=self.corpus_encoding) as f:
# word breaking
text = f.read()
# 全ての文字を小文字に統一し、改行をスペースに変換
text = text.lower().replace("n", " ")
# 特定の文字以外の文字を空文字に置換する
text = re.sub(r"[^a-z '-]", "", text)
# 複数のスペースはスペース一文字に変換
text = re.sub(r"[ ]+", " ", text)
# 前処理: '-' で始まる単語は無視する
words = [ word for word in text.split() if not word.startswith("-")]
self.data_n = len(words) - self.chunk_size
self.data = self.seq_to_matrix(words)
def prepare_data(self):
"""
訓練データとテストデータを準備する。
data_n = ( text データの総単語数 ) - chunk_size
input: (data_n, chunk_size, vocabulary_size)
output: (data_n, vocabulary_size)
"""
# 入力と出力の次元テンソルを準備
all_input = np.zeros([self.chunk_size, self.vocabulary_size, self.data_n])
all_output = np.zeros([self.vocabulary_size, self.data_n])
# 準備したテンソルに、コーパスの one-hot 表現(self.data) のデータを埋めていく
# i 番目から ( i + chunk_size - 1 ) 番目までの単語が1組の入力となる
# このときの出力は ( i + chunk_size ) 番目の単語
for i in range(self.data_n):
all_output[:, i] = self.data[:, i + self.chunk_size] # (i + chunk_size) 番目の単語の one-hot ベクトル
for j in range(self.chunk_size):
all_input[j, :, i] = self.data[:, i + self.chunk_size - j - 1]
# 後に使うデータ形式に合わせるために転置を取る
all_input = all_input.transpose([2, 0, 1])
all_output = all_output.transpose()
# 訓練データ:テストデータを 4 : 1 に分割する
training_num = ( self.data_n * 4 ) // 5
return all_input[:training_num], all_output[:training_num], all_input[training_num:],
all_output[training_num:]
def build_dict(self):
# コーパス全体を見て、単語の出現回数をカウントする
counter = collections.Counter()
for filename in glob.glob(self.corpus_file, recursive=True):
with open(filename, "r", encoding=self.corpus_encoding) as f:
# word breaking
text = f.read()
# 全ての文字を小文字に統一し、改行をスペースに変換
text = text.lower().replace("n", " ")
# 特定の文字以外の文字を空文字に置換する
text = re.sub(r"[^a-z '-]", "", text)
# 複数のスペースはスペース一文字に変換
text = re.sub(r"[ ]+", " ", text)
# 前処理: '-' で始まる単語は無視する
words = [word for word in text.split() if not word.startswith("-")]
counter.update(words)
# 出現頻度の低い単語を一つの記号にまとめる
word_id = 0
dictionary = {}
for word, count in counter.items():
if count <= self.unknown_word_threshold:
continue
dictionary[word] = word_id
word_id += 1
dictionary[self.unknown_word_symbol] = word_id
print("総単語数:", len(dictionary))
# 辞書を pickle を使って保存しておく
with open(self.dictionary_filename, "wb") as f:
pickle.dump(dictionary, f)
print("Dictionary is saved to", self.dictionary_filename)
self.dictionary = dictionary
print(self.dictionary)
def load_dict(self):
with open(self.dictionary_filename, "rb") as f:
self.dictionary = pickle.load(f)
self.vocabulary_size = len(self.dictionary)
self.input_layer_size = len(self.dictionary)
self.output_layer_size = len(self.dictionary)
print("総単語数: ", self.input_layer_size)
def get_word_id(self, word):
# print(word)
# print(self.dictionary)
# print(self.unknown_word_symbol)
# print(self.dictionary[self.unknown_word_symbol])
# print(self.dictionary.get(word, self.dictionary[self.unknown_word_symbol]))
return self.dictionary.get(word, self.dictionary[self.unknown_word_symbol])
# 入力された単語を one-hot ベクトルにする
def to_one_hot(self, word):
index = self.get_word_id(word)
data = np.zeros(self.vocabulary_size)
data[index] = 1
return data
def seq_to_matrix(self, seq):
print(seq)
data = np.array([self.to_one_hot(word) for word in seq]) # (data_n,
vocabulary_size)
return data.transpose() # (vocabulary_size, data_n)
class Language:
"""
input layer: self.vocabulary_size
hidden layer: rnn_size = 30
output layer: self.vocabulary_size
"""
def __init__(self):
self.corpus = Corpus()
self.dictionary = self.corpus.dictionary
self.vocabulary_size = len(self.dictionary) # 単語数
self.input_layer_size = self.vocabulary_size # 入力層の数
self.hidden_layer_size = 30 # 隠れ層の RNN ユニットの数
self.output_layer_size = self.vocabulary_size # 出力層の数
self.batch_size = 128 # バッチサイズ
self.chunk_size = 5 # 展開するシーケンスの数。c_0, c_1, ..., c_(chunk_size - 1)
を入力し、c_(chunk_size) 番目の単語の確率が出力される。
self.learning_rate = 0.005 # 学習率
self.epochs = 1000 # 学習するエポック数
self.forget_bias = 1.0 # LSTM における忘却ゲートのバイアス
self.model_filename = "./data_for_predict/predict_model.ckpt"
self.unknown_word_symbol = self.corpus.unknown_word_symbol
def inference(self, input_data, initial_state):
"""
:param input_data: (batch_size, chunk_size, vocabulary_size) 次元のテンソル
:param initial_state: (batch_size, hidden_layer_size) 次元の行列
:return:
"""
# 重みとバイアスの初期化
hidden_w = tf.Variable(tf.truncated_normal([self.input_layer_size,
self.hidden_layer_size], stddev=0.01))
hidden_b = tf.Variable(tf.ones([self.hidden_layer_size]))
output_w = tf.Variable(tf.truncated_normal([self.hidden_layer_size,
self.output_layer_size], stddev=0.01))
output_b = tf.Variable(tf.ones([self.output_layer_size]))
# BasicLSTMCell, BasicRNNCell は (batch_size, hidden_layer_size) が chunk_size 数
ぶんつながったリストを入力とする。
# 現時点での入力データは (batch_size, chunk_size, input_layer_size) という3
次元のテンソルなので
# tf.transpose や tf.reshape などを駆使してテンソルのサイズを調整する。
input_data = tf.transpose(input_data, [1, 0, 2]) # 転置。(chunk_size, batch_size,
vocabulary_size)
input_data = tf.reshape(input_data, [-1, self.input_layer_size]) # 変形。
(chunk_size * batch_size, input_layer_size)
input_data = tf.matmul(input_data, hidden_w) + hidden_b # 重みWとバイアスB
を適用。 (chunk_size, batch_size, hidden_layer_size)
input_data = tf.split(input_data, self.chunk_size, 0) # リストに分割。chunk_size *
(batch_size, hidden_layer_size)
# RNN のセルを定義する。RNN Cell の他に LSTM のセルや GRU のセルなどが
利用できる。
cell = tf.nn.rnn_cell.BasicRNNCell(self.hidden_layer_size)
outputs, states = tf.nn.static_rnn(cell, input_data, initial_state=initial_state)
# 最後に隠れ層から出力層につながる重みとバイアスを処理する
# 最終的に softmax 関数で処理し、確率として解釈される。
# softmax 関数はこの関数の外で定義する。
output = tf.matmul(outputs[-1], output_w) + output_b
return output
def loss(self, logits, labels):
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,
labels=labels))
return cost
def training(self, cost):
# 今回は最適化手法として Adam を選択する。
# ここの AdamOptimizer の部分を変えることで、Adagrad, Adadelta などの他
の最適化手法を選択することができる
optimizer =
tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(cost)
return optimizer
def train(self):
# 変数などの用意
input_data = tf.placeholder("float", [None, self.chunk_size, self.input_layer_size])
actual_labels = tf.placeholder("float", [None, self.output_layer_size])
initial_state = tf.placeholder("float", [None, self.hidden_layer_size])
prediction = self.inference(input_data, initial_state)
cost = self.loss(prediction, actual_labels)
optimizer = self.training(cost)
correct = tf.equal(tf.argmax(prediction, 1), tf.argmax(actual_labels, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
# TensorBoard で可視化するため、クロスエントロピーをサマリーに追加
tf.summary.scalar("Cross entropy: ", cost)
summary = tf.summary.merge_all()
# 訓練・テストデータの用意
# corpus = Corpus()
trX, trY, teX, teY = self.corpus.prepare_data()
training_num = trX.shape[0]
# ログを保存するためのディレクトリ
timestamp = time.time()
dirname = datetime.datetime.fromtimestamp(timestamp).strftime("%Y%m%d%H%M%S")
# ここから実際に学習を走らせる
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
summary_writer = tf.summary.FileWriter("./log/" + dirname, sess.graph)
# エポックを回す
for epoch in range(self.epochs):
step = 0
epoch_loss = 0
epoch_acc = 0
# 訓練データをバッチサイズごとに分けて学習させる (= optimizer を走らせる)
# エポックごとの損失関数の合計値や(訓練データに対する)精度も計算しておく
while (step + 1) * self.batch_size < training_num:
start_idx = step * self.batch_size
end_idx = (step + 1) * self.batch_size
batch_xs = trX[start_idx:end_idx, :, :]
batch_ys = trY[start_idx:end_idx, :]
_, c, a = sess.run([optimizer, cost, accuracy],
feed_dict={input_data: batch_xs,
actual_labels: batch_ys,
initial_state: np.zeros([self.batch_size, self.hidden_layer_size])
}
)
epoch_loss += c
epoch_acc += a
step += 1
# コンソールに損失関数の値や精度を出力しておく
print("Epoch", epoch, "completed ouf of", self.epochs, "-- loss:", epoch_loss, " -- accuracy:",
epoch_acc / step)
# Epochが終わるごとにTensorBoard用に値を保存
summary_str = sess.run(summary, feed_dict={input_data: trX,
actual_labels: trY,
initial_state: np.zeros(
[trX.shape[0],
self.hidden_layer_size]
)
}
)
summary_writer.add_summary(summary_str, epoch)
summary_writer.flush()
# 学習したモデルも保存しておく
saver = tf.train.Saver()
saver.save(sess, self.model_filename)
# 最後にテストデータでの精度を計算して表示する
a = sess.run(accuracy, feed_dict={input_data: teX, actual_labels: teY,
initial_state: np.zeros([teX.shape[0], self.hidden_layer_size])})
print("Accuracy on test:", a)
def predict(self, seq):
"""
文章を入力したときに次に来る単語を予測する
:param seq: 予測したい単語の直前の文字列。chunk_size 以上の単語数が必要。
:return:
"""
# 最初に復元したい変数をすべて定義してしまいます
tf.reset_default_graph()
input_data = tf.placeholder("float", [None, self.chunk_size, self.input_layer_size])
initial_state = tf.placeholder("float", [None, self.hidden_layer_size])
prediction = tf.nn.softmax(self.inference(input_data, initial_state))
predicted_labels = tf.argmax(prediction, 1)
# 入力データの作成
# seq を one-hot 表現に変換する。
words = [word for word in seq.split() if not word.startswith("-")]
x = np.zeros([1, self.chunk_size, self.input_layer_size])
for i in range(self.chunk_size):
word = seq[len(words) - self.chunk_size + i]
index = self.dictionary.get(word, self.dictionary[self.unknown_word_symbol])
x[0][i][index] = 1
feed_dict = {
input_data: x, # (1, chunk_size, vocabulary_size)
initial_state: np.zeros([1, self.hidden_layer_size])
}
# tf.Session()を用意
with tf.Session() as sess:
# 保存したモデルをロードする。ロード前にすべての変数を用意しておく必要がある。
saver = tf.train.Saver()
saver.restore(sess, self.model_filename)
# ロードしたモデルを使って予測結果を計算
u, v = sess.run([prediction, predicted_labels], feed_dict=feed_dict)
keys = list(self.dictionary.keys())
# コンソールに文字ごとの確率を表示
for i in range(self.vocabulary_size):
c = self.unknown_word_symbol if i == (self.vocabulary_size - 1) else keys[i]
print(c, ":", u[0][i])
print("Prediction:", seq + " " + ("<???>" if v[0] == (self.vocabulary_size - 1) else keys[v[0]]))
return u[0]
def build_dict():
cp = Corpus()
cp.build_dict()
if __name__ == "__main__":
#build_dict()
ln = Language()
# 学習するときに呼び出す
#ln.train()
# 保存したモデルを使って単語の予測をする
ln.predict("some of them looks like")
確認テスト
◦ 1.LSTMとCECが抱える課題について、それぞれ簡潔に述べよ。
解答:
LSTMは入力ゲート、出力ゲート、忘却ゲートそしてCEC、それぞれ4つの部品を持つ事で構成されていた。
そのため、LSTMではパラメータ数が多く、計算負荷が高くなるという課題があった。
その中にあるCECであるが、問題点としては学習能力が無い事が挙げられる。(そのために3つのゲートを周りに付け、学習
機能を持たせている、というのがCECの根本的な動きになっている。)
◦ 2.LSTMとGRUの違いを簡潔に述べよ。
解答:
LSTMには入力ゲート、出力ゲート、忘却ゲートの3つのゲートとCECがある。
1方のGRUにはCECが無く更新ゲートとリセットゲートを持つ。
LSTMはパラメータが多く、GRUはパラメータが少ない。
LSTMよりGRUの方が計算量は少ない。
Section4:双方向RNN
◦ 双方向RNN(Bidirectional RNN)
◦ 過去の情報だけでなく、未来の情報を加味する事で、精度を向上させるためのモデル。例)文章の推敲や機械翻訳等
◦ 文章というのは過去の情報も未来の情報も1度に入ってくる。過去の単語の羅列に加えて、その先に書いてある単語の羅列につい
ても自由にアクセスができる。
◦ Bidirectional RNN は、中間層の出力を、未来への順伝播と過去への逆伝播の両方向に伝播するネットワークである。
◦ BRNN では、学習時に、過去と未来の情報の入力を必要とすることから、運用時も過去から未来までのすべての情報を入力しては
じめて予測できるようになる。
◦ BRNN の応用範囲が限定される。例えば、DNA 塩基を k-mer ごとに区切れば、塩基配列解析に BRNN が使えるようになる。
あるいは、1 文全体を入力して、文中にある誤字・脱字の検出などに応用されている。
Section5:Seq2Seq
• Seq2seqとはEncoder-Decoderモデルの1種を指します(時系列データを入力に取って時系列のデータを出力するモデル)。
• Seq2seqの具体的な用途とは機械対話や機械翻訳等に使用されています。
• Encoder RNN:文の意味を集約する。文から文脈の意味ベクトルの抽出。
• Taking:文章を単語等のトークン事に分割し、トークン毎のIDに分割する(ONE HOT VECTOR)。
• Embedding:IDからそのトークンを表す分散表現ベクトルに変換。数字の並びが似かよっている事は似かよった意味を持つ単語という事にな
る ⇒ 単語の意味を抽出したベクトル。
• Encoder RNN:ベクトルを順番にRNNに入力していく。
• Encoder RNN処理手順
• 最後のベクトルを入れた時のhidden stateをfinal stateとして取っておく。
• このfinal stateがthought vectorと呼ばれ、入力した文の意味を表すベクトルになる。
• MLM - Masked Language Model(BERT)
• Decoder RNN:システムがアウトプットデータを単語等のトークン毎に生成する構造。
• Decoder RNN 処理手順
• Decoder RNN:Encoder RNNのfinal state(thought vector)から、各tokenの生成確率を出力してい
きます。final stateをDecoder RNNのinitial stateとして設定し、Embeddingを入力。
• Sampling:生成確率に基づいてtokenをランダムに選びます。
• Embedding:2で選ばれたtokenをEmbeddingしてDecoder RNNへの次の入力とします。
• Detokenize:1~3を繰り返し、2で得られたtokenを文字列に直します。
確認テスト
◦ 1.下記の選択肢から、seq2seqについて説明しているものを選べ。
(1)時刻に関して順方向と逆方向のRNNを構成し、それら2つの中間層表現を特徴量として利用するものである。
(2)RNNを用いたEncoder-Decoderモデルの一種であり、機械翻訳などのモデルに使われる。
(3)構文木などの木構造に対して、隣接単語から表現ベクトル(フレーズ)を作るという演算を再帰的に行い(重みは共通)、
文全体の表現ベクトルを得るニューラルネットワークである。
(4)RNNの一種であり、単純なRNNにおいて問題となる勾配消失問題をCECとゲートの概念を導入することで解決したも
のである。
◦ 2.Seq2seqとHRED、HREDとVHREDの違いを簡潔に述べよ。
◦ 3.VAEに関する下記の説明文中の空欄に当てはまる言葉を答えよ。自己符号化器の潜在変数に____を導入したもの。
解答:確率分布
解答:
Seq2seqは1問1答しかできない。
HREDは文章の過去の文脈を考慮することができる。
HREDは確かに文脈を意識した文を作る事ができるのだが、ありがちな答えしか出さなくなる。
VHREDは文脈を意識しながら文を生成するモデルにバリエーションを持たせられるように工夫をする仕組みである。
解答:(2)
Section6:Word2vec
◦ 単語のOne-Hotベクトルから1つ1うの単語(Embedding表現)意味同志が近くなるようなベクトルを見つけ
る。
◦ 課題:RNNでは単語のような可変長の文字列をNNに与える事はできない ⇒ 固定長形式で単語を表す必要がある。
◦ メリット:大規模データの分散表現の学習が、現実的な計算速度とメモリ量で実現可能となった。One-HotベクトルからE
mbedding表現に変換する時に変換表を用いるが、この変換表を機械学習によって学習させる事で、単語の意味を保ち
ながら、より少ない次元のベクトルで単語を表現できる。
Section7:Attention Mec
hanism
◦ 課題:seq2seqの問題は長い文章への対応が難しい事にある(seq2seqの構造によると、長い文章であろうと短
い文章であろうと、中間層(隠れ層)の大きさは決まっている。)seq2seqでは2単語でも、100単語でも、固定次元
ベクトルの中に入力しなければならない。
◦ 解決策:Attention Mechanism。1文の中で特に重要な単語というのを自力で見つけられるようにする機
構。途中の中間層の情報量が一定でも重要な情報だけ拾い集める。
◦ 近年特に性能が上がっている自然言語処理のモデルは全部Attention Mechanismである程、強力である。
確認テスト
1.RNNとword2vec、seq2seqとAttentionの違いを簡潔に述べよ。
解答:
RNNは時系列データを処理するのに適したネットワー
クです。
word2vecは単語の分散表現ベクトルを得る手法
です。
seq2seqは1つの時系列データから別の時系列
データを得るネットワークです。
Attention Mechanism は時系列データ
の中身に対して関連性に重みを付ける手法になります。
深層学習DAY4
2021/7/17
Section1:強化学習
◦ 教師あり、教師無し:特徴量を見つけ出し、未知のデータを予想する事が目標。
◦ 強化学習:優れた方策を見つける事が目標。
◦ 長期的に報酬を最大化できるように環境の中で行動を選択できるエージェントを作る事を目標とする機械学習の一分野 ⇒ 行動の結果として与えられる利益(報酬)をもとに行
動を決定する原理を改善していく仕組みです。
◦ 探索と利用のトレードオフ:不完全な知識をもとに行動しながらデータを収集。最適な行動を見つけていく。
◦ 強化学習で学習するターゲット:方策関数、行動価値関数
◦ 強化学習の歴史
◦ 計算速度の進展により大規模な状態を持つ場合が可能となりつつある。
◦ 関数近似法(価値関数や方策関数を関数近似する手法の事)とQ学習(行動価値関数を、行動する毎に更新する事により学習を進める方法)を組み合わせる手法の登
場。
◦ 価値関数(価値関数、行動価値関数:状態と価値を組み合わせた価値に注目)
◦ 方策関数:エージェントが取る行動を決定するための関数。
◦ 方策勾配法について
◦ 方策反復法:方策をモデル化して最適化する手法 ⇒ 方策勾配法
◦ 定義方法:平均報酬、割引報酬和に対応して、行動価値関数の定義を行い、方策勾配定理が成立する。
Section2:AlphaGo
• Alpha Go LeeのPolicyNet(方策関数)、ValueNet(価値関数)は共に畳み込みニューラル
ネットワーク。
• Policy Net(SoftMax Layer)出力は19x19マスの着手予想確率が出力される。
• Value Net(TanH Layer)出力は現局面の勝率を-1~1で表したものが出力される。
• Alpha Goの学習
• 教師あり学習によるRollOutPolicy(NNではなく線形の方策関数。探索中に高速に着手確率を出すために使用される。
PolicyNetの1000倍速い。)とPolicyNetの学習
• 強化学習によるPolicyNetの学習
• 強化学習によるValueNetの学習
• PolicyNetの強化学習
• ValueNetの学習
• PolicyNetとRollOutPolicyの教師あり学習。
• モンテカルロ木探索(強化学習の学習方法)(価値関数を学習させる時に用いる方法。価値関数をどういうふうに更新す
るか。)
Section3:軽量化・高速化技術
◦ 分散深層学習:データ並列、モデル並列
◦ データ並列化:データを分割し、各ワーカー毎に計算させる。
◦ 処理のスピードは、お互いのワーカーの計算を待たない非同期型の方が早い。
◦ 非同期型は最新のモデルのパラメータを利用できないので、学習が不安定になりやすい。-> Stale Gradient Problem
◦ 現在は同期型の方が精度が良いことが多いので、主流となっている。
◦ 親モデルを各ワーカーに分割し、それぞれのモデルを学習させる。全てのデータで学習が終わった後で、一つのモデルに復元。
◦ モデルが大きい時はモデル並列化を、データが大きい時はデータ並列化をすると良い。
◦ ある程度モデルが大きければ、分割した時の効果が目に見えるように出る。
◦ 並列コンピューティングを用いることで大規模なネットワークを高速に学習させる仕組みを提案。
◦ 主にモデル並列とデータ並列(非同期型)の提案をしている。
◦ GPUによる高速化
◦ 量子化(Quantization):重みの精度を下げることにより計算の高速化と省メモリ化を行う技術。
◦ 蒸留(Distillaion):複雑で精度の良い教師モデルから軽量な生徒モデルを効率よく学習を行う技術。
◦ プルーニング:寄与の少ないニューロンをモデルから削減し高速化と省メモリ化を行う技術。
確認テスト
解答:Dilated causal convolution 解答:パラメータ数に対する受容野が広い
解答:
(い)
HxWxCxKxK
(KxK)で出力マップの1ピクセル分は計算できる。
それが(HxWxC)必要である。 従って、計算量は、
HxWxCxKxK となる。
(う)
HxWxCxM
(C)で出力マップの1ピクセル分は計算できる。
それが(HxWxM)必要である。 従って、計算量は、
HxWxCxM となる。
Section4:応用モデル
◦ 「MobileNet(画像認識のモデルで軽量化したモデル)」
◦ 2017年に精度は最高レベルに達しており、そこから先は軽くて性能が良いモデルを研究する事が多くなった。MobileNetはその先駆け。あまり計算量を増やさずに比較的高性能である事が目標。
◦ 一般的な畳み込みレイヤ:ストライド1でパディングを適用した場合の畳み込み計算の計算量。
◦ MobileNetはここから、これをどうにか減らして行こうという試み。
◦ Depthwise Convolution と Pointwise Convolution の組み合わせで軽量化を実現。
◦ Depthwise Convolution:入力マップのチャネルごとに畳み込みを実施 ⇒ 計算量を大幅に削減可能。
◦ Pointwise Convolution:1x1 Conv とも呼ばれる(正確には1x1xC) ⇒ 計算量を大幅に削減可能。
◦ 「DenseNet(画像認識のネットワーク)」
◦ DenseBlock
◦ 出力層に前の層の入力を足し合わせる。
◦ DenseBlock内の各ブロック毎にk個ずつ特徴マップのチャネル数が増加していく時、kを成長率(Growth Rate)と呼ぶ。
◦ ここでkはハイパーパラメータである。
◦ kが大きくなる程ネットワークが大きくなるため、小さな整数に設定するのが良い。
◦ Transition Layer
◦ CNNでは中間層でチャネルサイズを変更する。
◦ 特徴マップのサイズを変更し、ダウンサンプリングを行うため、Transition Layerと呼ばれる層でDence blockをつなぐ。
◦ 以上のような構造になっている事で、各ブロック内で特徴マップのサイズは一致。
◦ DenseNetとResNetの違い
◦ DenseBlockでは前方の各層からの出力全てが後方の層への入力として用いられる。
◦ RessidualBlockでは前1層の入力のみ後方の層へ入力。
Section5:Transformer
◦ 「Self-Attention(自己注意機構)」
◦ 基本的にTransformerを構成している技術は全然新しい発明等では無く、過去のものを上手くくっつけて再構築したモデルになっているので、引用
だらけの側面がある。計算量のわりに表現力の豊かなモデルとして知られています。
◦ ニューラル機械翻訳の問題点:長さに弱い。
◦ 上の問題意識から生まれた「Attention(注意機構)(2015)」
◦ 情報量が多くなってきた時に何に注意を払って何に注意を払わないで良いかというのを学習的に決定していく、という機構が発明された。
◦ Attentionは何をしているのか
◦ Attentionは辞書オブジェクト:query(検索クエリ)に一致するKeyを索引し、対応するvalueを取り出す操作であると見做す事ができる。これは
「辞書オブジェクト」の機能と同じである。(Key Value Attentionと呼ばれる。)
◦ 「Transformer(2017)」
◦ Attention is all you need
◦ 従来、Encoder-Decoder Model の基本だったRNNモデルを全く使用しない。
Section5:Transformer
class DataLoader(object):
def __init__(self, src_insts, tgt_insts, batch_size, shuffle=True):
"""
:param src_insts: list, 入力言語の文章(単語IDのリスト)のリスト
:param tgt_insts: list, 出力言語の文章(単語IDのリスト)のリスト
:param batch_size: int, バッチサイズ
:param shuffle: bool, サンプルの順番をシャッフルするか否か
"""
self.data = list(zip(src_insts, tgt_insts))
self.batch_size = batch_size
self.shuffle = shuffle
self.start_index = 0
self.reset()
def reset(self):
if self.shuffle:
self.data = shuffle(self.data, random_state=random_state)
self.start_index = 0
def __iter__(self):
return self
def __next__(self):
def preprocess_seqs(seqs):
# パディング
max_length = max([len(s) for s in seqs])
data = [s + [PAD] * (max_length - len(s)) for s in seqs]
# 単語の位置を表現するベクトルを作成
positions = [[pos+1 if w != PAD else 0 for pos, w in enumerate(seq)] for seq in data]
# テンソルに変換
data_tensor = torch.tensor(data, dtype=torch.long, device=device)
position_tensor = torch.tensor(positions, dtype=torch.long, device=device)
return data_tensor, position_tensor
# ポインタが最後まで到達したら初期化する
if self.start_index >= len(self.data):
self.reset()
raise StopIteration()
# バッチを取得して前処理
src_seqs, tgt_seqs = zip(*self.data[self.start_index:self.start_index+self.batch_size])
src_data, src_pos = preprocess_seqs(src_seqs)
tgt_data, tgt_pos = preprocess_seqs(tgt_seqs)
# ポインタを更新する
self.start_index += self.batch_size
return (src_data, src_pos), (tgt_data, tgt_pos)
def position_encoding_init(n_position, d_pos_vec):
"""
Positional Encodingのための行列の初期化を行う
:param n_position: int, 系列長
:param d_pos_vec: int, 隠れ層の次元数
:return torch.tensor, size=(n_position, d_pos_vec)
"""
# PADがある単語の位置はpos=0にしておき、position_encも0にする
position_enc = np.array([
[pos / np.power(10000, 2 * (j // 2) / d_pos_vec) for j in range(d_pos_vec)]
if pos != 0 else np.zeros(d_pos_vec) for pos in range(n_position)])
position_enc[1:, 0::2] = np.sin(position_enc[1:, 0::2]) # dim 2i
position_enc[1:, 1::2] = np.cos(position_enc[1:, 1::2]) # dim 2i+1
return torch.tensor(position_enc, dtype=torch.float)
pe = position_encoding_init(50, 256).numpy()
plt.figure(figsize=(16,8))
sns.heatmap(pe, cmap='Blues')
plt.show()
Section6:物体検知・セグメンテーション
• 物体検知:Bounding Box
• セマンティックセグメンテーション(意味領域分割):(各ピクセルに対し単一の) クラスラベル
• インスタンスセグメンテーション(個体領域分割):(各ピクセルに対し単一の) クラスラベル
• 「代表的なデータセット」クラス数が大きい事はうれしいのか?
• 目的に応じた「BOX/画像」の選択を。
• 小:アイコン的な映り。日常感とはかけ離れやすい。
• 大:部分的な重なり等も見られる。日常生活のコンテクストに近い。
• 目的に合ったデータセットを選ぶ事が大切(クラス数あるいはBOX/画像を1つの基準として)
• VOC12(Visual Object Classes)
• ILSVRC12: ImageNetのサブセット
• MS COCO18 (Microsoft Common Object in Context)
• OICOD18 (Open Images Challenges Object Detection)

More Related Content

PDF
About RNN
Young Oh Jeong
 
PDF
About RNN
Young Oh Jeong
 
PDF
TensorFlow Tutorial
NamHyuk Ahn
 
PPTX
Explanation on Tensorflow example -Deep mnist for expert
홍배 김
 
PDF
Tele4653 l1
Vin Voro
 
PDF
DIGITAL IMAGE PROCESSING - Day 4 Image Transform
vijayanand Kandaswamy
 
PDF
Pytorch for tf_developers
Abdul Muneer
 
PDF
Tele4653 l5
Vin Voro
 
About RNN
Young Oh Jeong
 
About RNN
Young Oh Jeong
 
TensorFlow Tutorial
NamHyuk Ahn
 
Explanation on Tensorflow example -Deep mnist for expert
홍배 김
 
Tele4653 l1
Vin Voro
 
DIGITAL IMAGE PROCESSING - Day 4 Image Transform
vijayanand Kandaswamy
 
Pytorch for tf_developers
Abdul Muneer
 
Tele4653 l5
Vin Voro
 

What's hot (15)

PPTX
Nabaa
Nabaa Badee
 
PDF
Time Series Analysis:Basic Stochastic Signal Recovery
Daniel Cuneo
 
PDF
Comparison and analysis of combining techniques for spatial multiplexing spac...
IAEME Publication
 
PDF
Frequency Domain Filtering of Digital Images
Upendra Pratap Singh
 
PDF
Lecture 9
Wael Sharba
 
PPTX
Introduction to Tensorflow
Tzar Umang
 
PDF
fourier representation of signal and systems
Sugeng Widodo
 
PDF
presentation_final
Sushanta Roy
 
PDF
Introducton to Convolutional Nerural Network with TensorFlow
Etsuji Nakai
 
PPTX
Fourier transformation
zertux
 
PDF
Applied Machine Learning For Search Engine Relevance
charlesmartin14
 
PPT
Chapter 5 Image Processing: Fourier Transformation
Varun Ojha
 
PPTX
Tensor flow (1)
景逸 王
 
PPTX
fourier series and fourier transform
Vikas Rathod
 
KEY
NumPy/SciPy Statistics
Enthought, Inc.
 
Time Series Analysis:Basic Stochastic Signal Recovery
Daniel Cuneo
 
Comparison and analysis of combining techniques for spatial multiplexing spac...
IAEME Publication
 
Frequency Domain Filtering of Digital Images
Upendra Pratap Singh
 
Lecture 9
Wael Sharba
 
Introduction to Tensorflow
Tzar Umang
 
fourier representation of signal and systems
Sugeng Widodo
 
presentation_final
Sushanta Roy
 
Introducton to Convolutional Nerural Network with TensorFlow
Etsuji Nakai
 
Fourier transformation
zertux
 
Applied Machine Learning For Search Engine Relevance
charlesmartin14
 
Chapter 5 Image Processing: Fourier Transformation
Varun Ojha
 
Tensor flow (1)
景逸 王
 
fourier series and fourier transform
Vikas Rathod
 
NumPy/SciPy Statistics
Enthought, Inc.
 
Ad

Similar to 深層学習後半 (20)

PPTX
深層学習前半
ssusere8ae711
 
DOCX
機会学習レポート
taishimotoda
 
PPTX
深層学習前半
ssusere8ae711
 
PDF
ラビットチャレンジ 深層学習Day1 day2レポート
KazuyukiMasada
 
PPTX
3
matsuto1
 
DOCX
レポート深層学習前編
ssuser9d95b3
 
PDF
A Transformer-based Framework for Multivariate Time Series Representation Lea...
harmonylab
 
PPTX
【DL輪読会】Efficiently Modeling Long Sequences with Structured State Spaces
Deep Learning JP
 
PPTX
Rabbit challenge 5_dnn3
TOMMYLINK1
 
PDF
Talk
Taichi Kiwaki
 
PPTX
Rabbit challenge 2 Machine Learning
TOMMYLINK1
 
PDF
【AI実装4】TensorFlowのプログラムを読む2 非線形回帰
Ruo Ando
 
PDF
2016 dg2
Shin Asakawa
 
PDF
【博士論文発表会】パラメータ制約付き特異モデルの統計的学習理論
Naoki Hayashi
 
DOCX
LSTM Framework For Univariate Time series
bilyamine1
 
PDF
論文紹介:Learning With Neighbor Consistency for Noisy Labels
Toru Tamaki
 
PDF
ML基本からResNetまで
Institute of Agricultural Machinery, NARO
 
PDF
(文献紹介)デブラー手法の紹介
Morpho, Inc.
 
PPTX
Rabbit challenge 3 DNN Day1
TOMMYLINK1
 
PPTX
Recurrent neural networks (rnn) and long short term memory networks (lstm)
Minhazul Arefin
 
深層学習前半
ssusere8ae711
 
機会学習レポート
taishimotoda
 
深層学習前半
ssusere8ae711
 
ラビットチャレンジ 深層学習Day1 day2レポート
KazuyukiMasada
 
レポート深層学習前編
ssuser9d95b3
 
A Transformer-based Framework for Multivariate Time Series Representation Lea...
harmonylab
 
【DL輪読会】Efficiently Modeling Long Sequences with Structured State Spaces
Deep Learning JP
 
Rabbit challenge 5_dnn3
TOMMYLINK1
 
Rabbit challenge 2 Machine Learning
TOMMYLINK1
 
【AI実装4】TensorFlowのプログラムを読む2 非線形回帰
Ruo Ando
 
2016 dg2
Shin Asakawa
 
【博士論文発表会】パラメータ制約付き特異モデルの統計的学習理論
Naoki Hayashi
 
LSTM Framework For Univariate Time series
bilyamine1
 
論文紹介:Learning With Neighbor Consistency for Noisy Labels
Toru Tamaki
 
ML基本からResNetまで
Institute of Agricultural Machinery, NARO
 
(文献紹介)デブラー手法の紹介
Morpho, Inc.
 
Rabbit challenge 3 DNN Day1
TOMMYLINK1
 
Recurrent neural networks (rnn) and long short term memory networks (lstm)
Minhazul Arefin
 
Ad

Recently uploaded (20)

PDF
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PDF
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
PDF
REPORT: Heating appliances market in Poland 2024
SPIUG
 
PDF
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
PDF
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
PDF
How-Cloud-Computing-Impacts-Businesses-in-2025-and-Beyond.pdf
Artjoker Software Development Company
 
PDF
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
PPTX
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
PPTX
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
PDF
Software Development Methodologies in 2025
KodekX
 
PDF
A Day in the Life of Location Data - Turning Where into How.pdf
Precisely
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
PDF
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
PDF
Brief History of Internet - Early Days of Internet
sutharharshit158
 
PDF
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 
PPTX
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
PPTX
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
REPORT: Heating appliances market in Poland 2024
SPIUG
 
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
How-Cloud-Computing-Impacts-Businesses-in-2025-and-Beyond.pdf
Artjoker Software Development Company
 
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
Software Development Methodologies in 2025
KodekX
 
A Day in the Life of Location Data - Turning Where into How.pdf
Precisely
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
Brief History of Internet - Early Days of Internet
sutharharshit158
 
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 

深層学習後半

  • 3. Section1:再帰型ニューラルネットワークの 概念 ◦ 時系列データに対応可能なニュートラルネットワーク。 ◦ 時系列データとは、音声データ、株価データ、テキストデータなどがある。 ◦ RNN(Reccurent Neural Netowrk) ◦ RNNの数学的記述 ◦ RNNの特徴(再帰的構造) ◦ BPTTとは、RNNにおいてのパラメータ調整方法の一種である。 ◦ t時間目とt-1時間目には関係がある事が見てとれる。 ◦ パラメータの更新式 ◦ RNNが過去の時間を再帰的にたくわえている事を示している。
  • 4. Section1:再帰型ニューラルネットワークの概念 import numpy as np from common import functions import matplotlib.pyplot as plt def d_tanh(x): sinh = (np.exp(x) - np.exp(-x)) / 2 cosh = (np.exp(x) + np.exp(-x)) / 2 return (cosh**2 - sinh**2) / cosh**2 # データを用意 # 2進数の桁数 binary_dim = 8 # 最大値 + 1 largest_number = pow(2, binary_dim) # largest_numberまで2進数を用意 binary = np.unpackbits(np.array([range(largest_number)],dtype=np.uint8).T,axis=1) input_layer_size = 2 hidden_layer_size = 16 #16 output_layer_size = 1 weight_init_std = 1 learning_rate = 0.1 #0.1 iters_num = 10000 plot_interval = 100 # ウェイト初期化 (バイアスは簡単のため省略) W_in = weight_init_std * np.random.randn(input_layer_size, hidden_layer_size) W_out = weight_init_std * np.random.randn(hidden_layer_size, output_layer_size) W = weight_init_std * np.random.randn(hidden_layer_size, hidden_layer_size) # Xavier W_in = np.random.randn(input_layer_size, hidden_layer_size) / (np.sqrt(input_layer_size)) W_out = np.random.randn(hidden_layer_size, output_layer_size) / (np.sqrt(hidden_layer_size)) W = np.random.randn(hidden_layer_size, hidden_layer_size) / (np.sqrt(hidden_layer_size)) # He # W_in = np.random.randn(input_layer_size, hidden_layer_size) / np.sqrt(input_layer_size) * np.sqrt(2) # W_out = np.random.randn(hidden_layer_size, output_layer_size) / np.sqrt(hidden_layer_size) * np.sqrt(2) # W = np.random.randn(hidden_layer_size, hidden_layer_size) / np.sqrt(hidden_layer_size) * np.sqrt(2) # 勾配 W_in_grad = np.zeros_like(W_in) W_out_grad = np.zeros_like(W_out) W_grad = np.zeros_like(W) u = np.zeros((hidden_layer_size, binary_dim + 1)) z = np.zeros((hidden_layer_size, binary_dim + 1)) y = np.zeros((output_layer_size, binary_dim)) delta_out = np.zeros((output_layer_size, binary_dim)) delta = np.zeros((hidden_layer_size, binary_dim + 1)) all_losses = [] for i in range(iters_num): # A, B初期化 (a + b = d) a_int = np.random.randint(largest_number/2) a_bin = binary[a_int] # binary encoding b_int = np.random.randint(largest_number/2) b_bin = binary[b_int] # binary encoding # 正解データ d_int = a_int + b_int d_bin = binary[d_int] # 出力バイナリ out_bin = np.zeros_like(d_bin) # 時系列全体の誤差 all_loss = 0 # 時系列ループ for t in range(binary_dim): # 入力値 X = np.array([a_bin[ - t - 1], b_bin[ - t - 1]]).reshape(1, -1) # 時刻tにおける正解データ dd = np.array([d_bin[binary_dim - t - 1]]) u[:,t+1] = np.dot(X, W_in) + np.dot(z[:,t].reshape(1, -1), W) z[:,t+1] = functions.sigmoid(u[:,t+1]) y[:,t] = functions.sigmoid(np.dot(z[:,t+1].reshape(1, -1), W_out)) #誤差 loss = functions.mean_squared_error(dd, y[:,t]) delta_out[:,t] = functions.d_mean_squared_error(dd, y[:,t]) * functions.d_sigmoid(y[:,t]) all_loss += loss out_bin[binary_dim - t - 1] = np.round(y[:,t]) for t in range(binary_dim)[::-1]: X = np.array([a_bin[-t-1],b_bin[-t-1]]).reshape(1, -1) delta[:,t] = (np.dot(delta[:,t+1].T, W.T) + np.dot(delta_out[:,t].T, W_out.T)) * functions.d_sigmoid(u[:,t+1]) # 勾配更新 W_out_grad += np.dot(z[:,t+1].reshape(-1,1), delta_out[:,t].reshape(-1,1)) W_grad += np.dot(z[:,t].reshape(-1,1), delta[:,t].reshape(1,-1)) W_in_grad += np.dot(X.T, delta[:,t].reshape(1,-1)) # 勾配適用 W_in -= learning_rate * W_in_grad W_out -= learning_rate * W_out_grad W -= learning_rate * W_grad W_in_grad *= 0 W_out_grad *= 0 W_grad *= 0 if(i % plot_interval == 0): all_losses.append(all_loss) print("iters:" + str(i)) print("Loss:" + str(all_loss)) print("Pred:" + str(out_bin)) print("True:" + str(d_bin)) out_int = 0 for index,x in enumerate(reversed(out_bin)): out_int += x * pow(2, index) print(str(a_int) + " + " + str(b_int) + " = " + str(out_int)) print("------------") lists = range(0, iters_num, plot_interval) plt.plot(lists, all_losses, label="loss") plt.show() 中間層の活性化関数 をtanhに変更し モデルに合った活性化関数を使うことが大切である。
  • 5. 確認テスト ◦ 1. RNNのネットワークには大きくわけて3つの重みがある。1つは入力から現在の中間層を定義する際にかけられる重み、1つは中間 層から出力を定義する際にかけられる重みである。残り1つの重みについて説明せよ。 ◦ 2.連鎖率の原理を使い、dz/dx を求めよ。 ◦ 3.下図を数式で表せ。※バイアスは任意の文字で定義せよ。 ◦ ※また中間層の出力にシグモイド関数g(x)を作用させよ。 解答: 中間層から中間層へ至るところの重み。前の中間層からの重み。 𝜕𝑧 𝜕𝑡 = 2𝑡 𝜕𝑡 𝜕𝑥 = 1 𝜕𝑧 𝜕𝑡 𝜕𝑡 𝜕𝑥 = 2𝑡 𝜕𝑧 𝜕𝑥 = 2(𝑥 + 𝑦)
  • 6. Section2:LSTM ◦ RNNの課題の解決:これまでに触れた勾配消失の解決方法(tanh等の勾配消失問題に強い活性化関数を用いる、あるいは正 則化を用いる等)とは別に、構造自体を変えて解決したものがLSTM。 ◦ 勾配消失問題:誤差逆伝播法が下位層に進んで行くに連れて、勾配がどんどん緩やかになっていく。そのため、勾配降下法による更新では、 下位層のパラメータはほとんど変わらず、訓練は最適解に収束しなくなる。(例)シグモイド関数 ◦ 勾配爆発:勾配が層を逆伝播するごとに指数関数的に大きくなっていく⇒勾配クリッピング ◦ LSTMの全体図 ◦ CEC(Constant Error Carousel)記憶機能だけを持つもの ◦ CECの課題:入力データについて、時間依存に関係なく一律である(ニューラルネットワークの学習特性が無いという事) ◦ 入力ゲートと出力ゲートを追加する事で、それぞれのゲートへの入力値の重みを、重み行列で可変とする(CECの課題を解決) ◦ LSTMの現状 ◦ CECには過去の情報が全て保管されている。 ◦ LSTMブロックの課題:過去の情報が要らなくなった場合、そのタイミングで情報を忘却する機能が必要⇒忘却ゲート ◦ 覗き穴結合:CEC自身の値に重み行列を介して伝播可能にした構造(実際にはあまり大きな効果の改善は見られない。)
  • 7. Section2:LSTM from keras.utils import np_utils # keras.utilsからnp_utilsをイン ポート from keras.datasets import mnist # MNISTデータセットをイン ポート # MNISTデータセットの読み込み (x_trains, y_trains), (x_tests, y_tests) = mnist.load_data() # 訓練データ x_trains = x_trains.astype('float32') # float32型に変換 x_trains /= 255 # 0から1.0の範囲に変換 # 正解ラベルをワンホット表現に変換 correct = 10 # 正解ラベルの数 y_trains = np_utils.to_categorical(y_trains, correct) # テストデータ x_tests = x_tests.astype('float32') # float32型に変換 x_tests /= 255 # 0から1.0の範囲に変換 # 正解ラベルをワンホット表現に変換 y_tests = np_utils.to_categorical(y_tests, correct) print(x_trains.shape) # 訓練データの形状を出力 print(x_tests.shape) # テストデータの形状を出力 # RNNの構築 from keras.models import Sequential from keras.layers import InputLayer, Dense from keras.layers.recurrent import LSTM from keras import optimizers,regularizers # Sequentialオブジェクトを生成 model = Sequential() ## 入力層 # 入力データの形状は(28, 28) model.add( InputLayer(input_shape=(28,28)) ) ## 中間層 # LSTMブロック(ユニット数=128) weight_decay = 1e-4 # ハイパーパラメーター model.add(LSTM(units=128, dropout=0.25, return_sequences=True)) model.add(LSTM(units=128, dropout=0.25, return_sequences=True)) model.add(LSTM(units=128, dropout=0.25, return_sequences=False, kernel_regularizer=regularizers.l2(weight_decay)) # 正則化 ) ## 出力層 model.add( Dense(units=10, # 出力層のニューロン数は10 activation='softmax') # 活性化はシグモイド関数 ) # Squentialオブジェクをコンパイル model.compile( loss='categorical_crossentropy', # 誤差関数はクロスエントロピー optimizer=optimizers.Adam(), # Adamオプティマイザー metrics=['accuracy'] # 学習評価として正解率を指定 ) model.summary() # RNNのサマリ(概要)を出力 # 学習を開始 history = model.fit(x_trains, y_trains, # 訓練データ、正 解ラベル batch_size=100, # ミニバッチのサイズ epochs=10, # 学習回数 verbose=1, # 学習の進捗状況を出力す る validation_data=( # テストデータの指定 x_tests, y_tests) ) # 損失と正解率をグラフにする %matplotlib inline import matplotlib.pyplot as plt # プロット図のサイズを設定 plt.figure(figsize=(15, 6)) # プロット図を縮小して図の間のスペースを空ける plt.subplots_adjust(wspace=0.2) # 1×2のグリッドの左(1,2,1)の領域にプロット plt.subplot(1, 2, 1) # 訓練データの損失(誤り率)をプロット plt.plot(history.history['loss'], label='training', color='black') # テストデータの損失(誤り率)をプロット plt.plot(history.history['val_loss'], label='test', color='red') plt.ylim(0, 1) # y軸の範囲 plt.legend() # 凡例を表示 plt.grid() # グリッド表示 plt.xlabel('epoch') # x軸ラベル plt.ylabel('loss') # y軸ラベル # 1×2のグリッドの右(1,2,21)の領域にプロット plt.subplot(1, 2, 2) # 訓練データの正解率をプロット plt.plot(history.history['acc'], label='training', color='black') # テストデータの正解率をプロット plt.plot(history.history['val_acc'], label='test', color='red') plt.ylim(0.5, 1) # y軸の範囲 plt.legend() # 凡例を表示 plt.grid() # グリッド表示 plt.xlabel('epoch') # x軸ラベル plt.ylabel('acc') # y軸ラベル plt.show() 時間がかかった。 結果は良かった。
  • 8. 確認テスト ◦ 1.シグモイド関数を微分した時、入力値が0の時に最大値をとる。その値として正しいものを選択肢から選べ。 1. 0.15 2. 0.25 3. 0.35 4. 0.45 ◦ 2.以下の文章をLSTMに入力し空欄に当てはまる単語を予測したいとする。 文中の「とても」という言葉は空欄の予測においてなくなっても影響を及ぼさないと考えられる。 このような場合、どのゲートが作用すると考えられるか。 ◦ 「映画おもしろかったね。ところで、とてもお腹が空いたから何か_____。」 解答:2 解答:忘却ゲート
  • 9. Section3:GRU ◦ GRU(Gated Recurrent Unit) ◦ リセットゲートと更新ゲートがある。 ◦ LSTMの改良版である ◦ LSTMでは、パラメータ数が多く、計算負荷が高くなる問題があった。 ◦ GRUはパラメータを大幅に削減し(計算負荷が低い)、精度は同等またはそれ以上が望める様になった構造を持つ。 ◦ Leaky integrationだけを使ってメモリを公開する。
  • 10. Section3:GRU import tensorflow as tf import numpy as np import re import glob import collections import random import pickle import time import datetime import os # logging levelを変更 tf.logging.set_verbosity(tf.logging.ERROR) class Corpus: def __init__(self): self.unknown_word_symbol = "<???>" # 出現回数の少ない単語は未知語として定義しておく self.unknown_word_threshold = 3 # 未知語と定義する単語の出現回数の閾値 self.corpus_file = "./corpus/**/*.txt" self.corpus_encoding = "utf-8" self.dictionary_filename = "./data_for_predict/word_dict.dic" self.chunk_size = 5 self.load_dict() words = [] for filename in glob.glob(self.corpus_file, recursive=True): with open(filename, "r", encoding=self.corpus_encoding) as f: # word breaking text = f.read() # 全ての文字を小文字に統一し、改行をスペースに変換 text = text.lower().replace("n", " ") # 特定の文字以外の文字を空文字に置換する text = re.sub(r"[^a-z '-]", "", text) # 複数のスペースはスペース一文字に変換 text = re.sub(r"[ ]+", " ", text) # 前処理: '-' で始まる単語は無視する words = [ word for word in text.split() if not word.startswith("-")] self.data_n = len(words) - self.chunk_size self.data = self.seq_to_matrix(words) def prepare_data(self): """ 訓練データとテストデータを準備する。 data_n = ( text データの総単語数 ) - chunk_size input: (data_n, chunk_size, vocabulary_size) output: (data_n, vocabulary_size) """ # 入力と出力の次元テンソルを準備 all_input = np.zeros([self.chunk_size, self.vocabulary_size, self.data_n]) all_output = np.zeros([self.vocabulary_size, self.data_n]) # 準備したテンソルに、コーパスの one-hot 表現(self.data) のデータを埋めていく # i 番目から ( i + chunk_size - 1 ) 番目までの単語が1組の入力となる # このときの出力は ( i + chunk_size ) 番目の単語 for i in range(self.data_n): all_output[:, i] = self.data[:, i + self.chunk_size] # (i + chunk_size) 番目の単語の one-hot ベクトル for j in range(self.chunk_size): all_input[j, :, i] = self.data[:, i + self.chunk_size - j - 1] # 後に使うデータ形式に合わせるために転置を取る all_input = all_input.transpose([2, 0, 1]) all_output = all_output.transpose() # 訓練データ:テストデータを 4 : 1 に分割する training_num = ( self.data_n * 4 ) // 5 return all_input[:training_num], all_output[:training_num], all_input[training_num:], all_output[training_num:] def build_dict(self): # コーパス全体を見て、単語の出現回数をカウントする counter = collections.Counter() for filename in glob.glob(self.corpus_file, recursive=True): with open(filename, "r", encoding=self.corpus_encoding) as f: # word breaking text = f.read() # 全ての文字を小文字に統一し、改行をスペースに変換 text = text.lower().replace("n", " ") # 特定の文字以外の文字を空文字に置換する text = re.sub(r"[^a-z '-]", "", text) # 複数のスペースはスペース一文字に変換 text = re.sub(r"[ ]+", " ", text) # 前処理: '-' で始まる単語は無視する words = [word for word in text.split() if not word.startswith("-")] counter.update(words) # 出現頻度の低い単語を一つの記号にまとめる word_id = 0 dictionary = {} for word, count in counter.items(): if count <= self.unknown_word_threshold: continue dictionary[word] = word_id word_id += 1 dictionary[self.unknown_word_symbol] = word_id print("総単語数:", len(dictionary)) # 辞書を pickle を使って保存しておく with open(self.dictionary_filename, "wb") as f: pickle.dump(dictionary, f) print("Dictionary is saved to", self.dictionary_filename) self.dictionary = dictionary print(self.dictionary) def load_dict(self): with open(self.dictionary_filename, "rb") as f: self.dictionary = pickle.load(f) self.vocabulary_size = len(self.dictionary) self.input_layer_size = len(self.dictionary) self.output_layer_size = len(self.dictionary) print("総単語数: ", self.input_layer_size) def get_word_id(self, word): # print(word) # print(self.dictionary) # print(self.unknown_word_symbol) # print(self.dictionary[self.unknown_word_symbol]) # print(self.dictionary.get(word, self.dictionary[self.unknown_word_symbol])) return self.dictionary.get(word, self.dictionary[self.unknown_word_symbol]) # 入力された単語を one-hot ベクトルにする def to_one_hot(self, word): index = self.get_word_id(word) data = np.zeros(self.vocabulary_size) data[index] = 1 return data def seq_to_matrix(self, seq): print(seq) data = np.array([self.to_one_hot(word) for word in seq]) # (data_n, vocabulary_size) return data.transpose() # (vocabulary_size, data_n) class Language: """ input layer: self.vocabulary_size hidden layer: rnn_size = 30 output layer: self.vocabulary_size """ def __init__(self): self.corpus = Corpus() self.dictionary = self.corpus.dictionary self.vocabulary_size = len(self.dictionary) # 単語数 self.input_layer_size = self.vocabulary_size # 入力層の数 self.hidden_layer_size = 30 # 隠れ層の RNN ユニットの数 self.output_layer_size = self.vocabulary_size # 出力層の数 self.batch_size = 128 # バッチサイズ self.chunk_size = 5 # 展開するシーケンスの数。c_0, c_1, ..., c_(chunk_size - 1) を入力し、c_(chunk_size) 番目の単語の確率が出力される。 self.learning_rate = 0.005 # 学習率 self.epochs = 1000 # 学習するエポック数 self.forget_bias = 1.0 # LSTM における忘却ゲートのバイアス self.model_filename = "./data_for_predict/predict_model.ckpt" self.unknown_word_symbol = self.corpus.unknown_word_symbol def inference(self, input_data, initial_state): """ :param input_data: (batch_size, chunk_size, vocabulary_size) 次元のテンソル :param initial_state: (batch_size, hidden_layer_size) 次元の行列 :return: """ # 重みとバイアスの初期化 hidden_w = tf.Variable(tf.truncated_normal([self.input_layer_size, self.hidden_layer_size], stddev=0.01)) hidden_b = tf.Variable(tf.ones([self.hidden_layer_size])) output_w = tf.Variable(tf.truncated_normal([self.hidden_layer_size, self.output_layer_size], stddev=0.01)) output_b = tf.Variable(tf.ones([self.output_layer_size])) # BasicLSTMCell, BasicRNNCell は (batch_size, hidden_layer_size) が chunk_size 数 ぶんつながったリストを入力とする。 # 現時点での入力データは (batch_size, chunk_size, input_layer_size) という3 次元のテンソルなので # tf.transpose や tf.reshape などを駆使してテンソルのサイズを調整する。 input_data = tf.transpose(input_data, [1, 0, 2]) # 転置。(chunk_size, batch_size, vocabulary_size) input_data = tf.reshape(input_data, [-1, self.input_layer_size]) # 変形。 (chunk_size * batch_size, input_layer_size) input_data = tf.matmul(input_data, hidden_w) + hidden_b # 重みWとバイアスB を適用。 (chunk_size, batch_size, hidden_layer_size) input_data = tf.split(input_data, self.chunk_size, 0) # リストに分割。chunk_size * (batch_size, hidden_layer_size) # RNN のセルを定義する。RNN Cell の他に LSTM のセルや GRU のセルなどが 利用できる。 cell = tf.nn.rnn_cell.BasicRNNCell(self.hidden_layer_size) outputs, states = tf.nn.static_rnn(cell, input_data, initial_state=initial_state) # 最後に隠れ層から出力層につながる重みとバイアスを処理する # 最終的に softmax 関数で処理し、確率として解釈される。 # softmax 関数はこの関数の外で定義する。 output = tf.matmul(outputs[-1], output_w) + output_b return output def loss(self, logits, labels): cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels)) return cost def training(self, cost): # 今回は最適化手法として Adam を選択する。 # ここの AdamOptimizer の部分を変えることで、Adagrad, Adadelta などの他 の最適化手法を選択することができる optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(cost) return optimizer def train(self): # 変数などの用意 input_data = tf.placeholder("float", [None, self.chunk_size, self.input_layer_size]) actual_labels = tf.placeholder("float", [None, self.output_layer_size]) initial_state = tf.placeholder("float", [None, self.hidden_layer_size]) prediction = self.inference(input_data, initial_state) cost = self.loss(prediction, actual_labels) optimizer = self.training(cost) correct = tf.equal(tf.argmax(prediction, 1), tf.argmax(actual_labels, 1)) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) # TensorBoard で可視化するため、クロスエントロピーをサマリーに追加 tf.summary.scalar("Cross entropy: ", cost) summary = tf.summary.merge_all() # 訓練・テストデータの用意 # corpus = Corpus() trX, trY, teX, teY = self.corpus.prepare_data() training_num = trX.shape[0] # ログを保存するためのディレクトリ timestamp = time.time() dirname = datetime.datetime.fromtimestamp(timestamp).strftime("%Y%m%d%H%M%S") # ここから実際に学習を走らせる with tf.Session() as sess: sess.run(tf.global_variables_initializer()) summary_writer = tf.summary.FileWriter("./log/" + dirname, sess.graph) # エポックを回す for epoch in range(self.epochs): step = 0 epoch_loss = 0 epoch_acc = 0 # 訓練データをバッチサイズごとに分けて学習させる (= optimizer を走らせる) # エポックごとの損失関数の合計値や(訓練データに対する)精度も計算しておく while (step + 1) * self.batch_size < training_num: start_idx = step * self.batch_size end_idx = (step + 1) * self.batch_size batch_xs = trX[start_idx:end_idx, :, :] batch_ys = trY[start_idx:end_idx, :] _, c, a = sess.run([optimizer, cost, accuracy], feed_dict={input_data: batch_xs, actual_labels: batch_ys, initial_state: np.zeros([self.batch_size, self.hidden_layer_size]) } ) epoch_loss += c epoch_acc += a step += 1 # コンソールに損失関数の値や精度を出力しておく print("Epoch", epoch, "completed ouf of", self.epochs, "-- loss:", epoch_loss, " -- accuracy:", epoch_acc / step) # Epochが終わるごとにTensorBoard用に値を保存 summary_str = sess.run(summary, feed_dict={input_data: trX, actual_labels: trY, initial_state: np.zeros( [trX.shape[0], self.hidden_layer_size] ) } ) summary_writer.add_summary(summary_str, epoch) summary_writer.flush() # 学習したモデルも保存しておく saver = tf.train.Saver() saver.save(sess, self.model_filename) # 最後にテストデータでの精度を計算して表示する a = sess.run(accuracy, feed_dict={input_data: teX, actual_labels: teY, initial_state: np.zeros([teX.shape[0], self.hidden_layer_size])}) print("Accuracy on test:", a) def predict(self, seq): """ 文章を入力したときに次に来る単語を予測する :param seq: 予測したい単語の直前の文字列。chunk_size 以上の単語数が必要。 :return: """ # 最初に復元したい変数をすべて定義してしまいます tf.reset_default_graph() input_data = tf.placeholder("float", [None, self.chunk_size, self.input_layer_size]) initial_state = tf.placeholder("float", [None, self.hidden_layer_size]) prediction = tf.nn.softmax(self.inference(input_data, initial_state)) predicted_labels = tf.argmax(prediction, 1) # 入力データの作成 # seq を one-hot 表現に変換する。 words = [word for word in seq.split() if not word.startswith("-")] x = np.zeros([1, self.chunk_size, self.input_layer_size]) for i in range(self.chunk_size): word = seq[len(words) - self.chunk_size + i] index = self.dictionary.get(word, self.dictionary[self.unknown_word_symbol]) x[0][i][index] = 1 feed_dict = { input_data: x, # (1, chunk_size, vocabulary_size) initial_state: np.zeros([1, self.hidden_layer_size]) } # tf.Session()を用意 with tf.Session() as sess: # 保存したモデルをロードする。ロード前にすべての変数を用意しておく必要がある。 saver = tf.train.Saver() saver.restore(sess, self.model_filename) # ロードしたモデルを使って予測結果を計算 u, v = sess.run([prediction, predicted_labels], feed_dict=feed_dict) keys = list(self.dictionary.keys()) # コンソールに文字ごとの確率を表示 for i in range(self.vocabulary_size): c = self.unknown_word_symbol if i == (self.vocabulary_size - 1) else keys[i] print(c, ":", u[0][i]) print("Prediction:", seq + " " + ("<???>" if v[0] == (self.vocabulary_size - 1) else keys[v[0]])) return u[0] def build_dict(): cp = Corpus() cp.build_dict() if __name__ == "__main__": #build_dict() ln = Language() # 学習するときに呼び出す #ln.train() # 保存したモデルを使って単語の予測をする ln.predict("some of them looks like")
  • 11. 確認テスト ◦ 1.LSTMとCECが抱える課題について、それぞれ簡潔に述べよ。 解答: LSTMは入力ゲート、出力ゲート、忘却ゲートそしてCEC、それぞれ4つの部品を持つ事で構成されていた。 そのため、LSTMではパラメータ数が多く、計算負荷が高くなるという課題があった。 その中にあるCECであるが、問題点としては学習能力が無い事が挙げられる。(そのために3つのゲートを周りに付け、学習 機能を持たせている、というのがCECの根本的な動きになっている。) ◦ 2.LSTMとGRUの違いを簡潔に述べよ。 解答: LSTMには入力ゲート、出力ゲート、忘却ゲートの3つのゲートとCECがある。 1方のGRUにはCECが無く更新ゲートとリセットゲートを持つ。 LSTMはパラメータが多く、GRUはパラメータが少ない。 LSTMよりGRUの方が計算量は少ない。
  • 12. Section4:双方向RNN ◦ 双方向RNN(Bidirectional RNN) ◦ 過去の情報だけでなく、未来の情報を加味する事で、精度を向上させるためのモデル。例)文章の推敲や機械翻訳等 ◦ 文章というのは過去の情報も未来の情報も1度に入ってくる。過去の単語の羅列に加えて、その先に書いてある単語の羅列につい ても自由にアクセスができる。 ◦ Bidirectional RNN は、中間層の出力を、未来への順伝播と過去への逆伝播の両方向に伝播するネットワークである。 ◦ BRNN では、学習時に、過去と未来の情報の入力を必要とすることから、運用時も過去から未来までのすべての情報を入力しては じめて予測できるようになる。 ◦ BRNN の応用範囲が限定される。例えば、DNA 塩基を k-mer ごとに区切れば、塩基配列解析に BRNN が使えるようになる。 あるいは、1 文全体を入力して、文中にある誤字・脱字の検出などに応用されている。
  • 13. Section5:Seq2Seq • Seq2seqとはEncoder-Decoderモデルの1種を指します(時系列データを入力に取って時系列のデータを出力するモデル)。 • Seq2seqの具体的な用途とは機械対話や機械翻訳等に使用されています。 • Encoder RNN:文の意味を集約する。文から文脈の意味ベクトルの抽出。 • Taking:文章を単語等のトークン事に分割し、トークン毎のIDに分割する(ONE HOT VECTOR)。 • Embedding:IDからそのトークンを表す分散表現ベクトルに変換。数字の並びが似かよっている事は似かよった意味を持つ単語という事にな る ⇒ 単語の意味を抽出したベクトル。 • Encoder RNN:ベクトルを順番にRNNに入力していく。 • Encoder RNN処理手順 • 最後のベクトルを入れた時のhidden stateをfinal stateとして取っておく。 • このfinal stateがthought vectorと呼ばれ、入力した文の意味を表すベクトルになる。 • MLM - Masked Language Model(BERT) • Decoder RNN:システムがアウトプットデータを単語等のトークン毎に生成する構造。 • Decoder RNN 処理手順 • Decoder RNN:Encoder RNNのfinal state(thought vector)から、各tokenの生成確率を出力してい きます。final stateをDecoder RNNのinitial stateとして設定し、Embeddingを入力。 • Sampling:生成確率に基づいてtokenをランダムに選びます。 • Embedding:2で選ばれたtokenをEmbeddingしてDecoder RNNへの次の入力とします。 • Detokenize:1~3を繰り返し、2で得られたtokenを文字列に直します。
  • 14. 確認テスト ◦ 1.下記の選択肢から、seq2seqについて説明しているものを選べ。 (1)時刻に関して順方向と逆方向のRNNを構成し、それら2つの中間層表現を特徴量として利用するものである。 (2)RNNを用いたEncoder-Decoderモデルの一種であり、機械翻訳などのモデルに使われる。 (3)構文木などの木構造に対して、隣接単語から表現ベクトル(フレーズ)を作るという演算を再帰的に行い(重みは共通)、 文全体の表現ベクトルを得るニューラルネットワークである。 (4)RNNの一種であり、単純なRNNにおいて問題となる勾配消失問題をCECとゲートの概念を導入することで解決したも のである。 ◦ 2.Seq2seqとHRED、HREDとVHREDの違いを簡潔に述べよ。 ◦ 3.VAEに関する下記の説明文中の空欄に当てはまる言葉を答えよ。自己符号化器の潜在変数に____を導入したもの。 解答:確率分布 解答: Seq2seqは1問1答しかできない。 HREDは文章の過去の文脈を考慮することができる。 HREDは確かに文脈を意識した文を作る事ができるのだが、ありがちな答えしか出さなくなる。 VHREDは文脈を意識しながら文を生成するモデルにバリエーションを持たせられるように工夫をする仕組みである。 解答:(2)
  • 15. Section6:Word2vec ◦ 単語のOne-Hotベクトルから1つ1うの単語(Embedding表現)意味同志が近くなるようなベクトルを見つけ る。 ◦ 課題:RNNでは単語のような可変長の文字列をNNに与える事はできない ⇒ 固定長形式で単語を表す必要がある。 ◦ メリット:大規模データの分散表現の学習が、現実的な計算速度とメモリ量で実現可能となった。One-HotベクトルからE mbedding表現に変換する時に変換表を用いるが、この変換表を機械学習によって学習させる事で、単語の意味を保ち ながら、より少ない次元のベクトルで単語を表現できる。
  • 16. Section7:Attention Mec hanism ◦ 課題:seq2seqの問題は長い文章への対応が難しい事にある(seq2seqの構造によると、長い文章であろうと短 い文章であろうと、中間層(隠れ層)の大きさは決まっている。)seq2seqでは2単語でも、100単語でも、固定次元 ベクトルの中に入力しなければならない。 ◦ 解決策:Attention Mechanism。1文の中で特に重要な単語というのを自力で見つけられるようにする機 構。途中の中間層の情報量が一定でも重要な情報だけ拾い集める。 ◦ 近年特に性能が上がっている自然言語処理のモデルは全部Attention Mechanismである程、強力である。
  • 19. Section1:強化学習 ◦ 教師あり、教師無し:特徴量を見つけ出し、未知のデータを予想する事が目標。 ◦ 強化学習:優れた方策を見つける事が目標。 ◦ 長期的に報酬を最大化できるように環境の中で行動を選択できるエージェントを作る事を目標とする機械学習の一分野 ⇒ 行動の結果として与えられる利益(報酬)をもとに行 動を決定する原理を改善していく仕組みです。 ◦ 探索と利用のトレードオフ:不完全な知識をもとに行動しながらデータを収集。最適な行動を見つけていく。 ◦ 強化学習で学習するターゲット:方策関数、行動価値関数 ◦ 強化学習の歴史 ◦ 計算速度の進展により大規模な状態を持つ場合が可能となりつつある。 ◦ 関数近似法(価値関数や方策関数を関数近似する手法の事)とQ学習(行動価値関数を、行動する毎に更新する事により学習を進める方法)を組み合わせる手法の登 場。 ◦ 価値関数(価値関数、行動価値関数:状態と価値を組み合わせた価値に注目) ◦ 方策関数:エージェントが取る行動を決定するための関数。 ◦ 方策勾配法について ◦ 方策反復法:方策をモデル化して最適化する手法 ⇒ 方策勾配法 ◦ 定義方法:平均報酬、割引報酬和に対応して、行動価値関数の定義を行い、方策勾配定理が成立する。
  • 20. Section2:AlphaGo • Alpha Go LeeのPolicyNet(方策関数)、ValueNet(価値関数)は共に畳み込みニューラル ネットワーク。 • Policy Net(SoftMax Layer)出力は19x19マスの着手予想確率が出力される。 • Value Net(TanH Layer)出力は現局面の勝率を-1~1で表したものが出力される。 • Alpha Goの学習 • 教師あり学習によるRollOutPolicy(NNではなく線形の方策関数。探索中に高速に着手確率を出すために使用される。 PolicyNetの1000倍速い。)とPolicyNetの学習 • 強化学習によるPolicyNetの学習 • 強化学習によるValueNetの学習 • PolicyNetの強化学習 • ValueNetの学習 • PolicyNetとRollOutPolicyの教師あり学習。 • モンテカルロ木探索(強化学習の学習方法)(価値関数を学習させる時に用いる方法。価値関数をどういうふうに更新す るか。)
  • 21. Section3:軽量化・高速化技術 ◦ 分散深層学習:データ並列、モデル並列 ◦ データ並列化:データを分割し、各ワーカー毎に計算させる。 ◦ 処理のスピードは、お互いのワーカーの計算を待たない非同期型の方が早い。 ◦ 非同期型は最新のモデルのパラメータを利用できないので、学習が不安定になりやすい。-> Stale Gradient Problem ◦ 現在は同期型の方が精度が良いことが多いので、主流となっている。 ◦ 親モデルを各ワーカーに分割し、それぞれのモデルを学習させる。全てのデータで学習が終わった後で、一つのモデルに復元。 ◦ モデルが大きい時はモデル並列化を、データが大きい時はデータ並列化をすると良い。 ◦ ある程度モデルが大きければ、分割した時の効果が目に見えるように出る。 ◦ 並列コンピューティングを用いることで大規模なネットワークを高速に学習させる仕組みを提案。 ◦ 主にモデル並列とデータ並列(非同期型)の提案をしている。 ◦ GPUによる高速化 ◦ 量子化(Quantization):重みの精度を下げることにより計算の高速化と省メモリ化を行う技術。 ◦ 蒸留(Distillaion):複雑で精度の良い教師モデルから軽量な生徒モデルを効率よく学習を行う技術。 ◦ プルーニング:寄与の少ないニューロンをモデルから削減し高速化と省メモリ化を行う技術。
  • 22. 確認テスト 解答:Dilated causal convolution 解答:パラメータ数に対する受容野が広い 解答: (い) HxWxCxKxK (KxK)で出力マップの1ピクセル分は計算できる。 それが(HxWxC)必要である。 従って、計算量は、 HxWxCxKxK となる。 (う) HxWxCxM (C)で出力マップの1ピクセル分は計算できる。 それが(HxWxM)必要である。 従って、計算量は、 HxWxCxM となる。
  • 23. Section4:応用モデル ◦ 「MobileNet(画像認識のモデルで軽量化したモデル)」 ◦ 2017年に精度は最高レベルに達しており、そこから先は軽くて性能が良いモデルを研究する事が多くなった。MobileNetはその先駆け。あまり計算量を増やさずに比較的高性能である事が目標。 ◦ 一般的な畳み込みレイヤ:ストライド1でパディングを適用した場合の畳み込み計算の計算量。 ◦ MobileNetはここから、これをどうにか減らして行こうという試み。 ◦ Depthwise Convolution と Pointwise Convolution の組み合わせで軽量化を実現。 ◦ Depthwise Convolution:入力マップのチャネルごとに畳み込みを実施 ⇒ 計算量を大幅に削減可能。 ◦ Pointwise Convolution:1x1 Conv とも呼ばれる(正確には1x1xC) ⇒ 計算量を大幅に削減可能。 ◦ 「DenseNet(画像認識のネットワーク)」 ◦ DenseBlock ◦ 出力層に前の層の入力を足し合わせる。 ◦ DenseBlock内の各ブロック毎にk個ずつ特徴マップのチャネル数が増加していく時、kを成長率(Growth Rate)と呼ぶ。 ◦ ここでkはハイパーパラメータである。 ◦ kが大きくなる程ネットワークが大きくなるため、小さな整数に設定するのが良い。 ◦ Transition Layer ◦ CNNでは中間層でチャネルサイズを変更する。 ◦ 特徴マップのサイズを変更し、ダウンサンプリングを行うため、Transition Layerと呼ばれる層でDence blockをつなぐ。 ◦ 以上のような構造になっている事で、各ブロック内で特徴マップのサイズは一致。 ◦ DenseNetとResNetの違い ◦ DenseBlockでは前方の各層からの出力全てが後方の層への入力として用いられる。 ◦ RessidualBlockでは前1層の入力のみ後方の層へ入力。
  • 24. Section5:Transformer ◦ 「Self-Attention(自己注意機構)」 ◦ 基本的にTransformerを構成している技術は全然新しい発明等では無く、過去のものを上手くくっつけて再構築したモデルになっているので、引用 だらけの側面がある。計算量のわりに表現力の豊かなモデルとして知られています。 ◦ ニューラル機械翻訳の問題点:長さに弱い。 ◦ 上の問題意識から生まれた「Attention(注意機構)(2015)」 ◦ 情報量が多くなってきた時に何に注意を払って何に注意を払わないで良いかというのを学習的に決定していく、という機構が発明された。 ◦ Attentionは何をしているのか ◦ Attentionは辞書オブジェクト:query(検索クエリ)に一致するKeyを索引し、対応するvalueを取り出す操作であると見做す事ができる。これは 「辞書オブジェクト」の機能と同じである。(Key Value Attentionと呼ばれる。) ◦ 「Transformer(2017)」 ◦ Attention is all you need ◦ 従来、Encoder-Decoder Model の基本だったRNNモデルを全く使用しない。
  • 25. Section5:Transformer class DataLoader(object): def __init__(self, src_insts, tgt_insts, batch_size, shuffle=True): """ :param src_insts: list, 入力言語の文章(単語IDのリスト)のリスト :param tgt_insts: list, 出力言語の文章(単語IDのリスト)のリスト :param batch_size: int, バッチサイズ :param shuffle: bool, サンプルの順番をシャッフルするか否か """ self.data = list(zip(src_insts, tgt_insts)) self.batch_size = batch_size self.shuffle = shuffle self.start_index = 0 self.reset() def reset(self): if self.shuffle: self.data = shuffle(self.data, random_state=random_state) self.start_index = 0 def __iter__(self): return self def __next__(self): def preprocess_seqs(seqs): # パディング max_length = max([len(s) for s in seqs]) data = [s + [PAD] * (max_length - len(s)) for s in seqs] # 単語の位置を表現するベクトルを作成 positions = [[pos+1 if w != PAD else 0 for pos, w in enumerate(seq)] for seq in data] # テンソルに変換 data_tensor = torch.tensor(data, dtype=torch.long, device=device) position_tensor = torch.tensor(positions, dtype=torch.long, device=device) return data_tensor, position_tensor # ポインタが最後まで到達したら初期化する if self.start_index >= len(self.data): self.reset() raise StopIteration() # バッチを取得して前処理 src_seqs, tgt_seqs = zip(*self.data[self.start_index:self.start_index+self.batch_size]) src_data, src_pos = preprocess_seqs(src_seqs) tgt_data, tgt_pos = preprocess_seqs(tgt_seqs) # ポインタを更新する self.start_index += self.batch_size return (src_data, src_pos), (tgt_data, tgt_pos) def position_encoding_init(n_position, d_pos_vec): """ Positional Encodingのための行列の初期化を行う :param n_position: int, 系列長 :param d_pos_vec: int, 隠れ層の次元数 :return torch.tensor, size=(n_position, d_pos_vec) """ # PADがある単語の位置はpos=0にしておき、position_encも0にする position_enc = np.array([ [pos / np.power(10000, 2 * (j // 2) / d_pos_vec) for j in range(d_pos_vec)] if pos != 0 else np.zeros(d_pos_vec) for pos in range(n_position)]) position_enc[1:, 0::2] = np.sin(position_enc[1:, 0::2]) # dim 2i position_enc[1:, 1::2] = np.cos(position_enc[1:, 1::2]) # dim 2i+1 return torch.tensor(position_enc, dtype=torch.float) pe = position_encoding_init(50, 256).numpy() plt.figure(figsize=(16,8)) sns.heatmap(pe, cmap='Blues') plt.show()
  • 26. Section6:物体検知・セグメンテーション • 物体検知:Bounding Box • セマンティックセグメンテーション(意味領域分割):(各ピクセルに対し単一の) クラスラベル • インスタンスセグメンテーション(個体領域分割):(各ピクセルに対し単一の) クラスラベル • 「代表的なデータセット」クラス数が大きい事はうれしいのか? • 目的に応じた「BOX/画像」の選択を。 • 小:アイコン的な映り。日常感とはかけ離れやすい。 • 大:部分的な重なり等も見られる。日常生活のコンテクストに近い。 • 目的に合ったデータセットを選ぶ事が大切(クラス数あるいはBOX/画像を1つの基準として) • VOC12(Visual Object Classes) • ILSVRC12: ImageNetのサブセット • MS COCO18 (Microsoft Common Object in Context) • OICOD18 (Open Images Challenges Object Detection)