AI_TensorflowNotebook
北京大學公開課學習筆記
課程鏈接:https://www.icourse163.org/course/PKU-1002536002
課程github主頁:鏈接
推薦課程中的助教筆記,內容更加全面。筆記鏈接 提取碼: jhk5
本文相關代碼:github個人主頁
1 AI概述與環境搭建
1.1 人工智能概述
- 人工智能的概念、興衰史、學科帶頭人、常見消費產品。
- 機器學習概念、應用領域(CV、NLP)、三要素(數據、算法、算力)
- 深度學習概念、計算機實現。
- 關係:人工智能》機器學習》深度學習
1.2 環境配置
課程代碼基於python2.7,tensorflow版本:1.3.0,系統:windows10,其他環境可以自行百度或參考課程視頻安裝。
個人使用64位虛擬機:ubuntu18.04,安裝過程遇到的一些問題:
- 安裝pip:
sudu apt install python-pip
- pip 安裝完成後去 tflearn.org 左側Installation 找到對應python版本的TensorFlow下載指令。
如ubuntu/linux 64-bit,CPU only,python2.7對應:$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.1.0-cp27-none-linux_x86_64.whl
- 藉助輸入下面的對應python2 的安裝指令:
$ sudo pip install $TF_BINARY_URL
- 安裝後命令行進入python,輸入:
import tensorflow as tf
不報錯說明安裝成功,輸入:print tf.__version__
查看版本。
1.3 安裝必要包
使用清華鏡像,安裝其他需要的python包,如pandas,命令行輸入:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pandas
安裝vim:sudo apt-get install vim
替換apt軟件源爲阿里雲源:https://blog.csdn.net/zhangjiahao14/article/details/80554616
這裏ubuntu的版本影響源地址,所以之前一直替換不成功。
python2.7比較老,很多包和函數都因爲更新會出現各種各樣的問題,遇到問題多找找博客論壇。
2 編程語言基礎
2.1 常用基礎命令
- pwd:當前路徑
- ls:顯示文件
- cd… 返回上一級 …/…上兩級 ~ 返回home目錄
- mkdir:創建文件夾
- vim A.py 用vim打開一個py文件
- vim全選,全部複製,全部刪除,先按esc,分別對應ggVG、ggyG、dG
- :q 強制退出vim :wq保存更改退出 :q! 不保存退出 如果文件無法編輯保存退出,打開文件的時候使用sudo vim 文件命名
其他vim指令參考:點此連接
2.2 ubuntu指令
- 更新源:sudo apt-get update
- 更新已安裝的軟件:sudo apt-get upgrade
- 刪除包:sudo apt-get remove package
- 打開命令終端:Ctrl+Alt+T
- 回到桌面:win+D
- 切換輸入法:win+空格
- 其他快捷鍵在:設置->設備->鍵盤 處可看。
2.3 python基礎語法
學習本課程的都是有基礎的,不再贅述。
3 Tensorflow框架介紹
3.1 張量、圖、會話
基於tensorflow的神經網絡就是用張量(Tensor)表示數據,用計算圖(Graph)搭建網絡,用會話(Sess)進行運算,優化權重參數獲得模型。
1、張量(Tensor):多維數組的特殊表示形式
#coding:utf-8
import tensorflow as tf
a=tf.constant([1.0,2.0]) #張量
b=tf.constant([3.0,4.0])
result=a+b
print result
輸出:Tensor(“add:0”, shape=(2,), dtype=float32)
2、計算圖(Graph):搭建神經網絡的計算結構(乘加),不進行計算。
#coding:utf-8
import tensorflow as tf
x = tf.constant([[1.0, 2.0]])
w = tf.constant([[3.0], [4.0]])
y=tf.matmul(x,w)
print y
輸出:
Tensor(“MatMul:0”, shape=(1, 1), dtype=float32)
3、會話(Session):會話爲執行計算結果
with tf.Session() as sess:
print sess.run(y)
[[11.]]
4、常用參數tf.Variable()
tf.random_normal() #生成正態分佈隨機數
tf.truncated_normal() #去大偏離點的正態
tf.random_uniform() #均勻分佈隨機
tf.zeros() #全0
tf.ones() #全1
tf.fill() #全部爲某一個給定值
tf.constant([]) #給指定值,可不同
涉及到隨機數時給定seed即可生成相同隨機數。
3.2 前向傳播
將數據輸入,搭建好的Graph,Session結構,經卷積、池化、非線性激活等操作輸出運算結果。
#coding:utf-8
import tensorflow as tf
x = tf.constant([[0.7, 0.5]]) #輸入
w1= tf.Variable(tf.random_normal([2, 5], stddev=1, seed=1)) #兩層參數w 五個節點
w2= tf.Variable(tf.random_normal([5, 1], stddev=1, seed=1))
a = tf.matmul(x, w1) #前向傳播計算
y = tf.matmul(a, w2)
with tf.Session() as sess:
init_op = tf.global_variables_initializer() #彙總變量
sess.run(init_op) #變量初始化
print"y in test is:\n",sess.run(y) #計算接點輸出
使用:tf.placeholder(tf.float32, shape=(A, B))對輸入數據佔位,選擇喂入一組(A=1)或多組(A=None),以及選擇數據屬性(B=)。
喂1組,每組2列:
x = tf.placeholder(tf.float32, shape=(1, 2))
sess.run(y, feed_dict={x: [[0.6,0.4]]})
喂2組,每組3列:
x = tf.placeholder(tf.float32, shape=(None, 3))
sess.run(y, feed_dict={x: [[0.6,0.4,0.2],[0.3,0.5,0.8]]})
3.3 反向傳播
指定學習率、損失函數等參數不斷喂入數據進行參數w權重偏置b的優化,達到最小損失,參數最優。
1、損失函數(loss):預測值yu和已知答案y的差值,優化的目標,使它最小。
常用方法:
均方誤差(MSE): 預測yu和標準y差的平方和再求平均
loss_MSE = tf.reduce_mean(tf.square(y-yu))
交叉熵(CE):概率分佈距離,只越大預測、實際差距越大。
ce = -tf.reduce_mean(yu*tf.log(tf.clip_by_value(yu,1e-12,1.0))) #限定yu作爲log指數不爲0
自定義:其他損失函數。
2、 學習率(learning_rate)
參數更新的幅度,一般預設0.001
3、優化器選擇:
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_MSE) #梯度下降
train_step = tf.train.MomentumOptimizer(0.001,0.9).minimize(loss_MSE)
train_step = tf.train.AdamOptimizer(0.001).minimize(loss_MSE)
常見優化器優缺點比較:參考博客
訓練時可以加入 time 模塊計算時間。
4、激活函數:
增加模型的表達力,提高非線性分類的能力。
- relu函數:tf.nn.relu()
- sigmoid函數:tf.nn.sigmoid()
- tanh函數:tf.nn.tanh()
常用激活函數理解和總結:StevenSun2014的博客
3.4 神經網絡複雜度
與神經網絡層數和參數個數有關。
神經網絡層數爲隱含層個數+1,沒經過運算的不算(輸入層不算,輸出算)
參數:總的權重參數w個數 + 總偏置項b個數。權重參數w個數看每層前後節點乘積和,總偏置b個數看每兩層後靠後一層的節點數量。
4 神經網絡優化
4.0先導環節
tensorflow裏的一些常用函數
tf.get_collection("")
#從集合中取出全部變量形成列表
tf.add_n([])
#列表內對應元素相加
tf.cast(x,dtype)
#將x轉化爲dtype類型
f.argmax(x,axis=)
#返回最大值索引號
with tf.Graph().as_default as g:
#將()其中的節點用在計算圖 g 中,一般用於復現定義好的網絡
4.1 損失函數
MSE、CE、自定義三種,再tensorflow中的使用不再贅述,參考上節。
在交叉熵損失函數使用時如果使用softmax()轉化爲分類概率分佈:
CE = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=,labels=tf.argmax(yu,1)) #返回每行在列維度的最大值索引
CEM = tf.reduce_mean(CE)
4.2 學習率
可以設置靜態學習率爲定值,不宜過小過大,過小損失函數收斂很慢,較大容易振盪不收斂。
指數衰減學習率:根據訓練輪數動態更新學習率。
lr = lr_base * lr_decay^(global_step/lr_step)
- lr_base:學習率初始值,學習率基數
- lr_decay:學習率衰減率,屬於(0,1)
- global_step:運行了多少輪batch_size
- lr_step:多少輪更新(減低)一次學習率,取(總樣本數/batch_size)
在tensorflow中:
global_step = tf.Variable(0,trainable = False) #輪數不可訓練
lr = tf.train.exponential_decay(
lr_base,
global_step,
lr_step,
lr_decay,
staircase = Ture)
#staircase = Ture 時,比值取整,梯形衰減,False平滑衰減
指數衰減的學習率,在迭代初期得到較高的下降速度,可以在較小的訓練輪數下取得更有收斂度。
注意:global_step的值是使學習率更新的關鍵:
train_step = tf.train.GradientDescentOptimizer(lr).minimize(loss, global_step=global_step)
如果不在訓練目標**minimize(loss, global_step=global_step)**里加上global_step=global_step的話這個數值不會變化,學習率也就不會變化。
4.3 滑動平均
記錄網絡中每個參數一段時間內過往值的平均值,增加模型的泛化能力。針對所有參數w和b
滑動均值初值 = 參數初值
滑動均值 = 衰減率 * 上一滑動均值 + (1-衰減率)* 更新的參數值(w或b)
衰減率 = Min{ Moving_Average_Decay,(1+global_step)/(10+global_step)}
實際使用:
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step) #global_step當前輪數
ema_op = ema.apply(tf.trainable_variables()) #對所有待優化的參數求滑動平均
with tf.contral_dependencies([train_step,ema_op]): #只優化這兩個參數集
train_op = tf.no_np(name='train') #執行完上面兩之後什麼也不做
ema.average(w1)
可以在運行過程調用查看參數情況
4.4 正則化
在模型損失函數中給每個參數加上權重,抑制模型訓練數據噪聲。
通常只對權重參數w使用,緩解過擬合現象。
loss_all = loss(CE,MSE等) + REGULARIZER * loss(w)
#loss_all表示模型總的損失函數,REGULARIZER表示超參數權重,決定w在總loss中的比例。loss(w)是進行正則化的參數。
常用的兩種正則化方法:
L1正則: L1_loss=∑|w|
loss(w) = tf.contrib.layers.l1_regularizer(REGUIARIZER)(w)
L2正則:L2_loss=∑|w^2|
loss(w) = tf.contrib.layers.l2_regularizer(REGUIARIZER)(w)
tensorflow中使用方法:
loss_ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(yu, 1))
loss_cem = tf.reduce_mean(loss_ce)
loss_all = loss_cem + tf.add_n(tf.get_collection('losses')) #這裏的losses就是經過正則化的,
其他正則化方法可參考博客:Maples丶丶的博客
示例:初始分佈
無正則化訓練:60000次,學習率0.001.
有正則化訓練:60000次,學習率0.001.
可以調整其他參數查看效果:如訓練輪數爲120000次時:
4.5 神經網絡搭建樣例
def forward(x,regularizer): #聲明權重、參數,和預測輸出的計算方法
w =
b =
y =
return y #輸出結果
def get_weight(shape,regularizer): #shape是中間權重矩陣形狀
w = tf.Variable() #一般用隨機函數聲明
if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
#聲明如果有正則化超參數,則對w使用正則化
return w
def get_bias(shape): #偏置形狀和參數
b = tf.Variable()
return b
def backward():
x = tf.placeholder()
y = tf.placeholder() #標準的x和類標籤y 數據佔位
yu = forward.forward(x,REGULARIZER) #調用forward.py裏的forward函數計算預測輸出
global_step = tf.Variable(0,trainable=False)
loss = 可視任務情況選擇加入優化方法
①正則化的優化方法:
內容參考上一節:
最終loss = 基本損失loss(CE等) + 正則化損失tf.add_n(tf.get_collection('losses'))
②指數衰減學習率優化:
調用函數參考上節。
最終的訓練目標:train_step = tf.train.GradientDesentOptimizer(lr).minimize(loss,global_step = global_step)
優化器除梯度下降也可選其他MomentumOptimizer、AdamOptimizer等。
③滑動平均優化:
ema = tf.train.ExponentialMovingAverage(M_A_DECAY,global_step)
ema_op = ema.apply(tf.trainable_variables()) #應用到所有參數求滑動平均
with tf.contral_dependencies([train_step,ema_op]): #只執行這兩個部分
train_op = tf.no_np(name='train') #之後無操作
④實例化聲明:用以保存模型參數:
saver = tf.train.Saver()
⑤所有變量環節初始化
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op) #生成會話, 初始化變量
for i in range(STEPS):
sess.run(train_step,feed_dict={x: ,y_: }) #喂數
if i % 輪數 ==0:
print #每多少輪顯示輪數或者loss損失值
saver.save() #保存模型及參數
⑥判斷backward是否爲主文件:
if __name__ = '__main__':
backward()
def test():
with tf.Graph().as_default() as g: #復現計算圖
x = tf.placeholder(tf.float32, [None, ])
y = tf.placeholder(tf.float32, [None, ]) #輸入x y 佔位
yu = forward.forward(x, None) #前向傳播計算輸出yu
實例化帶滑動平均的saver對象,所有參數在會話中被加載時會被賦值爲各自的滑動平均值。就是調用以前經過滑動平均的參數。
ema = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
ema_restore = ema.variables_to_restore()
saver = tf.train.Saver(ema_restore)
計算準確率
correct_prediction = tf.equal(tf.argmax(yu, 1), tf.argmax(y, 1))
#yu是神經網絡喂入的batch_size組數據後計算的結果,是batchsiZe組*10(單個標籤所含10分類)的二維數組。
#1表示argmax函數選取最大值的操作僅在第一個維度,就是返回每行裏的最大值對應索引。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#cast()把equal()函數獲取的布爾值轉化爲實數,再用tf.reduce_mean()求平均,獲得準確率
while True:
with tf.Session() as sess:
ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
#加載模型,賦參數滑動平均值
if ckpt and ckpt.model_checkpoint_path: #確認模型路徑和文件都存在
saver.restore(sess, ckpt.model_checkpoint_path) #恢復到當前會話
global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
accuracy_score = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
print("經過 %s 訓練輪數, 準確率爲: %g" % (global_step, accuracy_score))
else:
print('沒有對應模型')
return
time.sleep(T) #測試進行的快,訓練保存模型進行的慢,不延遲可能多次調用的是同一個模型的參數,若不是一起運行則無影響
5 全連接網絡基礎
5.1 MNIST數據集
mnist爲黑底白字的手寫數字數據集,每行圖片大小爲28*28像素,附帶每張圖片的標籤信息。純黑像素爲 0,純白色像素爲1.
數據集分爲train, validation 和 test 三個數據集。訓練集和驗證集一般用來訓練。
- train:一般用來訓練調整網絡權重參數,計算訓練集準確率。
- validation:一般只用來計算準確率,達到閾值就退出訓練。**不使用該數據集調整參數權重。**如果訓練驗證過程中訓練集的準確率仍然不斷上升,但是驗證集準確率不變或者降低了,就過擬合了,停止訓練。
- test:用來測試網絡的實際預測能力
0加載數據集到指定路徑:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./python/pymnist/data/", one_hot=True)
1查看各個數據集樣本數量:
print "train sets size:\n",mnist.train.num_examples
print "validation sets size:\n",mnist.validation.num_examples
print "test sets size:\n",mnist.test.num_examples
2 查看制動數據集、指定圖片的標籤和像素值:
#訓練集中第6張圖片的標籤和像素值
mnist.train.labels[6]
>>>array([0., 1., 0., 0., 0., 0., 0., 0., 0., 0.])
#該數字爲2
mnist.train.images[6]
3 喂入網絡數據
xs,ys = mnist.train.next_batch(batchsize)
參數 batchsize,表示隨機從訓
練集中抽取 batchsize 個樣本輸入神經網絡,並將樣本的像素值和標籤分別賦
給 xs 和 ys。
5.2 模型的保存、複用和斷點續訓
保存:
saver = tf.train.Saver()
#聲明實例對象
with tf.Session() as sess:
...
for i in range(STEPS):
xs, ys = mnist.train.next_batch(BATCH_SIZE)
if i % 輪數 == 0:
saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)
#保存模型到當前會話,標註保存時的訓練輪數
模型加載:
with tf.Session() as sess:
ckpt = tf.train.get_checkpoint_state( 存儲路徑) )
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
#如果ckpt模型和保存路徑都存在,複用
斷點續訓:一般加在會話sess開始後初始化的後面,可以繼續之前意外中斷的訓練過程。
ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
5.3 全連接神經網絡識別手寫體數據
對應文件在文件夾chapter5_fullyConect中。
包含幾個部分:
- data文件夾:存放下載的mnist數據文件。
- model文件夾:存放訓練完成保存的模型及各個參數,默認只保存最近的5個。
- pic文件夾:爲待識別的手寫數字圖片。
- mnist_backward.py:反向傳播過程,及常見優化方法。
- mnist_forward.py:定義輸入參數、網絡結構。
- mnist_test.py:複用模型進行測試,查看準確率。
- mnist_app.py:應用訓練好的模型實現手寫數字預測。
使用時注意各文件存放路徑,避免使用時調用路徑錯誤,進行圖片預測測試時待判別圖片路徑輸入要完整。
反向傳播:
注意訓練過程可以按 ctrl+Z中斷訓練,模型下次訓練可以繼續,若要重新開始先刪除model文件夾裏的文件。
測試:
應用預測:
6 全連接神經網絡實戰
6.1 與第五章內容重合,不贅述
6.2 以mnist爲例自制數據集
6.2.1 什麼是tfrecords文件
1、tfrecords文件:
一種二進制文件,可先將圖片和標籤製作成該格式的文件。使用這種格式進行數據讀取,會提高內存利用率。
2、 tf.train.Example():
用來存儲訓練數據。tf.train.Example中包含了一個從屬性名稱及取值的字典,其中屬性名稱爲一個字符串,屬性的取值可以爲字符串(BytesList ),實數列表(FloatList )或整數列表(Int64List )。
訓練數據的特徵用 鍵值對 的形式表示。
如:
'img_raw':值
'label':值
值取:Byteslist/FloatList/Int64List
3、 SerializeToString( ) :
把數據序列化成字符串存儲。
6.2.2 生成 tfrecords文件
writer = tf.python_io.TFRecordWriter('train.tfrecords') #新建writer文件
.
.#中間讀待制作數據文件過程
.
for content in contents: #對每個數據處理
.
.#取數據路徑、轉爲二進制,打標籤
.
example = tf.train.Example(features=tf.train.Features(feature={
'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=labels))
})) #標準封裝格式 每張圖片和標籤封裝到example中
writer.write(example.SerializeToString()) #序列化存儲
writer.close() #完成
6.2.3 解析 tfrecords文件
filename_queue = tf.train.string_input_producer([tfRecord_path], shuffle=True) #解析隊列
reader = tf.TFRecordReader() #新建reader文件
_, serialized_example = reader.read(filename_queue) #讀出來的每一個樣本保存
features = tf.parse_single_example(serialized_example,
features={
'label': tf.FixedLenFeature([10], tf.int64),
'img_raw': tf.FixedLenFeature([], tf.string)
}) #解序列化
img = tf.decode_raw(features['img_raw'], tf.uint8) #恢復圖片
.
.
. #降維,整形 主要是符合選用網絡的輸入要求
.
6.2.4 獲取展示 tfrecords文件
tfrecords_file = '.../train.tfrecords'
image_batch, label_batch = read_tfrecord(tfrecords_file)
img_batch, label_batch = tf.train.shuffle_batch([img, label],
batch_size= batch_size,
num_threads=2,
capacity=2000,
min_after_dequeue=1500,
)
#從總樣本中順序取出capacity組數據,每次打亂順序輸出batch_size組,
#如果capacity小於min_after_dequeue,會再從總樣本中取出數據填滿capacity,
#結果輸出爲隨即取出的batchsize組圖像和標籤數據
此章數據集tfrecords文件製作有部分內容參考博客:鏈接
最後修改測試我沒有成功復現:可參考博客young liu
這部分內容數據及源碼鏈接:鏈接
試了幾次數據文件解壓都有問題。