TensorFlow入門

一、Model類

(1)初始化方法

1.可擴展參數(shù):kwargs字典里獲取,可限制key的取值

  • name: model變量域scope名稱,獲取不到采用self.__class__.__name__.lower()取類的名字
  • logging: 是否開啟TensorBoard直方圖儀表板嫂拴,獲取不到為False
  1. 其他參數(shù)

vars: name scope下的變量(字典)
placeholders: 外部變量占位,一般是特征和標簽(字典)
layers: 神經(jīng)網(wǎng)絡的layer(列表)
activations: 每個layer的輸出結果(列表)
inputs: 輸入
output: 輸出
loss: 損失
accuracy: 準確率
optimizer:優(yōu)化器
opt_op:最優(yōu)化的op操作

def __init__(self, **kwargs):
    allowed_kwargs = {'name', 'logging'}
    for kwarg in kwargs.keys():
        assert kwarg in allowed_kwargs, 'Invalid keyword argument: ' + kwarg
    name = kwargs.get('name')
    if not name:
        name = self.__class__.__name__.lower()
    self.name = name

    logging = kwargs.get('logging', False)
    self.logging = logging

    self.vars = {}
    self.placeholders = {}

    self.layers = []
    self.activations = []

    self.inputs = None
    self.outputs = None

    self.loss = 0
    self.accuracy = 0
    self.optimizer = None
    self.opt_op = None_build 

(2)build方法

_build 是私有build方法贮喧,在繼承Model的具體實現(xiàn)時對layers進行append操作筒狠,下面介紹build方法:

調用_build,所有變量設置共享空間(self.name
構建模型序列:給輸入箱沦,通過layer()返回輸出辩恼,又將這個輸出再次作為輸入到下一個layer()中,循環(huán)這一過程谓形;最終灶伊,取最后一層layer的結果作為output
保存name scope下的變量到self.vars
模型效果度量:_loss方法,_accuracy方法

def _build(self):
    raise NotImplementedError

def build(self):
    """ Wrapper for _build() """
    with tf.variable_scope(self.name):
        self._build()

    # Build sequential layer model
    self.activations.append(self.inputs)
    for layer in self.layers:
        hidden = layer(self.activations[-1])
        self.activations.append(hidden)
    self.outputs = self.activations[-1]

    # Store model variables for easy access
    variables = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=self.name)
    self.vars = {var.name: var for var in variables}

    # Build metrics
    self._loss()
    self._accuracy()

    self.opt_op = self.optimizer.minimize(self.loss)

(3)保存與加載方法

def save(self, sess=None):
        if not sess:
            raise AttributeError("TensorFlow session not provided.")
        saver = tf.train.Saver(self.vars)
        save_path = saver.save(sess, "tmp/%s.ckpt" % self.name)
        print("Model saved in file: %s" % save_path)

def load(self, sess=None):
        if not sess:
            raise AttributeError("TensorFlow session not provided.")
        saver = tf.train.Saver(self.vars)
        save_path = "tmp/%s.ckpt" % self.name
        saver.restore(sess, save_path)
        print("Model restored from file: %s" % save_path)    

二寒跳、數(shù)據(jù)讀取

常用的結構化數(shù)據(jù)文件格式有csv聘萨、txt 、libsvm童太,本篇文章主要說明結構化數(shù)據(jù)(csv/txt)如何在TF框架進行高效米辐、靈活的讀取,避免一些不合理的方式书释,邁出算法開發(fā)標準化翘贮、工程化的第一步。

使用pandas讀取數(shù)據(jù)

def load_data_with_pandas(filename):
    # load data as DataFrame to the memory
    data = pd.read_csv(filename, sep=',', header=0)
    features_df = data.iloc[:, :-1]
    label_df = data.iloc[:, -1]
    features = features_df.astype(np.float32).values
    labels = label_df.astype(np.int64).values
    return features, labels

最常見的讀取數(shù)據(jù)的方式是利用pandas包將csv征冷、txt讀取為DataFrame择膝,一次全部放入內存。這是一種非常低效的方式检激,應該盡量避免這種讀取方法肴捉。其他第三方封裝python讀取方式的包(TFLearn等)也不建議使用腹侣,推薦使用TF框架的OP操作進行數(shù)據(jù)讀取。

