[tensorflow] 通過Class的形式實現網絡的創建、加深理解graph和session


一.理解graph和session

  對tensorflow中的graph和session進行更深入的了解,能夠幫助理解tensorflow的運行機制,使得可以在一個運行程序中調用不同的神經網絡。總而言之,是深入學習必須掌握的東西。

  • 在程序一開始,tensorflow會自動生成一個默認的graph。如果不顯示的指定graph,所有的操作(添加張量、節點)都會自動加入默認圖。
  • 可以通過g=tf.Graph()顯示獲得一個圖的變量。然后通過 with g.as_default():上下文管理器,在后文中進行網絡的搭建工作。當然也有將g直接顯示申明為默認圖的函數,我忘記了,以后看見了來添加。但是不推薦顯示申明為默認圖,因為考慮到以后有多張圖存在的情況下,顯示申明會讓邏輯處理起來很混亂,還是按照前一種方式規范操作來得好。
  • 一個圖可以有多個session,但是一個session只能執行一個指定圖里的操作。
import tensorflow as tf

tf.reset_default_graph()#復位初始圖
g=tf.Graph()#獲得圖的對象
with g.as_default():
    a=tf.Variable('a')
    sess=tf.Session()
    sess.run(tf.global_variables_initializer())
    print(sess.run(a))#這里正常輸出'a'
b=tf.Variable('b')
with sess.as_default():
    sess.run(tf.global_variables_initializer())
    print(sess.run(b))#這里報錯“ is not an element of this graph ”

    上述代碼中,第一個print正常執行,正常輸出張量a。但是定義張量b時,是定義在了全局默認的圖中,並非在g中。而session對應的圖是g,不是默認圖,所以出錯。

import tensorflow as tf

tf.reset_default_graph()#復位初始圖
g=tf.Graph()#獲得圖的對象
with g.as_default():
    a=tf.Variable('a')
    sess=tf.Session()
    sess.run(tf.global_variables_initializer())
    print(sess.run(a))
b=tf.Variable('b')
with tf.Session() as sess2:
    sess2.run(tf.global_variables_initializer())
    print(sess2.run(b))

    代碼修改過后,則能正常執行第二個print,輸出張量b。因為以當前的默認graph重新申明了session來執行該操作。


二.通過class方式實現一個卷積網絡

   此種方式生卷積網絡的類。目標是可以新建多個類的實例進行訓練等操作,而不相互影響。此時就應該注重管理graph和session。

  實現代碼如下:

# -*- coding: utf-8 -*-
"""
Created on Fri Feb 16 12:31:04 2018

@author: FC
"""
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
class ConvNet():
    def __init__(self,layers=['c','p','c','p'],datain=[784],ind=[28,28,1],outd=[10]):
        self.layers=layers  #每一層的屬性
        self.ind=ind        #圖片的屬性
        self.outd=outd      #輸入的標記樣本數組維度
        self.datain=datain  #輸入的數據樣本數組維度
        self.convkernelsize=3#卷積核大小
        self.midchannels=24 #中間層每層的通道數
        self.net={}         #層的集合
        self.__NetInit()
    def __weight_variable(self,shape,name='w'):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial,name=name)
    def __bias_variable(self,shape,name='b'):
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial,name=name)
    
    def __AddInlayer(self,x,name='In-Layer'):
        #輸入處理層
        with tf.name_scope(name):
            x_reshape=tf.reshape(x, [-1]+self.ind)
            w=self.__weight_variable([self.convkernelsize,self.convkernelsize
                                      ,self.ind[2],self.midchannels])
            b=self.__bias_variable([self.midchannels])
            conv=tf.nn.conv2d(x_reshape, w, strides=[1, 1, 1, 1], padding='SAME')
            net=tf.nn.relu(conv+b,name=name)
        return net
    
    def __AddConvLayer(self,x,layertype='c',name='Mid_ConvLayer'):
        if ((layertype!='c') and (layertype!='p')):
            #只能是池化或者卷積層
            return
        if (layertype=='p'):
            with tf.name_scope(name+layertype):
                net = tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                            strides=[1, 2, 2, 1], padding='SAME')
            return net
        if (layertype=='c'):
            with tf.name_scope(name+layertype):
                w=self.__weight_variable([self.convkernelsize,self.convkernelsize
                                      ,self.midchannels,self.midchannels])
                b=self.__bias_variable([self.midchannels])
                conv=tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
                net=tf.nn.relu(conv+b,name=name+layertype)
            return net
        
    def __AddFcLayer(self,x,name='Out-FcLayer'):
        #全連接輸出層
        inshape=x.shape
        width=inshape[1]*inshape[2]*inshape[3]
        width=tf.cast(width,tf.int32)
