深入MNIST
TensorFlow是一个非常强大的用来做大规模数值计算的库。其所擅长的任务之一就是实现以及训练深度神经网络。
在本教程中,我们将学到构建一个TensorFlow模型的基本步骤,并将通过这些步骤为MNIST构建一个深度卷积神经网络。
这个教程假设你已经熟悉神经网络和MNIST数据集。如果你尚未了解,请查看新手指南.
构建一个多层卷积网络
在MNIST上只有91%正确率,实在太糟糕。在这个小节里,我们用一个稍微复杂的模型:卷积神经网络来改善效果。这会达到大概99.2%的准确率。虽然不是最高,但是还是比较让人满意。
权重初始化
为了创建这个模型,我们需要创建大量的权重和偏置项。这个模型中的权重在初始化时应该加入少量的噪声来打破对称性以及避免0梯度。由于我们使用的是ReLU神经元,因此比较好的做法是用一个较小的正数来初始化偏置项,以避免神经元节点输出恒为0的问题(dead neurons)。为了不在建立模型的时候反复做初始化操作,我们定义两个函数用于初始化。
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
卷积和池化
TensorFlow在卷积和池化上有很强的灵活性。我们怎么处理边界?步长应该设多大?在这个实例里,我们会一直使用vanilla版本。我们的卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入是同一个大小。我们的池化用简单传统的2x2大小的模板做max pooling。为了代码更简洁,我们把这部分抽象成一个函数。
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
第一层卷积
现在我们可以开始实现第一层了。它由一个卷积接一个max pooling完成。卷积在每个5x5的patch中算出32个特征。卷积的权重张量形状是[5, 5, 1, 32],前两个维度是patch的大小,接着是输入的通道数目,最后是输出的通道数目。 而对于每一个输出通道都有一个对应的偏置量。
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
为了用这一层,我们把x变成一个4d向量,其第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)。
x_image = tf.reshape(x, [-1,28,28,1])
We then convolve x_image with the weight tensor, add the bias, apply the ReLU function, and finally max pool. 我们把x_image和权值向量进行卷积,加上偏置项,然后应用ReLU激活函数,最后进行max pooling。
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
第二层卷积
为了构建一个更深的网络,我们会把几个类似的层堆叠起来。第二层中,每个5x5的patch会得到64个特征。
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
密集连接层
现在,图片尺寸减小到7x7,我们加入一个有1024个神经元的全连接层,用于处理整个图片。我们把池化层输出的张量reshape成一些向量,乘上权重矩阵,加上偏置,然后对其使用ReLU。
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
Dropout
为了减少过拟合,我们在输出层之前加入dropout。我们用一个placeholder来代表一个神经元的输出在dropout中保持不变的概率。这样我们可以在训练过程中启用dropout,在测试过程中关闭dropout。 TensorFlow的tf.nn.dropout操作除了可以屏蔽神经元的输出外,还会自动处理神经元输出值的scale。所以用dropout的时候可以不用考虑scale。
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
输出层
最后,我们添加一个softmax层,就像前面的单层softmax regression一样。
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
训练和评估模型
这个模型的效果如何呢?
为了进行训练和评估,我们使用与之前简单的单层SoftMax神经网络模型几乎相同的一套代码,只是我们会用更加复杂的ADAM优化器来做梯度最速下降,在feed_dict中加入额外的参数keep_prob来控制dropout比例。然后每100次迭代输出一次日志。
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess.run(tf.initialize_all_variables())
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0})
print "step %d, training accuracy %g"%(i, train_accuracy)
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
print "test accuracy %g"%accuracy.eval(feed_dict={
x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0})
以上代码,在最终测试集上的准确率大概是99.2%。
目前为止,我们已经学会了用TensorFlow快捷地搭建、训练和评估一个复杂一点儿的深度学习模型。
原文地址:Deep MNIST for Experts 翻译:chenweican 校对:HongyangWang
附录
导入数据
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
程序代码
#%% 自定义多层卷积神经网络
# '自定义权重初始化: 避免0梯度,避免神经元输出恒为,为了不在建立模型的时候反复初始化,定义两个函数用于初始化'
def weight_variable(shape):
initial=tf.truncated_normal(shape,stddev=.1)
return tf.Variable(initial)
def bias_variable(shape):
initial=tf.constant(.1,shape=shape)
return tf.Variable(initial)
# '卷积 池化'
def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
# '第一层卷积'
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
x_image=tf.reshape(x,[-1,28,28,1])
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
h_pool1=max_pool_2x2(h_conv1)
# '第2层卷积'
W_conv2=weight_variable([5,5,32,64])
b_conv2=weight_variable([64])
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
h_pool2=max_pool_2x2(h_conv2)
# '密集连接层'
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
# 'Dropout'
keep_prob=tf.placeholder('float')
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
# '输出层'
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
# '模型训练与评估'
cross_entropy=-tf.reduce_sum(y_*tf.log(y_conv))
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction=tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))
# '初始化'
sess=tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(20000):
batch=mnist.train.next_batch(50)
if i%100==0:
train_accuracy=accuracy.eval(session=sess,feed_dict={x:batch[0],y_:batch[1],keep_prob:1.0})
print('step: %d, training accuray %g'%(i,train_accuracy))
sess.run(train_step,feed_dict={x:batch[0],y_:batch[1],keep_prob:.5})
print('test_accuracy %g'%(accuracy.eval(session=sess,feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0})))
#%%
input_data.py
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Functions for downloading and reading MNIST data."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import gzip
import os
import tensorflow.python.platform
import numpy
from six.moves import urllib
from six.moves import xrange # pylint: disable=redefined-builtin
import tensorflow as tf
SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'
def maybe_download(filename, work_directory):
"""Download the data from Yann's website, unless it's already here."""
if not os.path.exists(work_directory):
os.mkdir(work_directory)
filepath = os.path.join(work_directory, filename)
if not os.path.exists(filepath):
filepath, _ = urllib.request.urlretrieve(SOURCE_URL + filename, filepath)
statinfo = os.stat(filepath)
print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
return filepath
def _read32(bytestream):
dt = numpy.dtype(numpy.uint32).newbyteorder('>')
return numpy.frombuffer(bytestream.read(4), dtype=dt)[0]
def extract_images(filename):
"""Extract the images into a 4D uint8 numpy array [index, y, x, depth]."""
print('Extracting', filename)
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2051:
raise ValueError(
'Invalid magic number %d in MNIST image file: %s' %
(magic, filename))
num_images = _read32(bytestream)
rows = _read32(bytestream)
cols = _read32(bytestream)
buf = bytestream.read(rows * cols * num_images)
data = numpy.frombuffer(buf, dtype=numpy.uint8)
data = data.reshape(num_images, rows, cols, 1)
return data
def dense_to_one_hot(labels_dense, num_classes=10):
"""Convert class labels from scalars to one-hot vectors."""
num_labels = labels_dense.shape[0]
index_offset = numpy.arange(num_labels) * num_classes
labels_one_hot = numpy.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot
def extract_labels(filename, one_hot=False):
"""Extract the labels into a 1D uint8 numpy array [index]."""
print('Extracting', filename)
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2049:
raise ValueError(
'Invalid magic number %d in MNIST label file: %s' %
(magic, filename))
num_items = _read32(bytestream)
buf = bytestream.read(num_items)
labels = numpy.frombuffer(buf, dtype=numpy.uint8)
if one_hot:
return dense_to_one_hot(labels)
return labels
class DataSet(object):
def __init__(self, images, labels, fake_data=False, one_hot=False,
dtype=tf.float32):
"""Construct a DataSet.
one_hot arg is used only if fake_data is true. `dtype` can be either
`uint8` to leave the input as `[0, 255]`, or `float32` to rescale into
`[0, 1]`.
"""
dtype = tf.as_dtype(dtype).base_dtype
if dtype not in (tf.uint8, tf.float32):
raise TypeError('Invalid image dtype %r, expected uint8 or float32' %
dtype)
if fake_data:
self._num_examples = 10000
self.one_hot = one_hot
else:
assert images.shape[0] == labels.shape[0], (
'images.shape: %s labels.shape: %s' % (images.shape,
labels.shape))
self._num_examples = images.shape[0]
# Convert shape from [num examples, rows, columns, depth]
# to [num examples, rows*columns] (assuming depth == 1)
assert images.shape[3] == 1
images = images.reshape(images.shape[0],
images.shape[1] * images.shape[2])
if dtype == tf.float32:
# Convert from [0, 255] -> [0.0, 1.0].
images = images.astype(numpy.float32)
images = numpy.multiply(images, 1.0 / 255.0)
self._images = images
self._labels = labels
self._epochs_completed = 0
self._index_in_epoch = 0
@property
def images(self):
return self._images
@property
def labels(self):
return self._labels
@property
def num_examples(self):
return self._num_examples
@property
def epochs_completed(self):
return self._epochs_completed
def next_batch(self, batch_size, fake_data=False):
"""Return the next `batch_size` examples from this data set."""
if fake_data:
fake_image = [1] * 784
if self.one_hot:
fake_label = [1] + [0] * 9
else:
fake_label = 0
return [fake_image for _ in xrange(batch_size)], [
fake_label for _ in xrange(batch_size)]
start = self._index_in_epoch
self._index_in_epoch += batch_size
if self._index_in_epoch > self._num_examples:
# Finished epoch
self._epochs_completed += 1
# Shuffle the data
perm = numpy.arange(self._num_examples)
numpy.random.shuffle(perm)
self._images = self._images[perm]
self._labels = self._labels[perm]
# Start next epoch
start = 0
self._index_in_epoch = batch_size
assert batch_size <= self._num_examples
end = self._index_in_epoch
return self._images[start:end], self._labels[start:end]
def read_data_sets(train_dir, fake_data=False, one_hot=False, dtype=tf.float32):
class DataSets(object):
pass
data_sets = DataSets()
if fake_data:
def fake():
return DataSet([], [], fake_data=True, one_hot=one_hot, dtype=dtype)
data_sets.train = fake()
data_sets.validation = fake()
data_sets.test = fake()
return data_sets
TRAIN_IMAGES = 'train-images-idx3-ubyte.gz'
TRAIN_LABELS = 'train-labels-idx1-ubyte.gz'
TEST_IMAGES = 't10k-images-idx3-ubyte.gz'
TEST_LABELS = 't10k-labels-idx1-ubyte.gz'
VALIDATION_SIZE = 5000
local_file = maybe_download(TRAIN_IMAGES, train_dir)
train_images = extract_images(local_file)
local_file = maybe_download(TRAIN_LABELS, train_dir)
train_labels = extract_labels(local_file, one_hot=one_hot)
local_file = maybe_download(TEST_IMAGES, train_dir)
test_images = extract_images(local_file)
local_file = maybe_download(TEST_LABELS, train_dir)
test_labels = extract_labels(local_file, one_hot=one_hot)
validation_images = train_images[:VALIDATION_SIZE]
validation_labels = train_labels[:VALIDATION_SIZE]
train_images = train_images[VALIDATION_SIZE:]
train_labels = train_labels[VALIDATION_SIZE:]
data_sets.train = DataSet(train_images, train_labels, dtype=dtype)
data_sets.validation = DataSet(validation_images, validation_labels,
dtype=dtype)
data_sets.test = DataSet(test_images, test_labels, dtype=dtype)
return data_sets
运行结果
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data\train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
# '自定义权重初始化: 避免0梯度,避免神经元输出恒为,为了不在建立模型的时候反复初始化,定义两个函数用于初始化'
def weight_variable(shape):
initial=tf.truncated_normal(shape,stddev=.1)
return tf.Variable(initial)
def bias_variable(shape):
initial=tf.constant(.1,shape=shape)
return tf.Variable(initial)
# '卷积 池化'
def conv2d(x,W):
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
# '第一层卷积'
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
x_image=tf.reshape(x,[-1,28,28,1])
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
h_pool1=max_pool_2x2(h_conv1)
# '第2层卷积'
W_conv2=weight_variable([5,5,32,64])
b_conv2=weight_variable([64])
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
h_pool2=max_pool_2x2(h_conv2)
# '密集连接层'
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
# 'Dropout'
rate=tf.placeholder('float')
h_fc1_drop=tf.nn.dropout(h_fc1,rate)
# '输出层'
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
# '模型训练与评估'
cross_entropy=-tf.reduce_sum(y_*tf.log(y_conv))
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction=tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,'float'))
# '初始化'
sess=tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(20000):
batch=mnist.train.next_batch(50)
if i%100==0:
train_accuracy=accuracy.eval(session=sess,feed_dict={x:batch[0],y_:batch[1],rate:1.0})
print('step: %d, training accuray %g'%(i,train_accuracy))
sess.run(train_step,feed_dict={x:batch[0],y_:batch[1],rate:.5})
print('test_accuracy %g'%(accuracy.eval(session=sess,feed_dict={x:mnist.test.images,y_:mnist.test.labels,rate:1.0})))
step: 0, training accuray 0.24
step: 100, training accuray 0.96
step: 200, training accuray 0.92
step: 300, training accuray 0.92
step: 400, training accuray 0.92
step: 500, training accuray 0.92
step: 600, training accuray 0.96
step: 700, training accuray 0.92
step: 800, training accuray 0.92
step: 900, training accuray 1
step: 1000, training accuray 0.98
step: 1100, training accuray 0.96
step: 1200, training accuray 0.96
step: 1300, training accuray 0.98
step: 1400, training accuray 0.98
step: 1500, training accuray 0.96
step: 1600, training accuray 1
step: 1700, training accuray 1
step: 1800, training accuray 0.98
step: 1900, training accuray 0.94
step: 2000, training accuray 1
step: 2100, training accuray 0.98
step: 2200, training accuray 0.98
step: 2300, training accuray 1
step: 2400, training accuray 0.96
step: 2500, training accuray 1
step: 2600, training accuray 0.98
step: 2700, training accuray 0.98
step: 2800, training accuray 0.98
step: 2900, training accuray 0.98
step: 3000, training accuray 0.98
step: 3100, training accuray 0.98
step: 3200, training accuray 0.96
step: 3300, training accuray 0.96
step: 3400, training accuray 1
step: 3500, training accuray 1
step: 3600, training accuray 1
step: 3700, training accuray 1
step: 3800, training accuray 0.96
step: 3900, training accuray 1
step: 4000, training accuray 1
step: 4100, training accuray 1
step: 4200, training accuray 1
step: 4300, training accuray 1
step: 4400, training accuray 1
step: 4500, training accuray 1
step: 4600, training accuray 0.98
step: 4700, training accuray 1
step: 4800, training accuray 1
step: 4900, training accuray 1
step: 5000, training accuray 1
step: 5100, training accuray 0.96
step: 5200, training accuray 0.98
step: 5300, training accuray 1
step: 5400, training accuray 1
step: 5500, training accuray 1
step: 5600, training accuray 1
step: 5700, training accuray 0.98
step: 5800, training accuray 1
step: 5900, training accuray 1
step: 6000, training accuray 0.98
step: 6100, training accuray 0.98
step: 6200, training accuray 1
step: 6300, training accuray 1
step: 6400, training accuray 1
step: 6500, training accuray 0.98
step: 6600, training accuray 0.98
step: 6700, training accuray 1
step: 6800, training accuray 0.98
step: 6900, training accuray 1
step: 7000, training accuray 0.96
step: 7100, training accuray 1
step: 7200, training accuray 1
step: 7300, training accuray 1
step: 7400, training accuray 0.98
step: 7500, training accuray 1
step: 7600, training accuray 1
step: 7700, training accuray 1
step: 7800, training accuray 0.96
step: 7900, training accuray 1
step: 8000, training accuray 1
step: 8100, training accuray 1
step: 8200, training accuray 1
step: 8300, training accuray 1
step: 8400, training accuray 1
step: 8500, training accuray 1
step: 8600, training accuray 1
step: 8700, training accuray 0.98
step: 8800, training accuray 1
step: 8900, training accuray 1
step: 9000, training accuray 0.98
step: 9100, training accuray 1
step: 9200, training accuray 0.98
step: 9300, training accuray 0.98
step: 9400, training accuray 1
step: 9500, training accuray 1
step: 9600, training accuray 1
step: 9700, training accuray 1
step: 9800, training accuray 1
step: 9900, training accuray 1
step: 10000, training accuray 0.98
step: 10100, training accuray 1
step: 10200, training accuray 1
step: 10300, training accuray 1
step: 10400, training accuray 0.98
step: 10500, training accuray 1
step: 10600, training accuray 1
step: 10700, training accuray 1
step: 10800, training accuray 0.98
step: 10900, training accuray 1
step: 11000, training accuray 1
step: 11100, training accuray 1
step: 11200, training accuray 1
step: 11300, training accuray 1
step: 11400, training accuray 0.98
step: 11500, training accuray 1
step: 11600, training accuray 0.98
step: 11700, training accuray 1
step: 11800, training accuray 1
step: 11900, training accuray 0.96
step: 12000, training accuray 1
step: 12100, training accuray 1
step: 12200, training accuray 0.98
step: 12300, training accuray 1
step: 12400, training accuray 1
step: 12500, training accuray 1
step: 12600, training accuray 1
step: 12700, training accuray 1
step: 12800, training accuray 1
step: 12900, training accuray 1
step: 13000, training accuray 0.98
step: 13100, training accuray 1
step: 13200, training accuray 1
step: 13300, training accuray 1
step: 13400, training accuray 1
step: 13500, training accuray 1
step: 13600, training accuray 1
step: 13700, training accuray 1
step: 13800, training accuray 1
step: 13900, training accuray 1
step: 14000, training accuray 1
step: 14100, training accuray 1
step: 14200, training accuray 1
step: 14300, training accuray 1
step: 14400, training accuray 1
step: 14500, training accuray 1
step: 14600, training accuray 1
step: 14700, training accuray 1
step: 14800, training accuray 0.98
step: 14900, training accuray 1
step: 15000, training accuray 1
step: 15100, training accuray 0.98
step: 15200, training accuray 1
step: 15300, training accuray 1
step: 15400, training accuray 1
step: 15500, training accuray 1
step: 15600, training accuray 1
step: 15700, training accuray 1
step: 15800, training accuray 1
step: 15900, training accuray 1
step: 16000, training accuray 1
step: 16100, training accuray 1
step: 16200, training accuray 1
step: 16300, training accuray 1
step: 16400, training accuray 1
step: 16500, training accuray 1
step: 16600, training accuray 1
step: 16700, training accuray 1
step: 16800, training accuray 1
step: 16900, training accuray 1
step: 17000, training accuray 1
step: 17100, training accuray 1
step: 17200, training accuray 1
step: 17300, training accuray 1
step: 17400, training accuray 1
step: 17500, training accuray 1
step: 17600, training accuray 1
step: 17700, training accuray 1
step: 17800, training accuray 1
step: 17900, training accuray 1
step: 18000, training accuray 1
step: 18100, training accuray 1
step: 18200, training accuray 1
step: 18300, training accuray 1
step: 18400, training accuray 1
step: 18500, training accuray 1
step: 18600, training accuray 1
step: 18700, training accuray 1
step: 18800, training accuray 1
step: 18900, training accuray 1
step: 19000, training accuray 1
step: 19100, training accuray 1
step: 19200, training accuray 1
step: 19300, training accuray 1
step: 19400, training accuray 1
step: 19500, training accuray 1
step: 19600, training accuray 1
step: 19700, training accuray 1
step: 19800, training accuray 1
step: 19900, training accuray 1
test_accuracy 0.9919