經過這兩天的閱讀,算是稍稍掌握了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