经过这两天的阅读,算是稍稍掌握了tensorflow的一些用法。
占位符
我们定义Lenet类,在类里构建网络。
构建类的实例需要初始化内部参数,内部参数通过self.***定义实现。
但是训练过程我们用的数据每一次是不同的,因此通过定义占位符实现,定义数据的格式和大小,在每一次训练时进行传递不同的数据。
占位符的使用在(一)里讲过了。
再说一下,tf.cast:用于改变某个张量的数据类型
tensorflow有一个命名域的问题:
https://blog.csdn.net/u012436149/article/details/53081454
本次代码中网络的构建是通过slim库实现的,这个库相当于对tf自带的conv又进行了一次封装。
https://blog.csdn.net/Cyiano/article/details/75006883
https://www.jianshu.com/p/4b608c2313e2
关于slim库的一些资料放在这里了。建议看到我这篇文章得大家看一下撒。
tip1:构建网络的过程中,我们往往需要随时查看现在网络的结果,但这些网络都是张量,所以通过get_shape()函数查看。
net = slim.max_pool2d(net, [2, 2], scope='pool4') print(net.get_shape())
就像这样。
tip2:卷积过程中,我们总是会遇到一个padding的参数,它有两种选择,“SAME”"VALID"。
根据上述描述我们就可以知道;假设一个28*28的图像,经过5*5的卷积核,步长为1,那么卷积后的结果依旧是28*28.
其他的在代码里都有实现啦~~
不算上ui界面,这次代码就算是看完啦~理解了很多东西~嘎嘎嘎~
但是好像写的不够清晰。没事,以后有机会。
接下来,我要自己手撸一遍!
#!usr/bin/python
# -*- coding:<encoding name> -*-
import tensorflow as tf
import tensorflow.contrib.slim as slim
import config as cfg
import pdb
class Lenet:
def __init__(self):
# 占位符数据
self.raw_input_image = tf.placeholder(tf.float32, [None, 784])
self.input_images = tf.reshape(self.raw_input_image, [-1, 28, 28, 1])
self.raw_input_label = tf.placeholder("float", [None, 10])
# tf.cast() 改变数据类型
self.input_labels = tf.cast(self.raw_input_label,tf.int32)
self.dropout = cfg.KEEP_PROB
with tf.variable_scope("Lenet") as scope:
self.train_digits = self.construct_net(True)
scope.reuse_variables()
self.pred_digits = self.construct_net(False)
#tf.argmax(vector, 1):返回的是vector中的最大值的索引号
self.prediction = tf.argmax(self.pred_digits, 1)
self.correct_prediction = tf.equal(tf.argmax(self.pred_digits, 1), tf.argmax(self.input_labels, 1))
self.train_accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, "float"))
# print('ddddd')
#通过交叉熵函数求得loss值;
self.loss = slim.losses.softmax_cross_entropy(self.train_digits, self.input_labels)
#初始化学习率
self.lr = cfg.LEARNING_RATE
#根据学习率反向传播优化参数
self.train_op = tf.train.AdamOptimizer(self.lr).minimize(self.loss)
def construct_net(self,is_trained = True):
with slim.arg_scope([slim.conv2d], padding='VALID',
weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
weights_regularizer=slim.l2_regularizer(0.0005)):
# 卷积默认经过relu;slim是对tf中卷积的简化;输入的图片大小为28*28;经过5*5的卷积核,因为是SAME,所以还是28*28;
# print(self.input_images.get_shape())
net = slim.conv2d(self.input_images, 6, [5, 5], 1, padding='SAME', scope='conv1')
# print(net.get_shape())
#max_pool的卷积核大小为2*2;步长为1;经过max 变成14*14
net = slim.max_pool2d(net, [2, 2], scope='pool2')
# print(net.get_shape())
#14*14经过卷积变成10*10
net = slim.conv2d(net, 16, [5, 5], 1, scope='conv3')
# print(net.get_shape())
#经过pool,变成5*5
net = slim.max_pool2d(net, [2, 2], scope='pool4')
# print(net.get_shape())
# 经过卷积变成1*1
net1 = slim.conv2d(net, 120, [5, 5], 1, scope='conv5')
# n1 = net1.get_shape()
# print(n1)
# 将120个1*1的撕扯成一个120维的长向量
net2 = slim.flatten(net1, scope='flat6')
# print(net2.get_shape())
#展开成84维
net3 = slim.fully_connected(net2, 84, scope='fc7')
# print(net3.get_shape())
net4 = slim.dropout(net3, self.dropout, is_training=is_trained, scope='dropout8')
# print(net4.get_shape())
digits = slim.fully_connected(net4, 10, scope='fc9')
# pdb.set_trace()
return digits