TensorFlow的數(shù)據(jù)讀取機制

一齿穗、tensorflow讀取機制圖解

首先需要思考的一個問題是傲隶,什么是數(shù)據(jù)讀取窃页?以圖像數(shù)據(jù)為例跺株,讀取數(shù)據(jù)的過程可以用下圖來表示:


假設我們的硬盤中有一個圖片數(shù)據(jù)集0001.jpg,0002.jpg脖卖,0003.jpg……我們只需要把它們讀取到內存中乒省,然后提供給GPU或是CPU進行計算就可以了。這聽起來很容易畦木,但事實遠沒有那么簡單袖扛。事實上,我們必須要把數(shù)據(jù)先讀入后才能進行計算十籍,假設讀入用時0.1s蛆封,計算用時0.9s,那么就意味著每過1s勾栗,GPU都會有0.1s無事可做惨篱,這就大大降低了運算的效率。

如何解決這個問題围俘?方法就是將讀入數(shù)據(jù)和計算分別放在兩個線程中砸讳,將數(shù)據(jù)讀入內存的一個隊列,如下圖所示:


讀取線程源源不斷地將文件系統(tǒng)中的圖片讀入到一個內存的隊列中界牡,而負責計算的是另一個線程绣夺,計算需要數(shù)據(jù)時,直接從內存隊列中取就可以了欢揖。這樣就可以解決GPU因為IO而空閑的問題!

而在tensorflow中奋蔚,為了方便管理她混,在內存隊列前又添加了一層所謂的“文件名隊列”

為什么要添加這一層文件名隊列泊碑?我們首先得了解機器學習中的一個概念:epoch坤按。對于一個數(shù)據(jù)集來講,運行一個epoch就是將這個數(shù)據(jù)集中的圖片全部計算一遍馒过。如一個數(shù)據(jù)集中有三張圖片A.jpg臭脓、B.jpg、C.jpg腹忽,那么跑一個epoch就是指對A来累、B砚作、C三張圖片都計算了一遍。兩個epoch就是指先對A嘹锁、B葫录、C各計算一遍,然后再全部計算一遍领猾,也就是說每張圖片都計算了兩遍米同。

tensorflow使用文件名隊列+內存隊列雙隊列的形式讀入文件,可以很好地管理epoch摔竿。下面我們用圖片的形式來說明這個機制的運行方式面粮。如下圖,還是以數(shù)據(jù)集A.jpg, B.jpg, C.jpg為例继低,假定我們要跑一個epoch熬苍,那么我們就在文件名隊列中把A、B郁季、C各放入一次冷溃,并在之后標注隊列結束。

程序運行后梦裂,內存隊列首先讀入A(此時A從文件名隊列中出隊):

再依次讀入B和C:


此時似枕,如果再嘗試讀入,系統(tǒng)由于檢測到了“結束”年柠,就會自動拋出一個異常(OutOfRange)凿歼。外部捕捉到這個異常后就可以結束程序了。這就是tensorflow中讀取數(shù)據(jù)的基本機制冗恨。如果我們要跑2個epoch而不是1個epoch答憔,那只要在文件名隊列中將A、B掀抹、C依次放入兩次再標記結束就可以了虐拓。

二、tensorflow讀取數(shù)據(jù)機制的對應函數(shù)

如何在tensorflow中創(chuàng)建上述的兩個隊列呢傲武?

對于文件名隊列蓉驹,我們使用tf.train.string_input_producer函數(shù)。這個函數(shù)需要傳入一個文件名list揪利,系統(tǒng)會自動將它轉為一個文件名隊列态兴。

此外tf.train.string_input_producer還有兩個重要的參數(shù),一個是num_epochs疟位,它就是我們上文中提到的epoch數(shù)瞻润。另外一個就是shuffle,shuffle是指在一個epoch內文件的順序是否被打亂。若設置shuffle=False绍撞,如下圖正勒,每個epoch內,數(shù)據(jù)還是按照A楚午、B昭齐、C的順序進入文件名隊列,這個順序不會改變:


如果設置shuffle=True矾柜,那么在一個epoch內阱驾,數(shù)據(jù)的前后順序就會被打亂,如下圖所示:

