一、Model類
(1)初始化方法
1.可擴展參數(shù):從kwargs
字典里獲取,可限制key的取值
-
name
:model
變量域scope
名稱,獲取不到采用self.__class__.__name__.lower()
取類的名字 -
logging
: 是否開啟TensorBoard
直方圖儀表板嫂拴,獲取不到為False
- 其他參數(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 | 運算名稱 |
- 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ù)也在增加,曲線從欠擬合變得過擬合爸黄。