先日の記事では、画像認識の分野でよく使用されているCNN(畳み込みニューラルネットワーク)について調べました。
今回はこのCNNをTensorflowを用いて実装し、MNISTデータセットの学習を行いました。
使用モデル
使用したCNNのモデルを示します。
- 階層は4とし、畳み込み層を2、全結合層を2としました。
- 活性化関数はRelu6関数を使用
- 出力層にはソフトマックスを使用
- 誤差関数には交差エントロピー誤差関数を使用
CNNについては下記の記事を参照してください。
コード
使用したコードを下記に示します。コードはPython3.6、TensorFlow1.8を用いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
import tensorflow as tf import numpy as np import random as rnd from tensorflow.python.framework import ops as _ops from tensorflow.python.ops import summary_op_util as _summary_op_util from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets ################################################## # MNIST ################################################## data_dir = 'temp' mnist_sets = read_data_sets(data_dir,one_hot=True) ################################################## #function ################################################## def conv_output_size(input, conv_padding, conv_filter, conv_stride, pool_padding, pool_filter, pool_stride): conv_out = (input + 2 * conv_padding - conv_filter) / conv_stride + 1 return ((conv_out + 2 * pool_padding - pool_filter) / pool_stride +1) ################################################## # Classs ################################################## class my_net: def __init__(self, model_num): self.model_num = model_num self.channel = 1 self.conv1_size = 5 self.conv1_feature = 32 self.conv1_stride = 1 self.pool1_size = 2 self.pool1_stride = 2 self.conv2_size = 5 self.conv2_feature = 64 self.conv2_stride = 1 self.pool2_size = 2 self.pool2_stride = 2 self.conv1_out_size = conv_output_size(28, 1, self.conv1_size, self.conv1_stride, 1, self.pool1_size, self.pool1_stride) self.conv2_out_size = conv_output_size(self.conv1_out_size, 1, self.conv2_size, self.conv2_stride, 1, self.pool2_size, self.pool2_stride) self.affine_input_size = int(self.conv2_out_size * self.conv2_out_size * self.conv2_feature) self.affine_1_size = 1024 self.affine_2_size = 10 self.conv_1_w = tf.Variable(tf.truncated_normal([self.conv1_size , self.conv1_size , self.channel, self.conv1_feature],stddev=0.1, dtype=tf.float32)) self.conv_1_b = tf.Variable(tf.truncated_normal([self.conv1_feature],stddev=0.1, dtype=tf.float32)) tf.summary.image("conv1",tf.reshape(self.conv_1_w, [32,5,5,1]), 32) tf.summary.histogram("cw1", self.conv_1_w) tf.summary.histogram("cb1", self.conv_1_b) self.conv_2_w = tf.Variable(tf.truncated_normal([self.conv2_size, self.conv2_size, self.conv1_feature, self.conv2_feature],stddev=0.1, dtype=tf.float32)) self.conv_2_b = tf.Variable(tf.truncated_normal([self.conv2_feature],stddev=0.1, dtype=tf.float32)) tf.summary.histogram("cw2", self.conv_2_w) tf.summary.histogram("cb2", self.conv_2_b) self.affine_1_w = tf.Variable(tf.truncated_normal([self.affine_input_size, self.affine_1_size],stddev=0.1, dtype=tf.float32)) self.affine_1_b = tf.Variable(tf.truncated_normal([self.affine_1_size],stddev=0.1,dtype=tf.float32)) tf.summary.histogram("w1", self.affine_1_w) tf.summary.histogram("b1", self.affine_1_b) self.affine_2_w = tf.Variable(tf.truncated_normal([self.affine_1_size,self.affine_2_size],stddev=0.1, dtype=tf.float32)) self.affine_2_b = tf.Variable(tf.truncated_normal([self.affine_2_size],stddev=0.1, dtype=tf.float32)) tf.summary.histogram("w2", self.affine_2_w) tf.summary.histogram("b2", self.affine_2_b) def my_cnn_net(self, input_data): with tf.name_scope("conv1"): conv1 = tf.nn.conv2d(input_data, self.conv_1_w, strides=[1, self.conv1_stride, self.conv1_stride,1], padding='SAME') relu1 = tf.nn.relu6(conv1 + self.conv_1_b) max_pool1 = tf.nn.max_pool(relu1, ksize=[1, self.pool1_size, self.pool1_size, 1], strides=[1,self.pool1_stride, self.pool1_stride, 1], padding='SAME') with tf.name_scope("conv2"): conv2 = tf.nn.conv2d(max_pool1, self. conv_2_w, strides=[1,self.conv2_stride, self.conv2_stride, 1], padding='SAME') relu2 = tf.nn.relu6(conv2 + self.conv_2_b) max_pool2 = tf.nn.max_pool(relu2, ksize=[1, self.pool2_size, self.pool2_size, 1], strides=[1, self.pool2_stride, self.pool2_stride, 1], padding='SAME') with tf.name_scope("affine1"): flat_output = tf.reshape(max_pool2, [-1, self.affine_input_size]) affine_1 = tf.nn.relu6(tf.add(tf.matmul(flat_output, self.affine_1_w), self.affine_1_b)) with tf.name_scope("affine2"): affine_2 = tf.nn.relu6(tf.add(tf.matmul(affine_1, self.affine_2_w), self.affine_2_b)) return affine_2 def predicter_make(self, net): with tf.name_scope("predict"): predicter = tf.nn.softmax(net) return predicter def loss_make(self, y, t): with tf.name_scope("loss"): loss = tf.reduce_mean(-tf.reduce_sum(t * tf.log(y + 1e-5),axis=[1])) tf.summary.scalar("loss", loss) return loss def train_make(self, loss, learning_rate): with tf.name_scope("train"): train_grad = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) return train_grad def accuracy_make(self, y, t): with tf.name_scope("accuracy"): correct = tf.equal(tf.argmax(y,1),tf.argmax(t,1)) accuracy = tf.reduce_mean(tf.cast(correct,tf.float32)) tf.summary.scalar("accuracy", accuracy) return accuracy def make_model(self,x,t): self.net = self.my_cnn_net(x) self.y = self.predicter_make(self.net) self.loss = self.loss_make(self.y, t) self.train_grad = self.train_make(self.loss,0.01) self.accuracy = self.accuracy_make(self.y, t) def model_summary(self): return tf.summary.merge_all() def make_filewriter(self,sess): return tf.summary.FileWriter("logs/model-{0}-{1}".format(self.model_num, rnd.randrange(1000)), sess.graph) ################################################## # Placeholder ################################################## x = tf.placeholder(tf.float32,shape=[None,784], name="input_data") t = tf.placeholder(tf.float32,shape=[None,10], name="input_labels") ################################################## # Main ################################################## net = my_net(1) net.make_model(tf.reshape(x,[-1, 28, 28,1]), t) init = tf.initialize_all_variables() with tf.Session() as sess: sess.run(init) test_images = mnist_sets.test.images test_labels = mnist_sets.test.labels summary_writer = net.make_filewriter(sess) for step in range(10000): train_images, train_labels = mnist_sets.train.next_batch(50) sess.run(net.train_grad, feed_dict={x:train_images, t:train_labels}) if(step % 500) == 0: summary_str = sess.run(net.model_summary(),feed_dict={x:test_images, t:test_labels}) summary_writer.add_summary(summary_str, step) print("step %d:" %(step)) |
結果
実行結果を示します。実行結果として、多層パーセプトロンの誤差関数の値(loss)とCNNの分類結果の正答率(accuracy)を載せています。実行結果はTensorBoardによってデータを取得しました。
実行の結果、CNNはMNISTデータセットを学習し、最終的に正答率としては98%になりました。
まとめ
- CNN(畳み込みニューラルネットワーク)をPythonとTensorFlowを用いて実装した。
- MNISTをCNNで学習させた結果、手書き数字を95%の精度で認識した。
関連記事