在tensorflow中怪蔑,內存隊列不需要我們自己建立汽久,我們只需要使用reader對象從文件名隊列中讀取數(shù)據(jù)就可以了茅诱,具體實現(xiàn)可以參考下面的實戰(zhàn)代碼。

除了tf.train.string_input_producer外,我們還要額外介紹一個函數(shù):tf.train.start_queue_runners吼鳞。初學者會經(jīng)常在代碼中看到這個函數(shù)烂翰,但往往很難理解它的用處参滴,在這里拉宗,有了上面的鋪墊后,我們就可以解釋這個函數(shù)的作用了渡冻。

在我們使用tf.train.string_input_producer創(chuàng)建文件名隊列后戚扳,整個系統(tǒng)其實還是處于“停滯狀態(tài)”的,也就是說族吻,我們文件名并沒有真正被加入到隊列中(如下圖所示)帽借。此時如果我們開始計算,因為內存隊列中什么也沒有超歌,計算單元就會一直等待砍艾,導致整個系統(tǒng)被阻塞。

而使用tf.train.start_queue_runners之后巍举,才會啟動填充隊列的線程脆荷,這時系統(tǒng)就不再“停滯”。此后計算單元就可以拿到數(shù)據(jù)并進行計算懊悯,整個程序也就跑起來了简烘,這就是函數(shù)tf.train.start_queue_runners的用處。

image

三定枷、實戰(zhàn)代碼

我們用一個具體的例子感受tensorflow中的數(shù)據(jù)讀取。如圖届氢,假設我們在當前文件夾中已經(jīng)有A.jpg欠窒、B.jpg、C.jpg三張圖片,我們希望讀取這三張圖片5個epoch并且把讀取的結果重新存到read文件夾中岖妄。


對應的代碼如下:

# 導入tensorflow
import tensorflow as tf 

# 新建一個Session
with tf.Session() as sess:
   # 我們要讀三幅圖片A.jpg, B.jpg, C.jpg
  filename = ['A.jpg', 'B.jpg', 'C.jpg']
   # string_input_producer會產(chǎn)生一個文件名隊列
   filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)
   # reader從文件名隊列中讀數(shù)據(jù)型将。對應的方法是reader.read
   reader = tf.WholeFileReader()
   key, value = reader.read(filename_queue)
   # tf.train.string_input_producer定義了一個epoch變量,要對它進行初始化
   tf.local_variables_initializer().run()
   # 使用start_queue_runners之后荐虐,才會開始填充隊列
   threads = tf.train.start_queue_runners(sess=sess)
   i = 0
   while True:
       i += 1
       # 獲取圖片數(shù)據(jù)并保存
       image_data = sess.run(value)
       with open('read/test_%d.jpg' % i, 'wb') as f:
           f.write(image_data)

我們這里使用filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)建立了一個會跑5個epoch的文件名隊列七兜。并使用reader讀取,reader每次讀取一張圖片并保存福扬。
運行代碼后腕铸,我們得到就可以看到read文件夾中的圖片,正好是按順序的5個epoch:


如果我們設置filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)中的shuffle=True铛碑,那么在每個epoch內圖像就會被打亂狠裹,如圖所示:

這里只是用三張圖片舉例,實際應用中一個數(shù)據(jù)集肯定不止3張圖片汽烦,不過涉及到的原理都是共通的涛菠。

高效的 TensorFlow 讀取方式是將數(shù)據(jù)讀取轉換成 OP,通過 session run的方式拉去數(shù)據(jù)撇吞。讀取線程源源不斷地將文件系統(tǒng)中的文件讀入到一個內存的隊列中俗冻,而負責計算的是另一個線程,計算需要數(shù)據(jù)時牍颈,直接從內存隊列中取就可以了迄薄,這樣就可以解決GPU因為IO而空閑的問題。同時颂砸,不會一次性的preload到內存噪奄,再大的數(shù)據(jù)量也不會超出內存的限制。

三人乓、TensorFlow API

1.TensorFlow 相關函數(shù)理解


  • tf.nn.conv2d ————卷積
conv2d(
    input,
    filter,
    strides,
    padding,
    use_cudnn_on_gpu=True,
    data_format='NHWC',
    name=None
)