#        print(type(width))
        with tf.name_scope(name):
            w1=self.__weight_variable([width,1024],name='w1')
            b1=self.__bias_variable([1024],name='b1')
            x_flat=tf.reshape(x,[-1,width],name='x_flat')             
            fc1=tf.nn.relu(tf.matmul(x_flat,w1)+b1,name='fc1')
            
            w2=self.__weight_variable([1024]+self.outd,name='w2')
            b2=self.__bias_variable(self.outd,name='b2')
            net=tf.nn.softmax(tf.matmul(fc1,w2)+b2,name=name)
        return net
    def __AddTrainstep(self,y,y_,name='Training'):
        with tf.name_scope(name):
            cross_entropy = -tf.reduce_sum(y_*tf.log(y))
            train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
            correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
            accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
        return train_step,accuracy
    def __NetInit(self):
        #由實際輸入決定
        tf.reset_default_graph()#復位初始圖
        self.Graph=tf.Graph()
        #如果在一個進程中創建了多個Graph,則需要創建不同的Session來加載每個Graph
        #而每個Graph則可以加載在多個Session中進行計算。
        #上下文管理器
        with self.Graph.as_default():
            #1. 初始化網絡結構
            self.x=tf.placeholder("float",[None]+self.datain,name='x-input') 
            self.y_=tf.placeholder("float", [None]+self.outd,name='y-input')
            
            #添加網絡
            self.net[0]=self.__AddInlayer(self.x)
            for i in range(len(self.layers)):
                self.net[i+1]=self.__AddConvLayer(self.net[i],layertype=self.layers[i])
            self.outnet=self.__AddFcLayer(self.net[len(self.layers)])
            self.trainstep,self.accuracy=self.__AddTrainstep(self.outnet,self.y_)
            self.sess=tf.Session()
            #2. 初始化圖中變量
            self.sess.run(tf.global_variables_initializer())
    def Train(self,datax,datay):
        self.sess.run(self.trainstep,feed_dict={self.x:datax, self.y_:datay})
#        for i in range(1000):
#            batch = mnist.train.next_batch(64)
#            if i%1000 == 0:
#                train_accuracy = self.sess.run(self.accuracy,feed_dict={self.x:batch[0], self.y_: batch[1]})
#                print ("step %d, training accuracy %g"%(i, train_accuracy))
#            self.sess.run(self.trainstep,feed_dict={self.x: batch[0], self.y_: batch[1]})
#
#        print ("test accuracy %g"%self.sess.run(self.accuracy,feed_dict={
#            self.x: mnist.test.images, self.y_: mnist.test.labels}))
    def GetAccuracy(self,datax,datay):
        return self.sess.run(self.accuracy,feed_dict={self.x: datax, self.y_: datay})
    def SaveGraph(self):
        #調用此函數,可通過tensorboard查看網絡形狀
        with self.Graph.as_default():
            merge = tf.summary.merge_all()
            writer = tf.summary.FileWriter('./log',self.sess.graph)
    def Close(self):
        self.sess.close()
if __name__=='__main__':
    net1=ConvNet(layers=['c','c','p','c','c','p'])
#    net1.SaveGraph()
    for i in range(1000):
        batch = mnist.train.next_batch(64)
        net1.Train(batch[0],batch[1])
    net2=ConvNet(layers=['c','c','p','c','c','p','c'])
    print("net2 accuracy: %g%%"%(100*net2.GetAccuracy(mnist.test.images,mnist.test.labels)))
    print("net1 accuracy: %g%%"%(100*net1.GetAccuracy(mnist.test.images,mnist.test.labels)))  
  1. 上述代碼中,定義了一個ConvNet類。
  2. 訓練的樣本集合是mnist。
  3. 在使用時,創建了兩個實例:net1和net2。
  4. 對net1輸入了樣本訓練。
  5. 同時輸入出net1和net2的預測准確率,如下所示:
net2 accuracy: 9.81%
net1 accuracy: 97.08%

  證明兩個實例是相互獨立的,對一個實例的訓練並沒有影響到另一個。


 


后續:

  后續的實驗應該是兩個實例同時進行訓練,保存准確率較高的實例的參數,作為下一次訓練共同的初始化數據。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM