源碼下載地址:https://share./a0c1664d334c4c67ed51fc5e0ac5f2b2 初學機器學習,寫篇文章mark一下,希望能為將入坑者解點惑。本文介紹一些機器學習的入門知識,從安裝環(huán)境到跑通機器學習入門程序MNIST demo。 內(nèi)容提綱:
1 環(huán)境搭建 (Windows)
Anaconda3 4.2 https://www./downloads,自帶python 3.5。
conda create -n tensorflow python=3.5 #創(chuàng)建名為tensorflow,python版本為3.5的虛擬環(huán)境activate tensorflow #激活這個環(huán)境 deactivate #退出當前虛擬環(huán)境。這個不用執(zhí)行 CPU 版本 pip install tensorflow #通過包管理來安裝pip install whl-file #通過下載 whl 文件安裝,tensorflow-cpu安裝包:http://mirrors.oa.com/tensorflow/windows/cpu/tensorflow-1.2.1-cp35-cp35m-win_amd64.whl, cp35是指python3.5 GPU 版本。我的筆記本是技持NVIDIA顯卡的,可以安裝cuda,GPU比CPU快很多,不過筆記本的顯存不大,小模型還可以跑,大模型建議在本地用CPU跑通,到Tesla平臺上訓練。 注意點:選擇正確的 CUDA 和 cuDNN 版本搭配,不要只安裝最新版本,tensorflow可能不支持。 目前Tensorflow已支持到CUDA 9 & cuDNN 7,之前本人安裝只支持CUDA 8 & cuDNN 6,所以用是的: CUDA8.1 https://developer./cuda-80-ga2-download-archive cudnn 6 https://developer./cudnn ,將cudnn包解壓,把文件放到cuda安裝的對應(yīng)目錄中,C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0,bin對應(yīng)bin,include對應(yīng)include,再添加bin目錄到環(huán)境變量path中。 pip install tensorflow-gpu #通過包管理來安裝pip install whl-file #http://mirrors.oa.com/tensorflow/windows/gpu/tensorflow_gpu-1.2.1-cp35-cp35m-win_amd64.whl
(tensorflow) D:\> pip install opencv-python #opencv, tensoflow 虛擬環(huán)境中(tensorflow) D:\> pip install scipy #圖片讀取寫入,scipy.misc.imread(tensorflow) D:\> pip install Pillow #PIL/Pillow,這里有個坑,壓縮過的PNG圖,在1.x版本解析會出現(xiàn)透明通道質(zhì)量下降,升級 2 了解Tensorflow運行機制
import tensorflow as tfhello_world = tf.constant('Hello World!', dtype=tf.string) #常量tensorprint(hello_world) #這時hello_world是一個tensor,代表一個運算的輸出#out: Tensor('Const:0', shape=(), dtype=string)hello = tf.placeholder(dtype=tf.string, shape=[None])#占位符tensor,在sess.run時賦值world = tf.placeholder(dtype=tf.string, shape=[None])hello_world2 = hello+world #加法運算tensorprint(hello_world2)#out: Tensor('add:0', shape=(?,), dtype=string)#mathx = tf.Variable([1.0, 2.0]) #變量tensor,可變。y = tf.constant([3.0, 3.0])mul = tf.multiply(x, y) #點乘運算tensor#logicalrgb = tf.constant([[[255], [0], [126]]], dtype=tf.float32)logical = tf.logical_or(tf.greater(rgb,250.), tf.less(rgb, 5.))#邏輯運算,rgb中>250 or <5的位置被標為True,其它Falsewhere = tf.where(logical, tf.fill(tf.shape(rgb),1.), tf.fill(tf.shape(rgb),5.))#True的位置賦值1,F(xiàn)alse位置賦值5# 啟動默認圖.# sess = tf.Session()with tf.Session() as sess: sess.run(tf.global_variables_initializer())#變量初始化 result = sess.run(hello_world) #Fetch, 獲取tensor運算結(jié)果 print(result, result.decode(), hello_world.eval())#`t.eval()` is a shortcut for calling `tf.get_default_session().run(t)`. #out: b'Hello World!' Hello World! b'Hello World!' #前輟'b'表示bytestring格式,decode解成string格式 print(sess.run(hello, feed_dict={hello: ['Hello']})) #out: ['Hello'] print(sess.run(hello_world2, feed_dict={hello: ['Hello'], world: [' World!']}))#Feed,占位符賦值 #out: [b'Hello World!'] print(sess.run(mul)) #out: [ 3. 6.] print(sess.run(logical)) #out: [[[ True] [ True] [False]]] #rgb中>250 or <5的位置被標為True,其它False print(sess.run(where)) #out: [[[ 1.] [ 1.] [ 5.]]] #True的位置賦值1,F(xiàn)alse位置賦值5#sess.close()#sess如果不是用with方式定義,需要close
3 MNIST(手寫數(shù)字識別 ) softmax性線回歸
MNIST是一個入門級的計算機視覺數(shù)據(jù)集,它包含各種手寫數(shù)字圖片: 它也包含每一張圖片對應(yīng)的標簽,告訴我們這個是數(shù)字幾。比如,上面這四張圖片的標簽分別是5,0,4,1。 數(shù)據(jù)集圖片大小28x28,單通道灰度圖。存儲樣式如下: MNIST手寫數(shù)字識別的目的是輸入這樣的包含手寫數(shù)字的28x28的圖片,預(yù)測出圖片中包含的數(shù)字。 softmax線性回歸認為圖片中數(shù)字是N可能性由圖像中每個像素點用 表示是 數(shù)字 i 的可能性,計算出所有數(shù)字(0-9)的可能性,也就是所有數(shù)字置信度,然后把可能性最高的數(shù)字作為預(yù)測值。 evidence的計算方式如下: 其中 代表權(quán)重, 代表數(shù)字 i 類的偏置量,j 代表給定圖片 x 的像素索引(0~28x28=784),用于像素求和。即圖片每個像素值x權(quán)重之和,再加上一個偏置b,得到可能性值。 引入softmax的目的是對可能性值做歸一化normalize,讓所有可能性之和為1。這樣可以把這些可能性轉(zhuǎn)換成概率 y:
數(shù)據(jù) X樣本 size 28x28 = 784 Y樣本 ,樣式如 讀取 from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True) #total 55000,one_hot方式,圖片x格式為1維數(shù)組,大小784batch_xs, batch_ys = mnist.train.next_batch(batch_size) #分batch讀取 構(gòu)建圖(Graph) Inference推理,由輸入 x 到輸出預(yù)測值 y 的推理過程 x = tf.placeholder(tf.float32, [None, 784], name='input')#None表示batch size待定with tf.variable_scope('inference'):#定義作用域,名子inference W = tf.Variable(tf.zeros([784, 10])) #初值為0,size 784x10 b = tf.Variable(tf.zeros([10])) #初值為0 size 10 y = tf.matmul(x, W) + b #矩陣相乘 Loss 損失函數(shù),分類一般采用交叉熵,這里用的是softmax交交叉熵。交叉熵是用來度量兩個概率分布間的差異性信息,交叉熵公式如下: with tf.variable_scope('loss'): loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y), name='loss') #softmax交叉熵公式: z * -log(softmax(x)) + (1 - z) * -log(1 - softmax (x)) # x: logits, z: label 計算loss的方法有很多種,常見的還有L1 loss 、L2 loss、sigmoid 交叉熵、聯(lián)合loss、自定義loss... Accuracy 準確率,預(yù)測值與真實值相同的概率。矩陣相乘輸出y值是一個數(shù)組,tf.argmax函數(shù)可能從數(shù)據(jù)中找出最大元素下標,預(yù)測值的最大值下標和真值的最大值下標一致即為正確。 with tf.variable_scope('accuracy'): accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)), tf.float32), name='accuracy') Training 訓練,訓練的目的是讓Loss接近最小化,預(yù)測值接近真值,Tensorflow通過優(yōu)化器Optimizers來實現(xiàn)。在y = Wx+b中,W、b在訓練之初會賦初值(隨機 or 0),經(jīng)過Optimizer不短優(yōu)化,Loss逼近最小值,使W、b不斷接近理想值。W、b一起共784x10+10個參數(shù)。 train_step = tf.train.GradientDescentOptimizer(FLAGS.learning_rate).minimize(loss) minimize函數(shù):更新參數(shù),讓Loss最小化,包含兩個步驟:計算梯度;更新參數(shù)。 grad_var = compute_gradients(loss) # return (gradient, variable) pairsapply_gradients(grad_var) #沿著參數(shù)的梯度反方向更新參數(shù),讓Loss變小 GradientDescentOptimizer:梯度下降算法優(yōu)化器, Tensorflow實現(xiàn)的是SGD(隨機梯度下降)。其缺點是依賴當前batch,波動較大。 其它一些增強版Optimizers:參考鏈接。 MomentumOptimizer、AdadeltaOptimizer、AdamOptimizer、RMSPropOptimizer、AdadeltaOptimizer ... Session:Tensorflow需要通過Session(會話)來執(zhí)行推理運算,有兩種創(chuàng)建方式,兩者差別在于InteractiveSession會將自己設(shè)置為默認session,有了默認session,tensor.eval()才能執(zhí)行。 sess = tf.Session()sess = tf.InteractiveSession() 也可以通過下設(shè)置默認session: with sess.as_default(): xx.eval()with tf.Session() as sess: xx.eval() 配置gpu相關(guān)session參數(shù): sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False)#允許沒有g(shù)pu或者gpu不足時用軟件模擬sess_config.gpu_options.allow_growth = True #動態(tài)申請顯存。不加會申請全部,導致其他訓練程序不能運行#sess_config.gpu_options.per_process_gpu_memory_fraction = 0.8 #按比例申請顯存sess = tf.InteractiveSession(config=sess_config) 一個網(wǎng)絡(luò)的訓練過程是一個不斷迭代(前向+反向)的過程。前向算法由前向后計算網(wǎng)絡(luò)各層輸出,反向算法由后向前計算參數(shù)梯度,優(yōu)化參數(shù),減小Loss。流程如圖: 注意:每隔一段時間輸出一下網(wǎng)絡(luò)Loss和Accuracy,查看效果。每隔一段時間緩存一下網(wǎng)絡(luò)參數(shù),防止被突然中斷,可再恢復。 模型參數(shù)的保存與恢復: check point:默認保存方式。 pb:mobile使用。 npz:字典保存方式,{name: value}, numpy的一種保存方式。對參數(shù)按名保存,按名恢復。save和restore方法自己控制,可以選擇性保存和恢復。參見附近代碼中【tools.py】save_npz_dict & load_and_assign_npz_dict方法。 saver = tf.train.Saver(max_to_keep = 3, write_version = 2)save_path = saver.save(sess, FLAGS.out_model_dir+'/model.ckpt')# check point方式output_graph_def = tf.graph_util.convert_variables_to_constants(sess, sess.graph_def, output_node_names=['output'])#指定輸出節(jié)點名稱,這個需要在網(wǎng)絡(luò)中定義with tf.gfile.FastGFile(FLAGS.out_model_dir+'/mobile-model.pb', mode='wb') as f: f.write(output_graph_def.SerializeToString()) #pb方式tools.save_npz_dict(save_list=tf.global_variables(), name=FLAGS.out_model_dir+'/model.npz', sess=sess) #pnz方式 恢復: #check pointsaver = tf.train.Saver(max_to_keep = 3, write_version = 2)model_file=tf.train.latest_checkpoint(FLAGS.log_dir)if model_file: saver.restore(sess, model_file)#npztools.load_and_assign_npz_dict(name=FLAGS.log_dir+'/model.npz', sess=sess))打印網(wǎng)絡(luò)中各參數(shù)信息:方便查看網(wǎng)絡(luò)參數(shù)是否正確。 def print_all_variables(train_only=False): if train_only: t_vars = tf.trainable_variables() print(' [*] printing trainable variables') else: t_vars = tf.global_variables() print(' [*] printing global variables') for idx, v in enumerate(t_vars): print(' var {:3}: {:15} {}'.format(idx, str(v.get_shape()), v.name))
tensorboard --logdir=your-log-path #path中不要出現(xiàn)中文# 需要在訓練過程指定相應(yīng)log路徑,寫入相關(guān)信息# 參考附件【sample.py】中summary、writer相關(guān)關(guān)鍵字代碼。 Graph可視化: 訓練過程可視化: batch size = 128, 訓練集,驗證集。可以看到loss在收斂,accuracy在提高。由于訓練集曲線反應(yīng)的是當前batch的loss和accuracy,batch size相對不高,抖動較大。而驗證集是全部圖片進行測試,曲線較平滑。 4 MNIST深度卷積神經(jīng)網(wǎng)絡(luò)(CNN)Softmax性線回歸網(wǎng)絡(luò)中,輸出y是輸入x的線性組合,即y = Wx+b,這是線性關(guān)系。在很多問題中其解法并非線性關(guān)系能完成的,在深度學習,能過能多層卷積神經(jīng)網(wǎng)絡(luò)組合非線性激活函數(shù)來模擬更復雜的非線性關(guān)系,效果往往比單一的線性關(guān)系更好。先看深度卷積神經(jīng)網(wǎng)絡(luò)(CNN,Convolutional Neural Network)構(gòu)建的MNIST預(yù)測模型,再逐一介紹各網(wǎng)絡(luò)層。
可以看出用的是AdamOptimizer優(yōu)化器。
with tf.name_scope('reshape'): #scope inputs = tf.reshape(inputs, [-1, 28, 28, 1]) #[batch_size, height, width, channels], batch size=-1表示由inputs決定, #batch_size=inputs_size/(28x28x1)
def conv2d(x, W): #W: filter [kernel[0], kernel[1], in_channels, out_channels] return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') tf.nn.conv2d: data_format: input和output數(shù)據(jù)的邏輯結(jié)構(gòu),NHWC : batch height width channel。NCHW: batch channel height width。常用的是NHWC格式;在一些輸入數(shù)據(jù)中各通道數(shù)據(jù)分開存放,這種更適合NCHW。 input:輸入,data_format=NHWC時,shape為batch, in_height, in_width, in_channels,Tensor。 filter:卷積核,shape為filter_height, filter_width, in_channels, out_channels,共有in_channels*out_channels個filter_height, filter_width的卷積核,輸入輸出channel越多,計算量越大。 strides: 步長,shape為1, stride_h, stride_w, 1,通常stride_h和stride_w相等,表示卷積核延縱橫方向上每次前進的步數(shù)。上gif圖stride為1。 padding:卷積計算時數(shù)據(jù)不對齊時填充方式,VALID:丟棄多余;SAME:兩端補0,讓多余部分可被計算。 output:輸出,shape為batch, out_height, out_width, out_channels output[b, i, j, k] = sum_{di, dj, q} input[b, strides[1] * i + di, strides[2] * j + dj, q] * filter[di, dj, q, k]
tf.nn.relu即是激活函數(shù),對卷積輸出作非線性處理,其函數(shù)如下: 其它還有如sigmoid: tanh:
if is_max_pool: x = tf.nn.max_pool(x, [1,kernel[0],kernel[1],1], strides=[1,stride[0],stride[1],1], padding=padding, name='pool')else: x = tf.nn.avg_pool(x, [1,kernel[0],kernel[1],1], strides=[1,stride[0],stride[1],1], padding=padding, name='pool')
x = tf.nn.dropout(x, keep_prob) #keep_prob 保留比例,keep_prob=1.0表示無dropout
BN好處:提升訓練速度,加快loss收斂,增加網(wǎng)絡(luò)適應(yīng)性,一定程序的解決反向傳播過程中的梯度消失和爆炸問題。詳細請戳。
,softmax性線回歸就是一個FC。在CNN中全連接常出現(xiàn)在最后幾層,用于對前面設(shè)計的特征做加權(quán)和。Tensorflow提供了相應(yīng)函數(shù)tf.layers.dense。
VGG,如下圖,非常有名的特征提取和分類網(wǎng)絡(luò)。由多層卷積池化層組成,最后用FC做特征融合實現(xiàn)分類,很多網(wǎng)絡(luò)基于其前幾層卷積池化層做特征提取,再發(fā)展自己的業(yè)務(wù)。 5 tool工具類【tool.py】是一個自己基于tensorflow二次封裝的工具類,位于附件中。好處是以后編程更方便,代碼結(jié)構(gòu)更好看。網(wǎng)上也有現(xiàn)成的開源庫,如TensorLayer、Keras、Tflearn,自己封裝的目的是更好的理解tensorflow API,自己造可控性也更強一些,如果控制是參數(shù)是否被訓練、log打印。 下圖是MNIST CNN網(wǎng)絡(luò)的Inference推理代碼: 6 CPU & GPU & multi GPU
sess_config = tf.ConfigProto(device_count={'CPU': 14}, allow_soft_placement=True, log_device_placement=False)sess_config.intra_op_parallelism_threads = 56sess_config.inter_op_parallelism_threads = 56sess = tf.InteractiveSession(config=sess_config)
with tf.device('/device:GPU:2'): a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a') b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b') c = tf.matmul(a, b)#下面的代碼配置可以避免GPU被占滿,用多少內(nèi)存占多少sess_config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=False)sess_config.gpu_options.allow_growth = Truesess_config.gpu_options.per_process_gpu_memory_fraction = 0.8sess = tf.InteractiveSession(config=sess_config) 多塊GPU時,可以通過在終端運行下面指令來設(shè)置CUDA可見GPU塊來控制程序使用哪些GPU。 export CUDA_VISIBLE_DEVICES=2,3
在Tensorflow中你需要自己寫代碼控制多GPU的loss和gradient的合并,這里有個官方例子請戳。自己也寫過多GPU的工程,附件代碼【tmp-main-gpus-不可用.py】可做參考,但此處不可用,來自它工程。 7 學習資料收藏了一些機器學習相關(guān)資料,分享一下。自己也只看過很小一部分,仍在學習中....
|
|