#Example
import tensorflow as tf
a = tf.constant([1,1,1,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,1,0,0],dtype=tf.float32,shape=[1,5,5,1])
b = tf.constant([1,0,1,0,1,0,1,0,1],dtype=tf.float32,shape=[3,3,1,1])
c = tf.nn.conv2d(a,b,strides=[1, 2, 2, 1],padding='VALID')
d = tf.nn.conv2d(a,b,strides=[1, 2, 2, 1],padding='SAME')
with tf.Session() as sess:
    print ("c shape:")
    print (c.shape)
    print ("c value:")
    print (sess.run(c))
    print ("d shape:")
    print (d.shape)
    print ("d value:")
    print (sess.run(d))
參數(shù)名 必選 類型 說明
input tensor 是一個 4 維的 tensor勤篮,即 [ batch, in_height, in_width, in_channels ](若 input 是圖像,[ 訓練時一個 batch 的圖片數(shù)量, 圖片高度, 圖片寬度, 圖像通道數(shù) ])
filter tensor 是一個 4 維的 tensor色罚,即 [ filter_height, filter_width, in_channels, out_channels ](若 input 是圖像碰缔,[ 卷積核的高度,卷積核的寬度戳护,圖像通道數(shù)金抡,卷積核個數(shù) ]),filter 的 in_channels 必須和 input 的 in_channels 相等
strides 列表 長度為 4 的 list,卷積時候在 input 上每一維的步長腌且,一般 strides[0] = strides[3] = 1
padding string 只能為 " VALID "梗肝," SAME " 中之一,這個值決定了不同的卷積方式铺董。VALID 丟棄方式巫击;SAME:補全方式
use_cudnn_on_gpu bool 是否使用 cudnn 加速,默認為 true
data_format string 只能是 " NHWC ", " NCHW ",默認 " NHWC "
name string 運算名稱
image

  • tf.nn.relu ————relu激活函數(shù)
relu(
    features,
    name=None
)

#Example
import tensorflow as tf

a = tf.constant([1,-2,0,4,-5,6])
b = tf.nn.relu(a)
with tf.Session() as sess:
    print (sess.run(b))
參數(shù)名 必選 類型 說明
features tensor 是以下類型float32, float64, int32, int64, uint8, int16, int8, uint16, half
name string 運算名稱

  • tf.nn.max_pool————池化
max_pool(
    value,
    ksize,
    strides,
    padding,
    data_format='NHWC',
    name=None
)


#Example
import tensorflow as tf

a = tf.constant([1,3,2,1,2,9,1,1,1,3,2,3,5,6,1,2],dtype=tf.float32,shape=[1,4,4,1])
b = tf.nn.max_pool(a,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='VALID')
c = tf.nn.max_pool(a,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME')
with tf.Session() as sess:
    print ("b shape:")
    print (b.shape)
    print ("b value:")
    print (sess.run(b))
    print ("c shape:")
    print (c.shape)
    print ("c value:")
    print (sess.run(c))
參數(shù)名 必選 類型 說明
value tensor 4 維的張量坝锰,即 [ batch, height, width, channels ]粹懒,數(shù)據(jù)類型為 tf.float32
ksize 列表 池化窗口的大小,長度為 4 的 list顷级,一般是 [1, height, width, 1]凫乖,因為不在 batch 和 channels 上做池化,所以第一個和最后一個維度為 1
strides 列表 池化窗口在每一個維度上的步長弓颈,一般 strides[0] = strides[3] = 1
padding string 只能為 " VALID "帽芽," SAME " 中之一,這個值決定了不同的池化方式恨豁。VALID 丟棄方式嚣镜;SAME:補全方式
data_format string 只能是 " NHWC ", " NCHW ",默認" NHWC "
name string 運算名稱

  • tf.nn.dropout————防止或減輕過擬合
dropout(
    x,
    keep_prob,
    noise_shape=None,
    seed=None,
    name=None
)

#Example
import tensorflow as tf

a = tf.constant([1,2,3,4,5,6],shape=[2,3],dtype=tf.float32)
b = tf.placeholder(tf.float32)
c = tf.nn.dropout(a,b,[2,1],1)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print (sess.run(c,feed_dict={b:0.75}))
參數(shù)名 必選 類型 說明
x tensor 輸出元素是 x 中的元素以 keep_prob 概率除以 keep_prob橘蜜,否則為 0
keep_prob scalar Tensor dropout 的概率菊匿,一般是占位符
noise_shape tensor 默認情況下,每個元素是否 dropout 是相互獨立计福。如果指定 noise_shape跌捆,若 noise_shape[i] == shape(x)[i],該維度的元素是否 dropout 是相互獨立象颖,若 noise_shape[i] != shape(x)[i] 該維度元素是否 dropout 不相互獨立佩厚,要么一起 dropout 要么一起保留
seed 數(shù)值 如果指定該值,每次 dropout 結果相同
name string 運算名稱

  • tf.nn.sigmoid_cross_entropy_with_logits————先對 logits 通過 sigmoid 計算说订,再計算交叉熵
sigmoid_cross_entropy_with_logits(
    _sentinel=None,
    labels=None,
    logits=None,
    name=None
)

#Example
import tensorflow as tf
x = tf.constant([1,2,3,4,5,6,7],dtype=tf.float64)
y = tf.constant([1,1,1,0,0,1,0],dtype=tf.float64)
loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = y,logits = x)
with tf.Session() as sess:
    print (sess.run(loss))
參數(shù)名 必選 類型 說明
_sentinel None 沒有使用的參數(shù)
labels Tensor type, shape 與 logits相同
logits Tensor type 是 float32 或者 float64
name string 運算名稱

  • tf.truncated_normal————產(chǎn)生截斷正態(tài)分布隨機數(shù)抄瓦,取值范圍為 [ mean - 2 * stddev, mean + 2 * stddev ]
truncated_normal(
    shape,
    mean=0.0,
    stddev=1.0,
    dtype=tf.float32,
    seed=None,
    name=None
)

#Example
import tensorflow as tf
initial = tf.truncated_normal(shape=[3,3], mean=0, stddev=1)
print(tf.Session().run(initial))
參數(shù)名 必選 類型 說明
shape 1 維整形張量或 array 輸出張量的維度
mean 0 維張量或數(shù)值 均值
stddev 0 維張量或數(shù)值 標準差
dtype dtype 輸出類型
seed 數(shù)值 隨機種子,若 seed 賦值陶冷,每次產(chǎn)生相同隨機數(shù)
name string 運算名稱

  • tf.constant————根據(jù) value 的值生成一個 shape 維度的常量張量
constant(
    value,
    dtype=None,
    shape=None,
    name='Const',
    verify_shape=False
)
參數(shù)名 必選 類型 說明
value 常量數(shù)值或者 list 輸出張量的值
dtype dtype 輸出張量元素類型
shape 1 維整形張量或 array 輸出張量的維度
name string 張量名稱
verify_shape Boolean 檢測 shape 是否和 value 的 shape 一致钙姊,若為 Fasle,不一致時埂伦,會用最后一個元素將 shape 補全

  • tf.placeholder————是一種占位符煞额,在執(zhí)行時候需要為其提供數(shù)據(jù)
placeholder(
    dtype,
    shape=None,
    name=None
)

#Example
import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32,[None,3])
y = tf.matmul(x,x)
with tf.Session() as sess:
    rand_array = np.random.rand(3,3)
    print(sess.run(y,feed_dict={x:rand_array}))
參數(shù)名 必選 類型 說明
dtype dtype 占位符數(shù)據(jù)類型
shape 1 維整形張量或 array 占位符維度
name string 占位符名稱

  • tf.nn.bias_add————將偏差項 bias 加到 value 上面,可以看做是 tf.add 的一個特例沾谜,其中 bias 必須是一維的膊毁,并且維度和 value 的最后一維相同,數(shù)據(jù)類型必須和 value 相同基跑。
bias_add(
    value,
    bias,
    data_format=None,
    name=None
)

#Example
import tensorflow as tf
import numpy as np

