sage/SageでTheanoの手書き数字認識(MNIST)を試す
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[FrontPage]]
#contents
2016/05/03からのアクセス回数 &counter;
ここで紹介したSageワークシートは、以下のURLからダウンロー...
http://www15191ue.sakura.ne.jp:8000/home/pub/70/
また、私の公開しているSageのサーバ(http://www15191ue.sak...
アップロードし、実行したり、変更していろいろ動きを試すこ...
** 参考サイト [#o5c346ed]
ここでは、
[[人工知能に関する断創録>http://aidiary.hatenablog.com/]]
のTheanoに関連する記事をSageのノートブックで実装し、Theno...
今回は、TheanoのTutorialからMNISTの手書き数字認識を以下の...
- [[Theanoによるロジスティック回帰の実装>http://aidiary.h...
** 処理系をSageからPythonに変更 [#fc34ef83]
SageでTheanoのtutorialのMNISTを実行すると、以下のy_predが...
#pre{{
self.y_pred = T.argmax(self.p_y_given_x, axis=1) ...
}}
そこで、ノートブックの処理系をSageからPythonに切り替えま...
「python」を選択してください。
&ref(theano_setup.png);
** 必要なライブラリをインポート [#md27713d]
今回は、ちょっと多くのライブラリを使用します。
sageへの入力:
#pre{{
# 必要なライブラリのインポート
import six.moves.cPickle as pickle
import gzip
import os
import sys
import timeit
import urllib
import numpy as np
import pylab as pl
import theano
import theano.tensor as T
}}
** データのセットアップ [#x390ccc2]
*** データのダウンロード [#pccb0218]
TheanoのTutorialで使用しているMNISTは手書き数字の画像デー...
cPickleモジュールでロードできる形式に圧縮したmnist.pkl.gz...
ダウンロードできます。
- http://deeplearning.net/data/mnist/mnist.pkl.gz
MNISTのデータには、70000の手書き数字データが収録されおり...
- 50000の訓練セット
- 10000のバリデーションセット
- 10000のテストセット
各サンプル画像は、28x28=784個の配列に格納され、データの値...
TensorFlowのMNIST for ML BeginnersのMNISTデータの説明が分...
&ref(https://www.tensorflow.org/versions/r0.7/images/MNIS...
sageへの入力:
#pre{{
# データのダウンロード(最初1回だけ実行)
# urllib.urlretrieve("http://deeplearning.net/data/mnist/...
# Sageサーバではメモリ不足のため、1/10のmini_mnist_pkl.gz...
}}
*** 1/10のサブセットを作成 [#tcd44697]
Sageサーバのメモリは1Gと少ないため、MNISTのデータをそのま...
そこで、1/10のサイズのサブセットデータmini_mnist.pkl.gzを...
sageへの入力:
#pre{{
# データセットをロードする
#f = gzip.open(DATA+"mnist.pkl.gz", 'rb')
f = gzip.open(DATA+"mini_mnist.pkl.gz", 'rb')
train_set, valid_set, test_set = pickle.load(f)
f.close()
}}
sageへの入力:
#pre{{
# データは、(画像データとラベル)のタプルで、画像データは...
print len(train_set), train_set[0].shape, train_set[1].sh...
}}
#pre{{
2 (5000, 784) (5000,) <type 'numpy.int64'>
}}
sageへの入力:
#pre{{
# 以下の手順でmini_mnist.pk.gzを作成(コメントを外す)
#mini_train_set = (train_set[0][0:5000], train_set[1][0:5...
#mini_valid_set = (valid_set[0][0:500], valid_set[1][0:50...
#mini_test_set = (test_set[0][0:500], test_set[1][0:500])
#f = gzip.open(DATA+"mini_mnist.pkl.gz", 'wb')
#pickle.dump((mini_train_set, mini_valid_set, mini_test_s...
#f.close()
}}
*** サンプルデータについて [#ra4d3b5d]
どのような画像データが入っているのか、訓練用データ(train...
sageへの入力:
#pre{{
# 訓練用データを100個表示
for index in range(100):
pl.subplot(10, 10, index + 1)
pl.axis('off')
pl.imshow(train_set[0][index].reshape(28, 28), cmap=p...
pl.savefig(DATA+'sample.png', dpi=50)
html("<img src='sample.png'/>")
}}
&ref(sample.png);
*** データをTheanoの共有変数に格納 [#mf788074]
Theanoの共有変数を使用すると、GPUのメモリ領域に保存され、...
共有変数の値を取り出すときに、get_value()を使用するのは、...
するためと考えられます。
また、GPUで使用するデータは必ずfloat型で格納しなければな...
そのため、ラベルshared_yは、T.cast(shared_y, 'int32')でキ...
これでdatasets変数に訓練用、検証用、テスト用のデータがセ...
sageへの入力:
#pre{{
# データセットをGPUの共有変数に格納
def shared_dataset(data_xy, borrow=True):
data_x, data_y = data_xy
# 共有変数には必ずfloat型で格納
shared_x = theano.shared(
np.asarray(data_x, dtype=theano.config.floatX), b...
shared_y = theano.shared(
np.asarray(data_y, dtype=theano.config.floatX), b...
# ラベルはint型なのでキャストして返す
return shared_x, T.cast(shared_y, 'int32')
test_set_x, test_set_y = shared_dataset(test_set)
valid_set_x, valid_set_y = shared_dataset(valid_set)
train_set_x, train_set_y = shared_dataset(train_set)
datasets = [(train_set_x, train_set_y),
(valid_set_x, valid_set_y),
(test_set_x, test_set_y)]
}}
** 多クラス分類 [#m6100c2f]
ニューラルネットの入力\(x_i\)と出力\(u_i\)の関係は、重み\...
$$
u_i = \sum_j W_{i,j} x_j + b_i
$$
これを分かりやすく説明した図を再度、TensorFlowのMNIST for...
&ref(https://www.tensorflow.org/versions/r0.7/images/soft...
この重みWとバイアスbをTheanoの共有変数でセットしているの...
#pre{{
# 重み行列を初期化
self.W = theano.shared(value=np.zeros((n_in, n_ou...
dtype=thean...
name='W',
borrow=True)
# バイアスベクトルを初期化
self.b = theano.shared(value=np.zeros((n_out,),
dtype=thean...
name='b',
borrow=True)
}}
*** ソフトマック関数 [#r8380dd0]
多クラス分類の活性化関数として使用されるのが、ソフトマッ...
$$
y_i = \frac{exp(u_i)}{\sum_j exp(u_j)}
$$
&ref(https://www.tensorflow.org/versions/r0.7/images/soft...
この部分をTheanoのシンボルで表現している箇所が以下の部分...
#pre{{
# 各サンプルが各クラスに分類される確率を計算する...
# 全データを行列化してまとめて計算している
# 出力は(n_samples, n_out)の行列
self.p_y_given_x = T.nnet.softmax(T.dot(input, se...
}}
人工知能に関する断創録の貴重なコメントがあります。
- T.dot(self.W, input)+ self.bは、サンプルxを1つだけ与え...
- T.dot(input, self.W)+ self.bは、複数のサンプル(ミニバ...
確率が求まったら最終的に一番高い確率が得られるクラスをy_p...
$$
y_{pred} = argmax(y)
$$
TheanoではT.argmax()にaxis=1を指定することでp_y_given_xの...
#pre{{
# 確率が最大のクラスのインデックスを計算
# 出力は(n_samples,)のベクトル
self.y_pred = T.argmax(self.p_y_given_x, axis=1) ...
}}
*** コスト関数 [#t70a10f5]
分類されたクラスkだけ1で、他は0のベクトルを\(d_n\)とする...
$$
p(d | x) = \prod_{k=1}^K p(C_k | x)^{d_k}
$$
訓練データ${ (x_n, d_n)}(n=1,...,N)$に対するwの尤度は、以...
$$
L(W) = \prod_{n=1}^N p(d_n | x_n; W) = \prod_{n=1}^N \pro...
$$
負の対数尤度を誤差関数とすると、
$$
E(W) = - \sum_{n=1}^N \sum_{k=1}^K d_{nk} log y_k(x_n; W)
$$
人工知能に関する断創録では、Sumの代わりに平均meanを使って...
#pre{{
# 式通りに計算するとsumだがmeanの方がよい
return -T.mean(T.log(self.p_y_given_x)[T.arange(y...
}}
sageへの入力:
#pre{{
class LogisticRegression(object):
def __init__(self, input, n_in, n_out):
"""ロジスティック回帰モデルの初期化
input: ミニバッチ単位のデータ行列(n_samples, n_i...
n_in : 入力の次元数
n_out: 出力の次元数
"""
# 重み行列を初期化
self.W = theano.shared(value=np.zeros((n_in, n_ou...
dtype=thean...
name='W',
borrow=True)
# バイアスベクトルを初期化
self.b = theano.shared(value=np.zeros((n_out,),
dtype=thean...
name='b',
borrow=True)
# 各サンプルが各クラスに分類される確率を計算する...
# 全データを行列化してまとめて計算している
# 出力は(n_samples, n_out)の行列
self.p_y_given_x = T.nnet.softmax(T.dot(input, se...
# 確率が最大のクラスのインデックスを計算
# 出力は(n_samples,)のベクトル
self.y_pred = T.argmax(self.p_y_given_x, axis=1)
# ロジスティック回帰モデルのパラメータ
self.params = [self.W, self.b]
# モデルの入力値を保持
self.input = input
def negative_log_likelihood(self, y):
"""誤差関数である負の対数尤度を計算するシンボルを...
yにはinputに対応する正解クラスを渡す
"""
# 式通りに計算するとsumだがmeanの方がよい
return -T.mean(T.log(self.p_y_given_x)[T.arange(y...
def errors(self, y):
"""分類の誤差率を計算するシンボルを返す
yにはinputに対応する正解クラスを渡す"""
if y.ndim != self.y_pred.ndim:
raise TypeError('y should have the same shape...
('y', y.type, 'y_pred', self....
if y.dtype.startswith('int'):
return T.mean(T.neq(self.y_pred, y))
else:
raise NotImplementedError()
}}
** モデルの訓練 [#pae15b8a]
モデルの訓練には、ミニバッチ確率的勾配降下法(MSGD)を使...
確率的勾配降下法(SGD)はただ1つのサンプルで1回だけパラメ...
少数のサンプルをひとまとめにしてその単位で重みを更新しま...
このひとまとめにしたサンプル集合をミニバッチ(minbatch)...
何番目のミニバッチを使用するかを示すのがシンボルindexです。
コードのfunction()のgivensで定義されている部分がミニバッ...
#pre{{
givens={
x: train_set_x[index * batch_size: (index + 1...
y: train_set_y[index * batch_size: (index + 1...
}
}}
確率的勾配降下法で使用するコスト関数とその微分は、負の対...
negative_log_likelihood関数とT.gradの箇所で計算しています。
#pre{{
# 誤差(コスト)を計算 => 最小化したい
cost = classifier.negative_log_likelihood(y)
# コスト関数のtheta = (W,b)の微分を計算
g_W = T.grad(cost=cost, wrt=classifier.W)
g_b = T.grad(cost=cost, wrt=classifier.b)
}}
パラメータの更新式は、Wとbの2個をタプルとして指定します。
#pre{{
# パラメータ更新式
updates = [(classifier.W, classifier.W - learning_rat...
(classifier.b, classifier.b - learning_ra...
}}
関数の定義は以下の通りです。
- inputs:何番目のミニバッチかを示すインデックスをindexで...
- outputs:負の対数尤度を計算するcostを渡す
- updates:update式を渡す
- givens:関数を実行する際にシンボルを置き替えるオプショ...
*** モデルの評価 [#u2830e0b]
モデルの当てはまりの良さをエラー率で評価しています。Logis...
#pre{{
def errors(self, y):
"""分類の誤差率を計算するシンボルを返す
yにはinputに対応する正解クラスを渡す"""
return T.mean(T.neq(self.y_pred, y))
}}
T.neq(self.y_pred, y)で予測クラスと正解クラスが異なる要素...
その平均を取ることでエラー率を計算しています。
*** Early-Stoppingによる収束判定 [#b71e53d3]
検証用データvalid_setのエラー率と訓練用データtrain_setの...
検証用データのエラー率が増加した時点で学習を打ち切る早期...
人工知能に関する断創録に解説されているEarly-Stoppingの説...
- モデルの訓練は訓練データのミニバッチ単位で行う。
- エポック epoch は訓練データのミニバッチを使い切ったら+1...
- 最初の while ループは、最大n_epochs 回エポックを繰り返...
- iterはこれまで訓練に使用したミニバッチの数が入る。つま...
- パラメータ更新回数がpatienceを超えたらもうこれ以上更新...
- patienceを上げるかどうかの判断はバリデーションセットを...
- validation_frequency回更新されるたびにモデルの検証が行...
- バリデーションセットを用いて平均エラー率が計算され、
この平均エラー率がこれまでの最良の平均エラー率より十分な...
- この検証の際にテストセットを用いたモデルのエラー率の評...
sageへの入力:
#pre{{
def sgd_optimization_mnist(learning_rate=0.13, n_epochs=1...
dataset='mnist.pkl.gz',
batch_size=60):
# 先にセットした学習データを利用
# datasets = load_data(dataset)
train_set_x, train_set_y = datasets[0]
valid_set_x, valid_set_y = datasets[1]
test_set_x, test_set_y = datasets[2]
# ミニバッチの数
n_train_batches = train_set_x.get_value(borrow=True)....
n_valid_batches = valid_set_x.get_value(borrow=True)....
n_test_batches = test_set_x.get_value(borrow=True).sh...
print('... building the model')
# シンボルの割り当て
# ミニバッチのインデックスを表すシンボル
index = T.lscalar() # index to a [mini]batch
# ミニバッチの学習データとラベルを表すシンボル
x = T.matrix('x') # data, presented as rasterized im...
y = T.ivector('y') # labels, presented as 1D vector ...
# MNISTの手書き数字を分類する多クラス分類モデル
# 入力は28ピクセルx28ピクセルの画像、出力は0から9のラ...
# 入力はシンボルxを割り当てておいてあとで具体的なデー...
classifier = LogisticRegression(input=x, n_in=28 * 28...
# 誤差(コスト)を計算 => 最小化したい
cost = classifier.negative_log_likelihood(y)
# index番目のテスト用ミニバッチを入力してエラー率を返...
test_model = theano.function(
inputs=[index],
outputs=classifier.errors(y),
givens={ # ここで初めてシンボル x, y を具体的...
x: test_set_x[index * batch_size: (index + 1)...
y: test_set_y[index * batch_size: (index + 1)...
}
)
# index番目のバリデーション用ミニバッチを入力してエラ...
validate_model = theano.function(
inputs=[index],
outputs=classifier.errors(y),
givens={
x: valid_set_x[index * batch_size: (index + 1...
y: valid_set_y[index * batch_size: (index + 1...
}
)
# コスト関数のtheta = (W,b)の微分を計算
g_W = T.grad(cost=cost, wrt=classifier.W)
g_b = T.grad(cost=cost, wrt=classifier.b)
# パラメータ更新式
updates = [(classifier.W, classifier.W - learning_rat...
(classifier.b, classifier.b - le...
# index番目の訓練バッチを入力し、パラメータを更新する...
# 戻り値としてコストが返される
# この関数の呼び出し時にindexに具体的な値が初めて渡さ...
train_model = theano.function(
inputs=[index],
outputs=cost,
updates=updates,
givens={
x: train_set_x[index * batch_size: (index + 1...
y: train_set_y[index * batch_size: (index + 1...
}
)
print('... training the model')
# eary-stoppingのパラメータ
# patience = 5000
patience = 500
patience_increase = 2
improvement_threshold = 0.995
validation_frequency = min(n_train_batches, patience ...
best_validation_loss = np.inf
test_score = 0.
start_time = timeit.default_timer()
done_looping = False
epoch = 0
while (epoch < n_epochs) and (not done_looping):
epoch = epoch + 1
for minibatch_index in range(n_train_batches):
# minibatch_index番目の訓練データのミニバッチ...
minibatch_avg_cost = train_model(minibatch_in...
# validation_frequency回の更新ごとにバリデー...
iter = (epoch - 1) * n_train_batches + miniba...
if (iter + 1) % validation_frequency == 0:
# バリデーションセットの平均エラー率を計算
validation_losses = [validate_model(i)
for i in range(n_val...
this_validation_loss = np.mean(validation...
print(
'epoch %i, minibatch %i/%i, validatio...
(
epoch,
minibatch_index + 1,
n_train_batches,
this_validation_loss * 100.
)
)
# エラー率が十分改善したならまだモデル改...
# patienceを上げてより多くループを回せる...
if this_validation_loss < best_validation...
#improve patience if loss improvement...
if this_validation_loss < best_valida...
improvement_threshold:
patience = max(patience, iter * p...
best_validation_loss = this_validatio...
# テストセットを用いたエラー率も求め...
test_losses = [test_model(i)
for i in range(n_test_...
test_score = np.mean(test_losses)
print(
(
' epoch %i, minibatch %i/...
' best model %f %%'
) %
(
epoch,
minibatch_index + 1,
n_train_batches,
test_score * 100.
)
)
# save the best model
with open(DATA+'best_model.pkl', 'wb'...
pickle.dump(classifier, f)
# patienceを超えたらループを終了
if patience <= iter:
done_looping = True
break
end_time = timeit.default_timer()
print(
(
'Optimization complete with best validation s...
'with test performance %f %%'
)
% (best_validation_loss * 100., test_score * 100.)
)
print('The code run for %d epochs, with %f epochs/sec...
epoch, 1. * epoch / (end_time - start_time)))
print('Ran for %.1fs' % ((end_time - start_time)))
}}
sageへの入力:
#pre{{
sgd_optimization_mnist()
}}
#pre{{
... building the model
... training the model
epoch 1, minibatch 83/83, validation error 16.458333 %
epoch 1, minibatch 83/83, test error of best model 1...
epoch 2, minibatch 83/83, validation error 14.375000 %
epoch 2, minibatch 83/83, test error of best model 1...
epoch 3, minibatch 83/83, validation error 13.333333 %
epoch 3, minibatch 83/83, test error of best model 1...
epoch 4, minibatch 83/83, validation error 13.541667 %
epoch 5, minibatch 83/83, validation error 13.750000 %
epoch 6, minibatch 83/83, validation error 13.125000 %
epoch 6, minibatch 83/83, test error of best model 1...
epoch 7, minibatch 83/83, validation error 12.916667 %
epoch 7, minibatch 83/83, test error of best model 1...
epoch 8, minibatch 83/83, validation error 13.125000 %
epoch 9, minibatch 83/83, validation error 13.125000 %
epoch 10, minibatch 83/83, validation error 12.916667 %
epoch 11, minibatch 83/83, validation error 12.916667 %
epoch 12, minibatch 83/83, validation error 12.291667 %
epoch 12, minibatch 83/83, test error of best model ...
epoch 13, minibatch 83/83, validation error 12.291667 %
epoch 14, minibatch 83/83, validation error 12.500000 %
epoch 15, minibatch 83/83, validation error 12.500000 %
epoch 16, minibatch 83/83, validation error 12.500000 %
epoch 17, minibatch 83/83, validation error 12.500000 %
epoch 18, minibatch 83/83, validation error 12.500000 %
epoch 19, minibatch 83/83, validation error 12.708333 %
epoch 20, minibatch 83/83, validation error 12.708333 %
epoch 21, minibatch 83/83, validation error 12.708333 %
epoch 22, minibatch 83/83, validation error 12.708333 %
epoch 23, minibatch 83/83, validation error 13.125000 %
Optimization complete with best validation score of 12.29...
The code run for 24 epochs, with 7.298651 epochs/sec
Ran for 3.3s
}}
** 学習結果を使った予測 [#yfbc6279]
テスト用データtest_setの最初の25個に対して認識を行い、予...
1/10の学習データでもそこそこ良い結果が得られています。
sageへの入力:
#pre{{
# 学習結果をテスト用データで確かめる
classifier = pickle.load(open(DATA+'best_model.pkl'))
test_set_x, test_set_y = datasets[2]
test_set_x = test_set_x.get_value()
# compile a predictor function
predict_model = theano.function(
inputs=[classifier.input],
outputs=classifier.p_y_given_x
)
predicted_values = predict_model(test_set_x[:25])
print("Predicted values for the first 10 examples in test...
print(["(%d, %.3f)" % (np.argmax(value), max(value)) for ...
}}
#pre{{
Predicted values for the first 10 examples in test set:
['(7, 0.988)', '(2, 0.733)', '(1, 0.951)', '(0, 0.995)', ...
'(1, 0.979)', '(4, 0.957)', '(9, 0.912)', '(6, 0.912)', '...
'(0, 0.904)', '(6, 0.668)', '(9, 0.917)', '(0, 0.983)', '...
'(5, 0.832)', '(9, 0.790)', '(7, 0.986)', '(3, 0.659)', '...
'(9, 0.775)', '(6, 0.952)', '(6, 0.801)', '(5, 0.955)', '...
}}
sageへの入力:
#pre{{
# 画像と認識結果を一緒に表示
for index in range(25):
pl.subplot(5, 5, index + 1)
pl.axis('off')
pl.imshow(test_set_x[index].reshape(28, 28), cmap=pl....
pl.title('%i' % predicted_values[index])
pl.savefig(DATA+'predicted.png', dpi=75)
html("<img src='predicted.png'/>")
}}
&ref(predicted.png);
*** 重みWのパターン [#z06e2deb]
最後に各クラスを識別した重みWがどのように形に求まったのか...
赤い部分で正で、葵部分が負の値です。各数字の特徴的な部分...
sageへの入力:
#pre{{
# Wにどのような値がセットされたか表示する
w = classifier.W.get_value()
for index in range(10):
pl.subplot(2, 5, index + 1)
pl.axis('off')
pl.imshow(w[:, index].reshape(28, 28), cmap=pl.cm. sp...
pl.title('%i' % index)
pl.savefig(DATA+'weight.png', dpi=75)
html("<img src='weight.png'/>")
}}
&ref(weight.png);
** コメント [#me141960]
#vote(おもしろかった[2],そうでもない[0],わかりずらい[0])
皆様のご意見、ご希望をお待ちしております。
- ロジスティック回帰の最後でエラーが出ているのを修正し、...
#comment_kcaptcha
終了行:
[[FrontPage]]
#contents
2016/05/03からのアクセス回数 &counter;
ここで紹介したSageワークシートは、以下のURLからダウンロー...
http://www15191ue.sakura.ne.jp:8000/home/pub/70/
また、私の公開しているSageのサーバ(http://www15191ue.sak...
アップロードし、実行したり、変更していろいろ動きを試すこ...
** 参考サイト [#o5c346ed]
ここでは、
[[人工知能に関する断創録>http://aidiary.hatenablog.com/]]
のTheanoに関連する記事をSageのノートブックで実装し、Theno...
今回は、TheanoのTutorialからMNISTの手書き数字認識を以下の...
- [[Theanoによるロジスティック回帰の実装>http://aidiary.h...
** 処理系をSageからPythonに変更 [#fc34ef83]
SageでTheanoのtutorialのMNISTを実行すると、以下のy_predが...
#pre{{
self.y_pred = T.argmax(self.p_y_given_x, axis=1) ...
}}
そこで、ノートブックの処理系をSageからPythonに切り替えま...
「python」を選択してください。
&ref(theano_setup.png);
** 必要なライブラリをインポート [#md27713d]
今回は、ちょっと多くのライブラリを使用します。
sageへの入力:
#pre{{
# 必要なライブラリのインポート
import six.moves.cPickle as pickle
import gzip
import os
import sys
import timeit
import urllib
import numpy as np
import pylab as pl
import theano
import theano.tensor as T
}}
** データのセットアップ [#x390ccc2]
*** データのダウンロード [#pccb0218]
TheanoのTutorialで使用しているMNISTは手書き数字の画像デー...
cPickleモジュールでロードできる形式に圧縮したmnist.pkl.gz...
ダウンロードできます。
- http://deeplearning.net/data/mnist/mnist.pkl.gz
MNISTのデータには、70000の手書き数字データが収録されおり...
- 50000の訓練セット
- 10000のバリデーションセット
- 10000のテストセット
各サンプル画像は、28x28=784個の配列に格納され、データの値...
TensorFlowのMNIST for ML BeginnersのMNISTデータの説明が分...
&ref(https://www.tensorflow.org/versions/r0.7/images/MNIS...
sageへの入力:
#pre{{
# データのダウンロード(最初1回だけ実行)
# urllib.urlretrieve("http://deeplearning.net/data/mnist/...
# Sageサーバではメモリ不足のため、1/10のmini_mnist_pkl.gz...
}}
*** 1/10のサブセットを作成 [#tcd44697]
Sageサーバのメモリは1Gと少ないため、MNISTのデータをそのま...
そこで、1/10のサイズのサブセットデータmini_mnist.pkl.gzを...
sageへの入力:
#pre{{
# データセットをロードする
#f = gzip.open(DATA+"mnist.pkl.gz", 'rb')
f = gzip.open(DATA+"mini_mnist.pkl.gz", 'rb')
train_set, valid_set, test_set = pickle.load(f)
f.close()
}}
sageへの入力:
#pre{{
# データは、(画像データとラベル)のタプルで、画像データは...
print len(train_set), train_set[0].shape, train_set[1].sh...
}}
#pre{{
2 (5000, 784) (5000,) <type 'numpy.int64'>
}}
sageへの入力:
#pre{{
# 以下の手順でmini_mnist.pk.gzを作成(コメントを外す)
#mini_train_set = (train_set[0][0:5000], train_set[1][0:5...
#mini_valid_set = (valid_set[0][0:500], valid_set[1][0:50...
#mini_test_set = (test_set[0][0:500], test_set[1][0:500])
#f = gzip.open(DATA+"mini_mnist.pkl.gz", 'wb')
#pickle.dump((mini_train_set, mini_valid_set, mini_test_s...
#f.close()
}}
*** サンプルデータについて [#ra4d3b5d]
どのような画像データが入っているのか、訓練用データ(train...
sageへの入力:
#pre{{
# 訓練用データを100個表示
for index in range(100):
pl.subplot(10, 10, index + 1)
pl.axis('off')
pl.imshow(train_set[0][index].reshape(28, 28), cmap=p...
pl.savefig(DATA+'sample.png', dpi=50)
html("<img src='sample.png'/>")
}}
&ref(sample.png);
*** データをTheanoの共有変数に格納 [#mf788074]
Theanoの共有変数を使用すると、GPUのメモリ領域に保存され、...
共有変数の値を取り出すときに、get_value()を使用するのは、...
するためと考えられます。
また、GPUで使用するデータは必ずfloat型で格納しなければな...
そのため、ラベルshared_yは、T.cast(shared_y, 'int32')でキ...
これでdatasets変数に訓練用、検証用、テスト用のデータがセ...
sageへの入力:
#pre{{
# データセットをGPUの共有変数に格納
def shared_dataset(data_xy, borrow=True):
data_x, data_y = data_xy
# 共有変数には必ずfloat型で格納
shared_x = theano.shared(
np.asarray(data_x, dtype=theano.config.floatX), b...
shared_y = theano.shared(
np.asarray(data_y, dtype=theano.config.floatX), b...
# ラベルはint型なのでキャストして返す
return shared_x, T.cast(shared_y, 'int32')
test_set_x, test_set_y = shared_dataset(test_set)
valid_set_x, valid_set_y = shared_dataset(valid_set)
train_set_x, train_set_y = shared_dataset(train_set)
datasets = [(train_set_x, train_set_y),
(valid_set_x, valid_set_y),
(test_set_x, test_set_y)]
}}
** 多クラス分類 [#m6100c2f]
ニューラルネットの入力\(x_i\)と出力\(u_i\)の関係は、重み\...
$$
u_i = \sum_j W_{i,j} x_j + b_i
$$
これを分かりやすく説明した図を再度、TensorFlowのMNIST for...
&ref(https://www.tensorflow.org/versions/r0.7/images/soft...
この重みWとバイアスbをTheanoの共有変数でセットしているの...
#pre{{
# 重み行列を初期化
self.W = theano.shared(value=np.zeros((n_in, n_ou...
dtype=thean...
name='W',
borrow=True)
# バイアスベクトルを初期化
self.b = theano.shared(value=np.zeros((n_out,),
dtype=thean...
name='b',
borrow=True)
}}
*** ソフトマック関数 [#r8380dd0]
多クラス分類の活性化関数として使用されるのが、ソフトマッ...
$$
y_i = \frac{exp(u_i)}{\sum_j exp(u_j)}
$$
&ref(https://www.tensorflow.org/versions/r0.7/images/soft...
この部分をTheanoのシンボルで表現している箇所が以下の部分...
#pre{{
# 各サンプルが各クラスに分類される確率を計算する...
# 全データを行列化してまとめて計算している
# 出力は(n_samples, n_out)の行列
self.p_y_given_x = T.nnet.softmax(T.dot(input, se...
}}
人工知能に関する断創録の貴重なコメントがあります。
- T.dot(self.W, input)+ self.bは、サンプルxを1つだけ与え...
- T.dot(input, self.W)+ self.bは、複数のサンプル(ミニバ...
確率が求まったら最終的に一番高い確率が得られるクラスをy_p...
$$
y_{pred} = argmax(y)
$$
TheanoではT.argmax()にaxis=1を指定することでp_y_given_xの...
#pre{{
# 確率が最大のクラスのインデックスを計算
# 出力は(n_samples,)のベクトル
self.y_pred = T.argmax(self.p_y_given_x, axis=1) ...
}}
*** コスト関数 [#t70a10f5]
分類されたクラスkだけ1で、他は0のベクトルを\(d_n\)とする...
$$
p(d | x) = \prod_{k=1}^K p(C_k | x)^{d_k}
$$
訓練データ${ (x_n, d_n)}(n=1,...,N)$に対するwの尤度は、以...
$$
L(W) = \prod_{n=1}^N p(d_n | x_n; W) = \prod_{n=1}^N \pro...
$$
負の対数尤度を誤差関数とすると、
$$
E(W) = - \sum_{n=1}^N \sum_{k=1}^K d_{nk} log y_k(x_n; W)
$$
人工知能に関する断創録では、Sumの代わりに平均meanを使って...
#pre{{
# 式通りに計算するとsumだがmeanの方がよい
return -T.mean(T.log(self.p_y_given_x)[T.arange(y...
}}
sageへの入力:
#pre{{
class LogisticRegression(object):
def __init__(self, input, n_in, n_out):
"""ロジスティック回帰モデルの初期化
input: ミニバッチ単位のデータ行列(n_samples, n_i...
n_in : 入力の次元数
n_out: 出力の次元数
"""
# 重み行列を初期化
self.W = theano.shared(value=np.zeros((n_in, n_ou...
dtype=thean...
name='W',
borrow=True)
# バイアスベクトルを初期化
self.b = theano.shared(value=np.zeros((n_out,),
dtype=thean...
name='b',
borrow=True)
# 各サンプルが各クラスに分類される確率を計算する...
# 全データを行列化してまとめて計算している
# 出力は(n_samples, n_out)の行列
self.p_y_given_x = T.nnet.softmax(T.dot(input, se...
# 確率が最大のクラスのインデックスを計算
# 出力は(n_samples,)のベクトル
self.y_pred = T.argmax(self.p_y_given_x, axis=1)
# ロジスティック回帰モデルのパラメータ
self.params = [self.W, self.b]
# モデルの入力値を保持
self.input = input
def negative_log_likelihood(self, y):
"""誤差関数である負の対数尤度を計算するシンボルを...
yにはinputに対応する正解クラスを渡す
"""
# 式通りに計算するとsumだがmeanの方がよい
return -T.mean(T.log(self.p_y_given_x)[T.arange(y...
def errors(self, y):
"""分類の誤差率を計算するシンボルを返す
yにはinputに対応する正解クラスを渡す"""
if y.ndim != self.y_pred.ndim:
raise TypeError('y should have the same shape...
('y', y.type, 'y_pred', self....
if y.dtype.startswith('int'):
return T.mean(T.neq(self.y_pred, y))
else:
raise NotImplementedError()
}}
** モデルの訓練 [#pae15b8a]
モデルの訓練には、ミニバッチ確率的勾配降下法(MSGD)を使...
確率的勾配降下法(SGD)はただ1つのサンプルで1回だけパラメ...
少数のサンプルをひとまとめにしてその単位で重みを更新しま...
このひとまとめにしたサンプル集合をミニバッチ(minbatch)...
何番目のミニバッチを使用するかを示すのがシンボルindexです。
コードのfunction()のgivensで定義されている部分がミニバッ...
#pre{{
givens={
x: train_set_x[index * batch_size: (index + 1...
y: train_set_y[index * batch_size: (index + 1...
}
}}
確率的勾配降下法で使用するコスト関数とその微分は、負の対...
negative_log_likelihood関数とT.gradの箇所で計算しています。
#pre{{
# 誤差(コスト)を計算 => 最小化したい
cost = classifier.negative_log_likelihood(y)
# コスト関数のtheta = (W,b)の微分を計算
g_W = T.grad(cost=cost, wrt=classifier.W)
g_b = T.grad(cost=cost, wrt=classifier.b)
}}
パラメータの更新式は、Wとbの2個をタプルとして指定します。
#pre{{
# パラメータ更新式
updates = [(classifier.W, classifier.W - learning_rat...
(classifier.b, classifier.b - learning_ra...
}}
関数の定義は以下の通りです。
- inputs:何番目のミニバッチかを示すインデックスをindexで...
- outputs:負の対数尤度を計算するcostを渡す
- updates:update式を渡す
- givens:関数を実行する際にシンボルを置き替えるオプショ...
*** モデルの評価 [#u2830e0b]
モデルの当てはまりの良さをエラー率で評価しています。Logis...
#pre{{
def errors(self, y):
"""分類の誤差率を計算するシンボルを返す
yにはinputに対応する正解クラスを渡す"""
return T.mean(T.neq(self.y_pred, y))
}}
T.neq(self.y_pred, y)で予測クラスと正解クラスが異なる要素...
その平均を取ることでエラー率を計算しています。
*** Early-Stoppingによる収束判定 [#b71e53d3]
検証用データvalid_setのエラー率と訓練用データtrain_setの...
検証用データのエラー率が増加した時点で学習を打ち切る早期...
人工知能に関する断創録に解説されているEarly-Stoppingの説...
- モデルの訓練は訓練データのミニバッチ単位で行う。
- エポック epoch は訓練データのミニバッチを使い切ったら+1...
- 最初の while ループは、最大n_epochs 回エポックを繰り返...
- iterはこれまで訓練に使用したミニバッチの数が入る。つま...
- パラメータ更新回数がpatienceを超えたらもうこれ以上更新...
- patienceを上げるかどうかの判断はバリデーションセットを...
- validation_frequency回更新されるたびにモデルの検証が行...
- バリデーションセットを用いて平均エラー率が計算され、
この平均エラー率がこれまでの最良の平均エラー率より十分な...
- この検証の際にテストセットを用いたモデルのエラー率の評...
sageへの入力:
#pre{{
def sgd_optimization_mnist(learning_rate=0.13, n_epochs=1...
dataset='mnist.pkl.gz',
batch_size=60):
# 先にセットした学習データを利用
# datasets = load_data(dataset)
train_set_x, train_set_y = datasets[0]
valid_set_x, valid_set_y = datasets[1]
test_set_x, test_set_y = datasets[2]
# ミニバッチの数
n_train_batches = train_set_x.get_value(borrow=True)....
n_valid_batches = valid_set_x.get_value(borrow=True)....
n_test_batches = test_set_x.get_value(borrow=True).sh...
print('... building the model')
# シンボルの割り当て
# ミニバッチのインデックスを表すシンボル
index = T.lscalar() # index to a [mini]batch
# ミニバッチの学習データとラベルを表すシンボル
x = T.matrix('x') # data, presented as rasterized im...
y = T.ivector('y') # labels, presented as 1D vector ...
# MNISTの手書き数字を分類する多クラス分類モデル
# 入力は28ピクセルx28ピクセルの画像、出力は0から9のラ...
# 入力はシンボルxを割り当てておいてあとで具体的なデー...
classifier = LogisticRegression(input=x, n_in=28 * 28...
# 誤差(コスト)を計算 => 最小化したい
cost = classifier.negative_log_likelihood(y)
# index番目のテスト用ミニバッチを入力してエラー率を返...
test_model = theano.function(
inputs=[index],
outputs=classifier.errors(y),
givens={ # ここで初めてシンボル x, y を具体的...
x: test_set_x[index * batch_size: (index + 1)...
y: test_set_y[index * batch_size: (index + 1)...
}
)
# index番目のバリデーション用ミニバッチを入力してエラ...
validate_model = theano.function(
inputs=[index],
outputs=classifier.errors(y),
givens={
x: valid_set_x[index * batch_size: (index + 1...
y: valid_set_y[index * batch_size: (index + 1...
}
)
# コスト関数のtheta = (W,b)の微分を計算
g_W = T.grad(cost=cost, wrt=classifier.W)
g_b = T.grad(cost=cost, wrt=classifier.b)
# パラメータ更新式
updates = [(classifier.W, classifier.W - learning_rat...
(classifier.b, classifier.b - le...
# index番目の訓練バッチを入力し、パラメータを更新する...
# 戻り値としてコストが返される
# この関数の呼び出し時にindexに具体的な値が初めて渡さ...
train_model = theano.function(
inputs=[index],
outputs=cost,
updates=updates,
givens={
x: train_set_x[index * batch_size: (index + 1...
y: train_set_y[index * batch_size: (index + 1...
}
)
print('... training the model')
# eary-stoppingのパラメータ
# patience = 5000
patience = 500
patience_increase = 2
improvement_threshold = 0.995
validation_frequency = min(n_train_batches, patience ...
best_validation_loss = np.inf
test_score = 0.
start_time = timeit.default_timer()
done_looping = False
epoch = 0
while (epoch < n_epochs) and (not done_looping):
epoch = epoch + 1
for minibatch_index in range(n_train_batches):
# minibatch_index番目の訓練データのミニバッチ...
minibatch_avg_cost = train_model(minibatch_in...
# validation_frequency回の更新ごとにバリデー...
iter = (epoch - 1) * n_train_batches + miniba...
if (iter + 1) % validation_frequency == 0:
# バリデーションセットの平均エラー率を計算
validation_losses = [validate_model(i)
for i in range(n_val...
this_validation_loss = np.mean(validation...
print(
'epoch %i, minibatch %i/%i, validatio...
(
epoch,
minibatch_index + 1,
n_train_batches,
this_validation_loss * 100.
)
)
# エラー率が十分改善したならまだモデル改...
# patienceを上げてより多くループを回せる...
if this_validation_loss < best_validation...
#improve patience if loss improvement...
if this_validation_loss < best_valida...
improvement_threshold:
patience = max(patience, iter * p...
best_validation_loss = this_validatio...
# テストセットを用いたエラー率も求め...
test_losses = [test_model(i)
for i in range(n_test_...
test_score = np.mean(test_losses)
print(
(
' epoch %i, minibatch %i/...
' best model %f %%'
) %
(
epoch,
minibatch_index + 1,
n_train_batches,
test_score * 100.
)
)
# save the best model
with open(DATA+'best_model.pkl', 'wb'...
pickle.dump(classifier, f)
# patienceを超えたらループを終了
if patience <= iter:
done_looping = True
break
end_time = timeit.default_timer()
print(
(
'Optimization complete with best validation s...
'with test performance %f %%'
)
% (best_validation_loss * 100., test_score * 100.)
)
print('The code run for %d epochs, with %f epochs/sec...
epoch, 1. * epoch / (end_time - start_time)))
print('Ran for %.1fs' % ((end_time - start_time)))
}}
sageへの入力:
#pre{{
sgd_optimization_mnist()
}}
#pre{{
... building the model
... training the model
epoch 1, minibatch 83/83, validation error 16.458333 %
epoch 1, minibatch 83/83, test error of best model 1...
epoch 2, minibatch 83/83, validation error 14.375000 %
epoch 2, minibatch 83/83, test error of best model 1...
epoch 3, minibatch 83/83, validation error 13.333333 %
epoch 3, minibatch 83/83, test error of best model 1...
epoch 4, minibatch 83/83, validation error 13.541667 %
epoch 5, minibatch 83/83, validation error 13.750000 %
epoch 6, minibatch 83/83, validation error 13.125000 %
epoch 6, minibatch 83/83, test error of best model 1...
epoch 7, minibatch 83/83, validation error 12.916667 %
epoch 7, minibatch 83/83, test error of best model 1...
epoch 8, minibatch 83/83, validation error 13.125000 %
epoch 9, minibatch 83/83, validation error 13.125000 %
epoch 10, minibatch 83/83, validation error 12.916667 %
epoch 11, minibatch 83/83, validation error 12.916667 %
epoch 12, minibatch 83/83, validation error 12.291667 %
epoch 12, minibatch 83/83, test error of best model ...
epoch 13, minibatch 83/83, validation error 12.291667 %
epoch 14, minibatch 83/83, validation error 12.500000 %
epoch 15, minibatch 83/83, validation error 12.500000 %
epoch 16, minibatch 83/83, validation error 12.500000 %
epoch 17, minibatch 83/83, validation error 12.500000 %
epoch 18, minibatch 83/83, validation error 12.500000 %
epoch 19, minibatch 83/83, validation error 12.708333 %
epoch 20, minibatch 83/83, validation error 12.708333 %
epoch 21, minibatch 83/83, validation error 12.708333 %
epoch 22, minibatch 83/83, validation error 12.708333 %
epoch 23, minibatch 83/83, validation error 13.125000 %
Optimization complete with best validation score of 12.29...
The code run for 24 epochs, with 7.298651 epochs/sec
Ran for 3.3s
}}
** 学習結果を使った予測 [#yfbc6279]
テスト用データtest_setの最初の25個に対して認識を行い、予...
1/10の学習データでもそこそこ良い結果が得られています。
sageへの入力:
#pre{{
# 学習結果をテスト用データで確かめる
classifier = pickle.load(open(DATA+'best_model.pkl'))
test_set_x, test_set_y = datasets[2]
test_set_x = test_set_x.get_value()
# compile a predictor function
predict_model = theano.function(
inputs=[classifier.input],
outputs=classifier.p_y_given_x
)
predicted_values = predict_model(test_set_x[:25])
print("Predicted values for the first 10 examples in test...
print(["(%d, %.3f)" % (np.argmax(value), max(value)) for ...
}}
#pre{{
Predicted values for the first 10 examples in test set:
['(7, 0.988)', '(2, 0.733)', '(1, 0.951)', '(0, 0.995)', ...
'(1, 0.979)', '(4, 0.957)', '(9, 0.912)', '(6, 0.912)', '...
'(0, 0.904)', '(6, 0.668)', '(9, 0.917)', '(0, 0.983)', '...
'(5, 0.832)', '(9, 0.790)', '(7, 0.986)', '(3, 0.659)', '...
'(9, 0.775)', '(6, 0.952)', '(6, 0.801)', '(5, 0.955)', '...
}}
sageへの入力:
#pre{{
# 画像と認識結果を一緒に表示
for index in range(25):
pl.subplot(5, 5, index + 1)
pl.axis('off')
pl.imshow(test_set_x[index].reshape(28, 28), cmap=pl....
pl.title('%i' % predicted_values[index])
pl.savefig(DATA+'predicted.png', dpi=75)
html("<img src='predicted.png'/>")
}}
&ref(predicted.png);
*** 重みWのパターン [#z06e2deb]
最後に各クラスを識別した重みWがどのように形に求まったのか...
赤い部分で正で、葵部分が負の値です。各数字の特徴的な部分...
sageへの入力:
#pre{{
# Wにどのような値がセットされたか表示する
w = classifier.W.get_value()
for index in range(10):
pl.subplot(2, 5, index + 1)
pl.axis('off')
pl.imshow(w[:, index].reshape(28, 28), cmap=pl.cm. sp...
pl.title('%i' % index)
pl.savefig(DATA+'weight.png', dpi=75)
html("<img src='weight.png'/>")
}}
&ref(weight.png);
** コメント [#me141960]
#vote(おもしろかった[2],そうでもない[0],わかりずらい[0])
皆様のご意見、ご希望をお待ちしております。
- ロジスティック回帰の最後でエラーが出ているのを修正し、...
#comment_kcaptcha
ページ名:
SmartDoc