a = tf.constant([[1.0, 2.0],[1.0, 2.0],[1.0, 2.0]])
b = tf.constant([2.0,1.0])
c = tf.constant([1.0])
sess = tf.Session()
print (sess.run(tf.nn.bias_add(a, b)))
#print (sess.run(tf.nn.bias_add(a,c))) error
print ("##################################")
print (sess.run(tf.add(a, b)))
print ("##################################")
print (sess.run(tf.add(a, c)))
參數(shù)名 必選 類型 說明
value 張量 數(shù)據(jù)類型為 float, double, int64, int32, uint8, int16, int8, complex64, or complex128
bias 一維張量 維度必須和 value 最后一維維度相等
data_format string 數(shù)據(jù)格式婚温,支持 ' NHWC ' 和 ' NCHW '
name string 運算名稱

  • tf.reduce_mean————計算張量 input_tensor 平均值
reduce_mean(
    input_tensor,
    axis=None,
    keep_dims=False,
    name=None,
    reduction_indices=None
)

#Example
import tensorflow as tf
import numpy as np

initial = [[1.,1.],[2.,2.]]
x = tf.Variable(initial,dtype=tf.float32)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init_op)
    print(sess.run(tf.reduce_mean(x)))
    print(sess.run(tf.reduce_mean(x,0))) #Column
    print(sess.run(tf.reduce_mean(x,1))) #row
參數(shù)名 必選 類型 說明
input_tensor 張量 輸入待求平均值的張量
axis None、0媳否、1 None:全局求平均值缭召;0:求每一列平均值栈顷;1:求每一行平均值
keep_dims Boolean 保留原來的維度(例如不會從二維矩陣降為一維向量)
name string 運算名稱
reduction_indices None 和 axis 等價,被棄用

  • tf.squared_difference————計算張量 x嵌巷、y 對應元素差平方
squared_difference(
    x,
    y,
    name=None
)
參數(shù)名 必選 類型 說明
x 張量 是 half, float32, float64, int32, int64, complex64, complex128 其中一種類型
y 張量 是 half, float32, float64, int32, int64, complex64, complex128 其中一種類型
name string 運算名稱

  • tf.square————計算張量對應元素平方
square(
    x,
    name=None
    )
參數(shù)名 必選 類型 說明
x 張量 是half, float32, float64, int32, int64, complex64, complex128 其中一種類型
name string 運算名稱

2.Tensorflow相關類理解

  • tf.Variable————維護圖在執(zhí)行過程中的狀態(tài)信息,例如神經(jīng)網(wǎng)絡權重值的變化
__init__(
    initial_value=None,
    trainable=True,
    collections=None,
    validate_shape=True,
    caching_device=None,
    name=None,
    variable_def=None,
    dtype=None,
    expected_shape=None,
    import_scope=None
)
參數(shù)名 類型 說明
initial_value 張量 Variable 類的初始值室抽,這個變量必須指定 shape 信息搪哪,否則后面 validate_shape 需設為 False
trainable Boolean 是否把變量添加到 collection GraphKeys.TRAINABLE_VARIABLES 中(collection 是一種全局存儲,不受變量名生存空間影響坪圾,一處保存晓折,到處可取)
collections Graph collections 全局存儲兽泄,默認是 GraphKeys.GLOBAL_VARIABLES
validate_shape Boolean 是否允許被未知維度的 initial_value 初始化
caching_device string 指明哪個 device 用來緩存變量
name string 變量名
dtype dtype 如果被設置漓概,初始化的值就會按照這個類型初始化
expected_shape TensorShape 要是設置了,那么初始的值會是這種維度


四病梢、LeNet網(wǎng)絡的構建

#模型訓練
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt


#打開數(shù)據(jù)集
path='C:/Users/86769/.keras/datasets/mnist.npz'
f = np.load(path)
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
f.close()

#格式化
x_train = np.pad(x_train,((0,0),(2,2),(2,2)),'constant',constant_values=0)
x_train = x_train.astype('float32')
x_train /=255
x_train=x_train.reshape(x_train.shape[0],32,32,1)

x_test = np.pad(x_test,((0,0),(2,2),(2,2)),'constant',constant_values=0)
x_test = x_test.astype('float32')
x_test /=255
x_test=x_test.reshape(x_test.shape[0],32,32,1)

#創(chuàng)建模型
model=tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(filters=6,kernel_size=(5,5),padding='valid',activation=tf.nn.relu,input_shape=(32,32,1)),
    tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
    tf.keras.layers.Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation=tf.nn.relu),
    tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=120,activation=tf.nn.relu),
    # tf.keras.layers.Conv2D(filters=120,kernel_size=(5,5),strides=(1,1),activation='tanh',padding='valid'),
    # tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=84,activation=tf.nn.relu),
    tf.keras.layers.Dense(units=10,activation=tf.nn.softmax)
])

model.summary()


#超參數(shù)配置
num_epochs=10          #訓練輪數(shù)
batch_size=64          #批大小
learning_rate=0.001    #學習率

#優(yōu)化器
adam_optimizer=tf.keras.optimizers.Adam(learning_rate)

model.compile(optimizer=adam_optimizer,
              loss=tf.keras.losses.sparse_categorical_crossentropy,metrics=['accuracy'])

import datetime
start_time=datetime.datetime.now()

model.fit(x=x_train,
          y=y_train,
          batch_size=batch_size,
          epochs=num_epochs)
end_time=datetime.datetime.now()
time_cost=end_time-start_time
print("time_cost = ",time_cost) #CPU time cost: 5min, GPU time cost: less than 1min

#模型保存
model.save('E:/ML/LeNet_Model.hui')

#評估指標
print(model.evaluate(x_test, y_test))  #loss value & metrics value

#預測
image_index=4444
print(x_test[image_index].shape)
plt.imshow(x_test[image_index].reshape(32,32),cmap='Greys')

pred = model.predict((x_test[image_index].reshape(1,32,32,1)))
print(pred.argmax())

神經(jīng)網(wǎng)絡中的幾個重要概念

梯度下降:梯度下降是一個在機器學習中用于尋找較佳結果(曲線的最小值)的迭代優(yōu)化算法胃珍。梯度的含義是斜率或者斜坡的傾斜度。下降的含義是代價函數(shù)的下降蜓陌。
?算法是迭代的觅彰,意思是需要多次使用算法獲取結果,以得到最優(yōu)化結果钮热。梯度下降的迭代性質能使欠擬合演變成獲得對數(shù)據(jù)的較佳擬合填抬。

?梯度下降中有一個稱為學習率的參量。如上圖左所示隧期,剛開始學習率較大飒责,因此下降步長更大。隨著點的下降仆潮,學習率變得越來越小宏蛉,從而下降步長也變小。同時鸵闪,代價函數(shù)也在減小檐晕,或者說代價在減小,有時候也稱為損失函數(shù)或者損失蚌讼,兩者是一樣的辟灰。(損失/代價的減小是一個概念)。

?只有在數(shù)據(jù)很龐大的時候(在機器學習中篡石,數(shù)據(jù)一般情況下都會很大)芥喇,我們才需要使用epochs,batch size凰萨,iteration這些術語继控,在這種情況下械馆,一次性將數(shù)據(jù)輸入計算機是不可能的。因此武通,為了解決這個問題霹崎,我們需要把數(shù)據(jù)分成小塊,一塊一塊的傳遞給計算機冶忱,在每一步的末端更新神經(jīng)網(wǎng)絡的權重尾菇,擬合給定的數(shù)據(jù)。

(1)batchsize:批大小囚枪。在深度學習中派诬,一般采用SGD訓練,即每次訓練在訓練集中取batchsize個樣本訓練链沼;
(2)iteration:1個iteration等于使用batchsize個樣本訓練一次默赂;
(3)epoch:1個epoch等于使用訓練集中的全部樣本訓練一次;

  • batchsize:批大欣ㄉ住(批尺寸)
    批大小將決定我們一次訓練的樣本數(shù)目缆八。
    batch_size將影響到模型的優(yōu)化程度和速度。

batchsize的正確選擇是為了在內存效率和內存容量之間尋找最佳平衡朝刊。
Batch_Size的取值:

BatchSize

全批次(藍色)
如果數(shù)據(jù)集比較小耀里,我們就采用全數(shù)據(jù)集。全數(shù)據(jù)集確定的方向能夠更好的代表樣本總體拾氓,從而更準確的朝向極值所在的方向冯挎。
注:對于大的數(shù)據(jù)集,我們不能使用全批次咙鞍,因為會得到更差的結果房官。

迷你批次(綠色)
選擇一個適中的Batch_Size值。就是說我們選定一個batch的大小后续滋,將會以batch的大小將數(shù)據(jù)輸入深度學習的網(wǎng)絡中翰守,然后計算這個batch的所有樣本的平均損失,即代價函數(shù)是所有樣本的平均疲酌。

隨機(Batch_Size等于1的情況)(紅色)
每次修正方向以各自樣本的梯度方向修正蜡峰,橫沖直撞各自為政,難以達到收斂朗恳。

適當?shù)脑黾覤atch_Size的優(yōu)點:

  • 1.通過并行化提高內存利用率湿颅。
  • 2.單次epoch的迭代次數(shù)減少,提高運行速度粥诫。(單次epoch=(全部訓練樣本/batchsize)/iteration=1)
  • 3.適當?shù)脑黾覤atch_Size,梯度下降方向準確度增加油航,訓練震動的幅度減小。(看上圖便可知曉)
經(jīng)驗總結:

相對于正常數(shù)據(jù)集怀浆,如果Batch_Size過小谊囚,訓練數(shù)據(jù)就會非常難收斂怕享,從而導致underfitting。
增大Batch_Size,相對處理速度加快,所需內存容量增加(epoch的次數(shù)需要增加以達到最好的結果)
這里我們發(fā)現(xiàn)上面兩個矛盾的問題镰踏,因為當epoch增加以后同樣也會導致耗時增加從而速度下降函筋。因此我們需要尋找最好的Batch_Size。

iteration:迭代
迭代是重復反饋的動作奠伪,神經(jīng)網(wǎng)絡中我們希望通過迭代進行多次的訓練以達到所需的目標或結果驻呐。
每一次迭代得到的結果都會被作為下一次迭代的初始值。
一個迭代=一個正向通過+一個反向通過

Epoch
當一個完整的數(shù)據(jù)集通過了神經(jīng)網(wǎng)絡一次并且返回了一次芳来,這個過程稱為一次epoch。然而猜拾,當一個epoch對于計算機而言太龐大的時候即舌,就需要把它分成多個小塊。
為什么要使用多于一個epoch?
在神經(jīng)網(wǎng)絡中傳遞完整的數(shù)據(jù)集一次是不夠的挎袜,而且我們需要將完整的數(shù)據(jù)集在同樣的神經(jīng)網(wǎng)絡中傳遞多次顽聂。但請記住,我們使用的是有限的數(shù)據(jù)集盯仪,并且我們使用一個迭代過程即梯度下降來優(yōu)化學習過程紊搪。如下圖所示。因此僅僅更新一次或者說使用一個epoch是不夠的全景。

Epoch Influence

隨著epoch數(shù)量增加耀石,神經(jīng)網(wǎng)絡中的權重的更新次數(shù)也在增加,曲線從欠擬合變得過擬合爸黄。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末滞伟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子炕贵,更是在濱河造成了極大的恐慌梆奈,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件称开,死亡現(xiàn)場離奇詭異亩钟,居然都是意外死亡,警方通過查閱死者的電腦和手機鳖轰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門清酥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脆霎,你說我怎么就攤上這事总处。” “怎么了睛蛛?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵鹦马,是天一觀的道長胧谈。 經(jīng)常有香客問我,道長荸频,這世上最難降的妖魔是什么菱肖? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮旭从,結果婚禮上稳强,老公的妹妹穿的比我還像新娘。我一直安慰自己和悦,他們只是感情好退疫,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸽素,像睡著了一般褒繁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馍忽,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天棒坏,我揣著相機與錄音,去河邊找鬼遭笋。 笑死坝冕,一個胖子當著我的面吹牛,可吹牛的內容都是我干的瓦呼。 我是一名探鬼主播喂窟,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吵血!你這毒婦竟也來了谎替?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蹋辅,失蹤者是張志新(化名)和其女友劉穎钱贯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侦另,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡秩命,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了褒傅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弃锐。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖殿托,靈堂內的尸體忽然破棺而出霹菊,到底是詐尸還是另有隱情,我是刑警寧澤支竹,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布旋廷,位于F島的核電站鸠按,受9級特大地震影響,放射性物質發(fā)生泄漏饶碘。R本人自食惡果不足惜目尖,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扎运。 院中可真熱鬧瑟曲,春花似錦、人聲如沸豪治。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽负拟。三九已至扣甲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間齿椅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工启泣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涣脚,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓寥茫,卻偏偏與公主長得像遣蚀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纱耻,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360