本博客所有內(nèi)容以學(xué)習(xí)晾腔、研究和分享為主愉老,如需轉(zhuǎn)載场绿,請聯(lián)系本人,標(biāo)明作者和出處嫉入,并且是非商業(yè)用途焰盗,謝謝!
Mnist圖像分類(tensorflow)
1.1案例概述
1.1.1 案例簡介
用深度學(xué)習(xí)做項目咒林,當(dāng)下最流行的就是Tensorflow框架了熬拒。那么什么是Tensorflow呢?
Tensorflow是一個Google開發(fā)的第二代機器學(xué)習(xí)系統(tǒng)垫竞,克服了第一代系統(tǒng)DistBelief僅能開發(fā)神經(jīng)網(wǎng)絡(luò)算法澎粟、難以配置、依賴Google內(nèi)部硬件等局限性欢瞪,應(yīng)用更加廣泛活烙,并且提高了靈活性和可移植性,速度和擴展性也有了大幅提高引有。字面上理解瓣颅,TensorFlow就是以張量(Tensor)在計算圖(Graph)上流動(Flow)的方式的實現(xiàn)和執(zhí)行機器學(xué)習(xí)算法的框架。
要想使用深度學(xué)習(xí)做項目譬正,我們就要學(xué)會怎么使用tensorflow帚湘。在這一章我們就以mnist數(shù)據(jù)集為例扑媚,通過tensorflow搭建分類算法蟹瘾,從而真正的了解怎么使用tensorflow抵卫。
1.1.2 功能概述
本案例主要讓你從零學(xué)會使用tensorflow,前面先簡單的介紹如何使用tensorflow抒巢,后面以Mnist數(shù)據(jù)集為例贫贝,用不同的方法對其進行分類。分為以下五個功能。
- tensorflow的簡單操作稚晚,讓你了解tensorflow的規(guī)則和使用方法
- 用tensorflow做線性回歸崇堵,對前面介紹的方法進行實踐
- 用tensorflow做邏輯回歸,這里是進入神經(jīng)網(wǎng)絡(luò)的第一步
- 構(gòu)建神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)客燕,用tensorflow一步一步去構(gòu)建神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)
1.1.3 數(shù)據(jù)描述
Mnist數(shù)據(jù)集是來自美國國家標(biāo)準(zhǔn)與技術(shù)研究所, National Institute of Standards and Technology (NIST). 訓(xùn)練集 (training set) 由來自 250 個不同人手寫的數(shù)字構(gòu)成, 其中 50% 是高中學(xué)生, 50% 來自人口普查局 (the Census Bureau) 的工作人員. 測試集(test set) 也是同樣比例的手寫數(shù)字?jǐn)?shù)據(jù)鸳劳。
tensorflow中已經(jīng)提供了這份數(shù)據(jù)集,我們直接從中調(diào)用即可
# 導(dǎo)入各種包
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
# 下載數(shù)據(jù)集
mnist = input_data.read_data_sets('data/', one_hot=True)
print (" 類型是 %s" % (type(mnist)))
print (" 訓(xùn)練數(shù)據(jù)有 %d" % (mnist.train.num_examples))
print (" 測試數(shù)據(jù)有 %d" % (mnist.test.num_examples))
運行結(jié)果
Extracting data/train-images-idx3-ubyte.gz
Extracting data/train-labels-idx1-ubyte.gz
Extracting data/t10k-images-idx3-ubyte.gz
Extracting data/t10k-labels-idx1-ubyte.gz
類型是 <class 'tensorflow.contrib.learn.python.learn.datasets.base.Datasets'>
訓(xùn)練數(shù)據(jù)有 55000
測試數(shù)據(jù)有 10000
我們發(fā)現(xiàn)這份數(shù)據(jù)集分為訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)也搓,數(shù)據(jù)量還可以赏廓,不是很大,用cpu足夠了傍妒。
接下來我們看一下Mnist數(shù)據(jù)集的規(guī)格是什么樣的幔摸。內(nèi)置數(shù)據(jù)集有個好處,就是別人幫我們把數(shù)據(jù)的屬性都寫好了颤练,我們直接調(diào)用即可既忆。
trainimg = mnist.train.images
trainlabel = mnist.train.labels
testimg = mnist.test.images
testlabel = mnist.test.labels
print (" 數(shù)據(jù)類型 is %s" % (type(trainimg)))
print (" 標(biāo)簽類型 %s" % (type(trainlabel)))
print (" 訓(xùn)練集的shape %s" % (trainimg.shape,))
print (" 訓(xùn)練集的標(biāo)簽的shape %s" % (trainlabel.shape,))
print (" 測試集的shape' is %s" % (testimg.shape,))
print (" 測試集的標(biāo)簽的shape %s" % (testlabel.shape,))
運行結(jié)果
數(shù)據(jù)類型 is <class 'numpy.ndarray'>
標(biāo)簽類型 <class 'numpy.ndarray'>
訓(xùn)練集的shape (55000, 784)
訓(xùn)練集的標(biāo)簽的shape (55000, 10)
測試集的shape' is (10000, 784)
測試集的標(biāo)簽的shape (10000, 10)
我們發(fā)現(xiàn)訓(xùn)練集的shape 是(55000, 784),55000是指有55000張圖像嗦玖,784是指每張圖像的大小尿贫,也就是28281,28*28可以理解為圖像的長和寬踏揣,1是指這些圖是黑白圖,也就是顏色通道匾乓。每張圖都有784個像素點捞稿。 訓(xùn)練集的標(biāo)簽的shape是(55000, 10),55000還是指有55000張圖像拼缝,10是指有10類標(biāo)簽娱局,0到9一共是10個數(shù)據(jù)。這里面的意思是指每張圖都會對應(yīng)出0到9這十類標(biāo)簽咧七,然后每類標(biāo)簽下都對應(yīng)著數(shù)字0和1衰齐。具體我們看下圖。
當(dāng)數(shù)字是2的時候继阻,在2這個標(biāo)簽下對應(yīng)的是數(shù)字是1耻涛,其他都是0。同理其他數(shù)字也是這樣瘟檩。label就是這樣的編碼抹缕。
我們最后就會預(yù)測每個類別的概率值,看看預(yù)測的哪個類別的概率最大墨辛,那么這個手寫圖像就對應(yīng)哪個類別
來看一下圖像具體長什么樣子
nsample = 5
randidx = np.random.randint(trainimg.shape[0], size=nsample)
for i in randidx:
curr_img = np.reshape(trainimg[i, :], (28, 28)) # 28 by 28 matrix
curr_label = np.argmax(trainlabel[i, :] ) # Label
plt.matshow(curr_img, cmap=plt.get_cmap('gray'))
print ("" + str(i) + "th 訓(xùn)練數(shù)據(jù) "
+ "標(biāo)簽是 " + str(curr_label))
plt.show()
代碼解釋:
這里是隨機挑選了5張圖卓研,并且打印了它的標(biāo)簽。我就不全部放進來了,直接看看運行后的結(jié)果
Mnist數(shù)據(jù)集就是長這個樣子奏赘,然后我們的任務(wù)就是訓(xùn)練出來一個分類器寥闪,讓計算機自動識別出來這些手寫數(shù)據(jù)
我們訓(xùn)練模型的時候肯定不是一次性讀入所有的數(shù)據(jù),而是分批次讀取磨淌,也就是每次取一個batch疲憋,具體操作如下
# Batch數(shù)據(jù)
batch_size = 100
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
print ("Batch數(shù)據(jù) %s" % (type(batch_xs)))
print ("Batch標(biāo)簽 %s" % (type(batch_ys)))
print ("Batch數(shù)據(jù)的shape %s" % (batch_xs.shape,))
print ("Batch標(biāo)簽的shape %s" % (batch_ys.shape,))
這里是每次隨機取出100張圖像拿來訓(xùn)練
運行結(jié)果
Batch數(shù)據(jù) <class 'numpy.ndarray'>
Batch標(biāo)簽 <class 'numpy.ndarray'>
Batch數(shù)據(jù)的shape (100, 784)
Batch標(biāo)簽的shape (100, 10)
1.2 實現(xiàn)分析
本案例的目的就是讓大家學(xué)會使用tensorflow,為后面的深度學(xué)習(xí)案例做準(zhǔn)備伦糯。
整體的結(jié)構(gòu)如圖所示
流程概述:
1)tensorflow的基本結(jié)構(gòu)介紹柜某,主要是介紹它的操作規(guī)矩
2)用tensorflow實現(xiàn)線性回歸,先生成一份線性分布的數(shù)據(jù)敛纲,然后構(gòu)建模型喂击,去擬合這份數(shù)據(jù),用梯度下降法去優(yōu)化這個模型淤翔,最終得到好的權(quán)重參數(shù)
3)用tensorflow實現(xiàn)邏輯回歸翰绊,這是在為后面構(gòu)建神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)做準(zhǔn)備,神經(jīng)網(wǎng)絡(luò)比邏輯回歸多了兩個特點旁壮,一個是層次結(jié)構(gòu)监嗜,另一個是激活函數(shù)。所以實現(xiàn)邏輯回歸很重要抡谐。先導(dǎo)入所需工具包以及Mnist數(shù)據(jù)集裁奇,然后設(shè)置參數(shù),指定數(shù)據(jù)集x和y麦撵。對權(quán)重參數(shù)進行初始化刽肠,構(gòu)造模型,迭代計算音五,最后用測試數(shù)據(jù)進行測試,這些操作都會在后面的代碼中詳細(xì)體現(xiàn)羔沙。
4)構(gòu)建神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)躺涝,這里構(gòu)建的是單層的。有了前面的基礎(chǔ)扼雏,這里就會變得很容易坚嗜。我們只要在邏輯回歸的基礎(chǔ)上實現(xiàn)出它的那兩個特點,層次結(jié)構(gòu)以及激活函數(shù)呢蛤,那么就可以結(jié)束了惶傻。整個操作流程和邏輯回歸的一樣,具體代碼見后面其障。最后還介紹了一下雙層的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)银室,流程其實也是一樣的,只不過多了權(quán)重參數(shù),看后面代碼便可了解蜈敢。
1.2.1 tensorflow的簡單操作
我們先從最簡單的問題入手辜荠,怎么用tensorflow定義一個變量。在這里和python定義變量的方法不一樣抓狭,創(chuàng)建一個變量首先要指定它的格式伯病,也就是tensor格式,因為在tensorflow里的一系列計算它對數(shù)據(jù)的格式是有要求的,所以我們要先把變量指定成tensor格式否过。比如
w是行向量午笛,x是列向量,y是把w苗桂,x作矩陣相乘
import tensorflow as tf
w = tf.Variable([[0.5,1.0]])
x = tf.Variable([[2.0],[1.0]])
y = tf.matmul(w, x)
在tensorflow中药磺,我們得遵守人家的規(guī)矩,按照它們的要求來操作煤伟。創(chuàng)建完這些變量還沒完癌佩,這些操作僅僅是聲明了有這么個事,但還沒有執(zhí)行便锨,所以還要把它們初始化出來——全局變量初始化围辙。然后打開一個session,session可以簡單地理解成被開辟出來的一個可計算區(qū)域放案,然后執(zhí)行一下(也就是run一下)姚建,才能會有效果。前面寫的都是擺設(shè)吱殉,只有在session里run一下桥胞,才是被執(zhí)行。通過下面代碼我們就會計算出y值
#全局變量初始化
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
print (y.eval())
tensorflow中還有很多操作考婴,跟numpy很類似。比如我們想構(gòu)建一個隨機的正態(tài)分布催烘。
[2,3]是指定的維度沥阱,mean是指定的平均值,stddev是指定的標(biāo)準(zhǔn)偏差
norm = tf.random_normal([2, 3], mean=-1, stddev=4)
我們再用tensorflow做一個洗牌的操作
c是我們構(gòu)造的常量數(shù)據(jù)
c = tf.constant([[1, 2], [3, 4], [5, 6]])
shuff = tf.random_shuffle(c)
上面的操作還沒結(jié)束伊群,我們還沒給它開辟一個計算區(qū)域呢考杉,開辟session區(qū)域之后,再run一下舰始,就可以得到結(jié)果了
# 每一次執(zhí)行結(jié)果都會不同
sess = tf.Session()
print (sess.run(norm))
print (sess.run(shuff))
運行結(jié)果
[[-5.58110332 0.84881377 7.51961231]
[ 3.27404118 -7.22483826 7.70631599]]
[[5 6]
[1 2]
[3 4]]
為了更好的理解崇棠,我們再舉個例子,假設(shè)我們要實現(xiàn)這么一個功能丸卷,做出一個循環(huán)枕稀,每次遞增1。用python是非常好實現(xiàn)的,但在tensorflow中有點麻煩萎坷,我們來看一下
state = tf.Variable(0)
new_value = tf.add(state, tf.constant(1))
update = tf.assign(state, new_value)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(state))
for _ in range(3):
sess.run(update)
print(sess.run(state))
代碼解釋:
state是指定的初始值變量凹联,為0。new_value是指新的值哆档,做的是一個加法的操作蔽挠,里面?zhèn)魅氲膮?shù)是state初始值,和一個常量1瓜浸。意思就是每次加1澳淑。update是做了一個賦值的操作,就是把新的值new_value賦值給state插佛,相當(dāng)于"+="的操作杠巡。上面的這些操作聲明好之后,我們該給它開辟一個可計算區(qū)域了朗涩。第一步就是進行一個全局變量的初始化忽孽,然后再去執(zhí)行我們定義的操作
接下來我們說一個比較重要的操作,placeholder操作谢床,這個操作大概意思就是先固定好shape值兄一,然后再傳值進去。就像是先挖好一個坑识腿,固定坑的大小出革,這樣就把數(shù)據(jù)的格式定好了,埋進去的蘿卜大小都一樣渡讼,只是品種不同骂束。用這樣的操作好處就是可以邊賦值邊操作。比如batch成箫,我們訓(xùn)練數(shù)據(jù)的時候不是一次性把數(shù)據(jù)全部輸入進去展箱,而是分批次輸入,輸入的數(shù)據(jù)格式是一樣的蹬昌,但是數(shù)據(jù)的值是不一樣的混驰,這時候就可以用這種操作了。也就是每次數(shù)據(jù)的維度(shape)是一樣的皂贩,那么我們先固定好它的維度栖榨,然后就可以傳入格式相同,但值不一樣的數(shù)據(jù)了
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
with tf.Session() as sess:
print(sess.run([output], feed_dict={input1:[7.], input2:[2.]}))
代碼解釋:
input1和input2是我們挖好了的兩個坑明刷,要求傳入的數(shù)值是tf.float32的格式婴栽。output就是我們要執(zhí)行的乘法操作,里面?zhèn)魅氲膮?shù)是沒有值的辈末,僅僅只是坑愚争,這個時候我們開辟一個可計算的區(qū)域映皆,然后在實際執(zhí)行操作(run)的時候進行賦值。run里面是你要執(zhí)行的操作准脂,feed_dict是一個字典的結(jié)構(gòu)劫扒,在里面?zhèn)魅霐?shù)值。
1.2.2 用tensorflow做線性回歸
線性回歸描述:
現(xiàn)在有一些數(shù)據(jù)狸膏,這些數(shù)據(jù)有自己的分布規(guī)則沟饥,然后我們可以找出一條線,最好的擬合這個數(shù)據(jù)湾戳。
以上就是我們要實現(xiàn)的算法贤旷。
1)構(gòu)造出一份數(shù)據(jù)
隨機生成1000個點,圍繞在y=0.1x+0.3的直線周圍砾脑,一會兒我們的任務(wù)就是要去求這條直線幼驶,也就是求出這條線的權(quán)重參數(shù),所以把數(shù)據(jù)造在這條線的周圍韧衣,這樣一會兒訓(xùn)練的時候看看計算出來的權(quán)重參數(shù)是不是接近這條線的權(quán)重參數(shù)盅藻。
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
num_points = 1000
vectors_set = []
for i in range(num_points):
x1 = np.random.normal(0.0, 0.55)
y1 = x1 * 0.1 + 0.3 + np.random.normal(0.0, 0.03)
vectors_set.append([x1, y1])
# 生成一些樣本
x_data = [v[0] for v in vectors_set]
y_data = [v[1] for v in vectors_set]
plt.scatter(x_data,y_data,c='r')
plt.show()
代碼解釋:
vectors_set這個是用來裝我們造的數(shù)據(jù),也就是那些隨機點的坐標(biāo)畅铭。x1是我們的橫坐標(biāo)氏淑,指定范圍是0.0到0.55,y1是我們的縱坐標(biāo)硕噩,要利用x1來求出y1假残,這就是那個方程y=0.1x+0.3。y1后面又加了一個np.random.normal(0.0, 0.03)炉擅,這樣做的目的就是為了讓這些點有個幅動的范圍辉懒,然后把x1,y1存到vectors_set這里。x_data就是所有的橫坐標(biāo)谍失,y_data就是所有的縱坐標(biāo)眶俩。我們來看一下代碼運行之后的結(jié)果
這便是我們生成的數(shù)據(jù)集,這里面有1000個點快鱼,是圍繞著方程y=0.1x+0.3的一個幅動仿便,幅動范圍不是很大。那么我們能不能根據(jù)這些點得到y(tǒng)=wx+b中的w和b呢攒巍?
2)線性回歸器
接下來我們要根據(jù)這些數(shù)據(jù)訓(xùn)練出一個線性回歸器,然后它可以幫我們求出w和b荒勇。
基本操作流程:
首先隨機初始化w和b柒莉,然后根據(jù)x_data可以得到一個預(yù)測值,有了預(yù)測值我們可以和真實值y_data進行一個比較沽翔,得到loss值(損失值)兢孝,最后再利用梯度下降法去優(yōu)化參數(shù)窿凤,最小化loss值。
我們用tensorflow實現(xiàn)一下上面的操作流程
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W')
b = tf.Variable(tf.zeros([1]), name='b')
y = W * x_data + b
loss = tf.reduce_mean(tf.square(y - y_data), name='loss')
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss, name='train')
代碼解釋:
生成1維的W矩陣跨蟹,取值是[-1,1]之間的隨機數(shù)雳殊,生成1維的b矩陣,初始值是0窗轩, 經(jīng)過計算得出預(yù)估值y夯秃。以預(yù)估值y和實際值y_data之間的均方誤差作為損失值(loss值)。optimizer是定義了一個梯度下降的優(yōu)化器痢艺,里面?zhèn)魅氲膮?shù)0.5是學(xué)習(xí)率仓洼。train是訓(xùn)練過程,采用梯度下降法來優(yōu)化參數(shù)堤舒,使loss值最小色建。
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
print ("W =", sess.run(W), "b =", sess.run(b),"lossess.run(b)s =", sess.run(loss))
for step in range(20):
sess.run(train)
print ("W =", sess.run(W), "b =", sess.run(b), "loss =", sess.run(loss))
代碼解釋:
流程定義好之后就要開辟一個可計算的區(qū)域,然后全局變量初始化舌缤,最后再session中run一下箕戳。然后我們打印一些日志信息,并且迭代20次
我們來看一下最終的運行結(jié)果
W = [-0.72371006] b = [0.] loss= 0.30402443
W = [-0.467951] b = [0.3085696] loss = 0.099842414
W = [-0.29404098] b = [0.30557194] loss = 0.048583176
W = [-0.17329207] b = [0.30353367] loss = 0.023872528
W = [-0.08945438] b = [0.30211845] loss = 0.011960209
W = [-0.03124467] b = [0.30113584] loss = 0.0062176106
W = [0.00917115] b = [0.30045357] loss = 0.003449263
W = [0.03723244] b = [0.2999799] loss = 0.0021147195
W = [0.05671579] b = [0.299651] loss = 0.0014713728
W = [0.07024335] b = [0.29942265] loss = 0.0011612334
W = [0.07963573] b = [0.2992641] loss = 0.0010117239
W = [0.08615699] b = [0.299154] loss = 0.00093964936
W = [0.0906848] b = [0.2990776] loss = 0.00090490433
W = [0.09382852] b = [0.29902452] loss = 0.0008881546
W = [0.09601125] b = [0.2989877] loss = 0.00088008004
W = [0.09752675] b = [0.2989621] loss = 0.0008761875
W = [0.09857899] b = [0.29894432] loss = 0.0008743111
W = [0.09930957] b = [0.298932] loss = 0.00087340653
W = [0.09981682] b = [0.29892343] loss = 0.0008729704
W = [0.10016902] b = [0.2989175] loss = 0.0008727602
W = [0.10041355] b = [0.29891336] loss = 0.00087265886
看一下結(jié)果国撵,我們發(fā)現(xiàn)陵吸,W一開始就是一個隨機的值,b是0卸留,隨著迭代的次數(shù)增加走越,不斷的訓(xùn)練,loss值在變小耻瑟,w和b在不斷的接近真實值旨指。我們的方程是y=0.1x+0.3,w的真實值是0.1喳整,b的真實值是0.3谆构。我們發(fā)現(xiàn)經(jīng)過20次迭代之后,w的值是0.10041355框都,b的值是0.29891336搬素,很接近真實值了。
我們把訓(xùn)練出來的這條線畫出來看看是否擬合這些數(shù)據(jù)點
plt.scatter(x_data,y_data,c='r')
plt.plot(x_data,sess.run(W)*x_data+sess.run(b))
plt.show()
運行結(jié)果如下:
這條線還是很擬合我們的數(shù)據(jù)點的
1.2.3 用tensorflow做邏輯回歸
接下來我們可以對Mnist數(shù)據(jù)集進行分類魏保,分類算法我們采用邏輯回歸算法熬尺。
1)導(dǎo)入工具包并下載數(shù)據(jù)集
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
mnist = input_data.read_data_sets('data/', one_hot=True)
2)設(shè)置參數(shù)
numClasses = 10
inputSize = 784
trainingIterations = 50000
batchSize = 64
邏輯回歸是個分類算法,所以我們的參數(shù)得包含類別數(shù)numClasses谓罗,這是輸出粱哼;然后還要有輸入,輸入是圖片檩咱,所以圖片的大小inputSize揭措;迭代次數(shù)trainingIterations胯舷;每次迭代的圖片數(shù)量batchSize
3)指定x和y的大小
X = tf.placeholder(tf.float32, shape = [None, inputSize])
y = tf.placeholder(tf.float32, shape = [None, numClasses])
X是輸入,y是標(biāo)簽绊含。這里指定成placeholder的格式桑嘶,因為我們訓(xùn)練是一個batch一個batch訓(xùn)練,這些數(shù)據(jù)的格式是定下來的躬充,不會改變的逃顶。這樣方便我們的計算。這里的shape是指維度的大小麻裳,也就是坑的大小口蝠,None值暫時我們認(rèn)為它是無限多,就是可以傳入任意數(shù)量的數(shù)據(jù)津坑,這里可以寫batch的大小妙蔗,也就是64,也可以寫None疆瑰,總之只要把數(shù)據(jù)的大小固定住了就行眉反。
4)參數(shù)初始化
W1 = tf.Variable(tf.random_normal([inputSize, numClasses], stddev=0.1))
B1 = tf.Variable(tf.constant(0.1), [numClasses])
這里還是隨機初始化參數(shù),我們來推導(dǎo)一下W1的維度是怎么計算出來的穆役。輸入數(shù)據(jù)的維度是(64784)寸五,輸出類別的維度是(6410),輸入數(shù)據(jù)乘以權(quán)重參數(shù)W1可以得到輸出類別耿币,那么反推W1的維度應(yīng)該是(784*10)梳杏,也就是inputSize和numClasses相乘。B1是偏置參數(shù)淹接,所有的偏置參數(shù)和輸出結(jié)果的維度是一致的十性,我們指定B1為一個常數(shù)。
5)構(gòu)造模型
y_pred = tf.nn.softmax(tf.matmul(X, W1) + B1)
loss = tf.reduce_mean(tf.square(y - y_pred))
opt = tf.train.GradientDescentOptimizer(learning_rate = .05).minimize(loss)
預(yù)測值y_pred是指每個類別的概率值塑悼,有了預(yù)測值之后就可以計算loss值劲适,我們希望預(yù)測值跟真實值越接近越好,也就是讓loss值越小越好厢蒜。計算出loss值再用梯度下降法優(yōu)化參數(shù)霞势,讓loss值最小。這些過程是類似的斑鸦。
然后我們想打印一個結(jié)果愕贡,就是訓(xùn)練和測試的時候的準(zhǔn)確度是多少
correct_prediction = tf.equal(tf.argmax(y_pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
這里直接拿預(yù)測值和真實值做對比,預(yù)測值是y_pred巷屿,真實值是y固以。tf.argmax(y_pred,1)的意思是從y_pred矩陣中找出最大的那個預(yù)測概率。y_pred是一個包含十個預(yù)測概率值的向量攒庵,然后通過tf.argmax函數(shù)可以找到組內(nèi)最大的預(yù)測概率值嘴纺。這樣我們就可以對比預(yù)測值和真實值是否相等。統(tǒng)計預(yù)測值與真實值相等的個數(shù)浓冒,再除以總數(shù)就會得到精度accuracy
操作都聲明好了栽渴,接下來要開辟一個可計算的區(qū)域,全局初始化稳懒,再run一下闲擦。
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
6)迭代計算
for i in range(trainingIterations):
batch = mnist.train.next_batch(batchSize)
batchInput = batch[0]
batchLabels = batch[1]
_, trainingLoss = sess.run([opt, loss], feed_dict={X: batchInput, y: batchLabels})
if i%1000 == 0:
train_accuracy = accuracy.eval(session=sess, feed_dict={X: batchInput, y: batchLabels})
print ("step %d, training accuracy %g"%(i, train_accuracy))
代碼解釋:
我們要迭代50000次,首先要取出batch個數(shù)據(jù)场梆,通過mnist自帶的函數(shù)我們可以取出batch個數(shù)據(jù)墅冷, batchInput 相當(dāng)于x,batchLabels相當(dāng)于y或油。batchInput 的大小是(64784)寞忿,batchLabels的大小是(6410)。然后是判斷顶岸,整千次我們才打印腔彰。如果是整千次,我們就計算一下精度值辖佣,而精度值的需要預(yù)測值和真實值霹抛,所以還要把batchInput和batchLabels作為參數(shù)傳進去。
我們來看一下最終的運行結(jié)果
step 0, training accuracy 0.0625
step 1000, training accuracy 0.546875
step 2000, training accuracy 0.703125
step 3000, training accuracy 0.796875
step 4000, training accuracy 0.6875
step 5000, training accuracy 0.84375
step 6000, training accuracy 0.875
step 7000, training accuracy 0.890625
step 8000, training accuracy 0.84375
step 9000, training accuracy 0.90625
step 10000, training accuracy 0.828125
step 11000, training accuracy 0.859375
step 12000, training accuracy 0.859375
step 13000, training accuracy 0.8125
step 14000, training accuracy 0.921875
step 15000, training accuracy 0.921875
step 16000, training accuracy 0.9375
step 17000, training accuracy 0.859375
step 18000, training accuracy 0.890625
step 19000, training accuracy 0.921875
step 20000, training accuracy 0.890625
step 21000, training accuracy 0.953125
step 22000, training accuracy 0.859375
step 23000, training accuracy 0.921875
step 24000, training accuracy 0.9375
step 25000, training accuracy 0.9375
step 26000, training accuracy 0.96875
step 27000, training accuracy 0.8125
step 28000, training accuracy 0.859375
step 29000, training accuracy 0.9375
step 30000, training accuracy 0.875
step 31000, training accuracy 0.90625
step 32000, training accuracy 0.9375
step 33000, training accuracy 0.921875
step 34000, training accuracy 0.90625
step 35000, training accuracy 0.9375
step 36000, training accuracy 0.96875
step 37000, training accuracy 0.9375
step 38000, training accuracy 0.90625
step 39000, training accuracy 0.921875
step 40000, training accuracy 0.90625
step 41000, training accuracy 0.9375
step 42000, training accuracy 0.9375
step 43000, training accuracy 0.890625
step 44000, training accuracy 0.890625
step 45000, training accuracy 0.921875
step 46000, training accuracy 0.953125
step 47000, training accuracy 0.90625
step 48000, training accuracy 0.8125
step 49000, training accuracy 0.953125
可以發(fā)現(xiàn)最終迭代了50000次卷谈,精度在不斷的提升杯拐,模型的效果在提升,最終精度可以達到0.95世蔗。
7)測試結(jié)果
然后我們用測試數(shù)據(jù)集進行一個測試端逼,看看模型的效果究竟如何
batch = mnist.test.next_batch(batchSize)
testAccuracy = sess.run(accuracy, feed_dict={X: batch[0], y: batch[1]})
print ("test accuracy %g"%(testAccuracy))
代碼解釋:
還是調(diào)用mnist自帶的函數(shù),這里是mnist.test凸郑,之前訓(xùn)練的時候我們調(diào)用的是mnist.train裳食。然后我們來看一下運行結(jié)果
test accuracy 0.9375
測試的精度是0.9375,效果還是不錯的
1.2.4 神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)
1.2.4.1 單層神經(jīng)網(wǎng)絡(luò)
1)導(dǎo)入mnist數(shù)據(jù)集
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("data/", one_hot=True)
首先來看一下我們的任務(wù)是什么芙沥。
我們的任務(wù)就是把圖片(28281)輸入到神經(jīng)網(wǎng)絡(luò)中诲祸,最終得到十個類別的預(yù)測概率值,這就是一個很簡單的分類任務(wù)而昨。那么怎么構(gòu)造神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)呢救氯?
神經(jīng)網(wǎng)路與邏輯回歸相比不同之處在于多了兩個特點,一個是層次結(jié)構(gòu)歌憨,一個是非線性(激活函數(shù))着憨。看下圖务嫡,我們拿一張圖作為輸入舉例甲抖。
第一步先把向量輸入到隱藏層中漆改,意思就是讓特征進行一個什么樣的組合變換更好,把這784個特征按照什么樣的組合方式映射成多少個特征准谚。因此輸入層和隱藏層之間就是權(quán)重參數(shù)矩陣挫剑,隱藏層的作用就是對原始特征進行的一個變換,變換之后其分辨識別能力更強柱衔,接下來做分類樊破。
簡單地說神經(jīng)網(wǎng)絡(luò)就是幫我們做了一個特征提取的工作,利用梯度下降尋找到一個合適的中間特征唆铐,然后按照這種方式去構(gòu)造我們的特征哲戚,這樣便構(gòu)造出了神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。它就相當(dāng)于一個黑盒子艾岂,幫助我們?nèi)ハ胧裁礃拥奶卣魈崛》绞剿成伲趺唇M合好這些特征,組合成什么樣最可取澳盐。
對照上圖我們來用代碼展示一下
2)參數(shù)設(shè)置
numClasses = 10
inputSize = 784
numHiddenUnits = 50
trainingIterations = 10000
batchSize = 100
numClasses是指類別數(shù)祈纯,一共十個類別;inputSize是輸入數(shù)據(jù)的大械鸢摇腕窥;numHiddenUnits是隱藏層神經(jīng)元的個數(shù)(也就是把784個像素點映射成50個新的特征);trainingIterations是指迭代次數(shù)筛婉,我們設(shè)置為10000次簇爆;batchSize是指一次迭代的圖片數(shù)目。
X = tf.placeholder(tf.float32, shape = [None, inputSize])
y = tf.placeholder(tf.float32, shape = [None, numClasses])
X是我們的輸入數(shù)據(jù)爽撒,y是我們的輸出標(biāo)簽入蛆。依舊是先占一個坑。
3)參數(shù)初始化
W1 = tf.Variable(tf.truncated_normal([inputSize, numHiddenUnits], stddev=0.1))
B1 = tf.Variable(tf.constant(0.1), [numHiddenUnits])
W2 = tf.Variable(tf.truncated_normal([numHiddenUnits, numClasses], stddev=0.1))
B2 = tf.Variable(tf.constant(0.1), [numClasses])
我們發(fā)現(xiàn)神經(jīng)網(wǎng)絡(luò)比邏輯回歸多了一個隱層硕勿,所以權(quán)重參數(shù)也就多了哨毁。W1和輸入相連,輸入有784個像素點源武,然后W1又與隱藏層相連扼褪,隱藏層有50個神經(jīng)元,所以W1的維度是(78450)粱栖。B1和輸出的維度是一致的话浇,對于輸入層而言,輸出就是隱藏層闹究,它是有50個特征幔崖,所以B1的維度就是50。W2和隱藏層相連,它有50個特征赏寇,然后W2又與輸出層相連吉嫩,輸出層是十個類別,所以W2的維度就是(5010)嗅定。輸出是10個類別率挣,所以B2的維度是10。
4)網(wǎng)絡(luò)結(jié)構(gòu)
hiddenLayerOutput = tf.matmul(X, W1) + B1
hiddenLayerOutput = tf.nn.relu(hiddenLayerOutput)
finalOutput = tf.matmul(hiddenLayerOutput, W2) + B2
finalOutput = tf.nn.relu(finalOutput)
參數(shù)初始化完之后就是定義神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)露戒,隱層的輸出hiddenLayerOutput 是W1X+B1,這樣還沒結(jié)束捶箱,前面有講過智什,神經(jīng)網(wǎng)絡(luò)有兩個特征,一個是層次結(jié)構(gòu)丁屎,另一個就是非線性荠锭,怎么才能表達出非線性呢,還要加一個激活函數(shù)(relu函數(shù))晨川。所以hiddenLayerOutput = tf.nn.relu(hiddenLayerOutput)
最終的輸出finalOutput 是W2hiddenLayerOutput+B2证九,同理也要加一個激活函數(shù)。這樣便得到了最終的輸出值共虑。
5)網(wǎng)絡(luò)迭代
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y, logits = finalOutput))
opt = tf.train.GradientDescentOptimizer(learning_rate = .1).minimize(loss)
計算loss值用到了一個交叉熵函數(shù)愧怜,它可以用來衡量兩個數(shù)據(jù)的相似性,里面?zhèn)魅氲膮?shù)就是真實標(biāo)簽y妈拌,以及我們的預(yù)測標(biāo)簽finalOutput拥坛。然后用梯度下降法去優(yōu)化我們的權(quán)重參數(shù),最小化loss值即可尘分。
correct_prediction = tf.equal(tf.argmax(finalOutput,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
這里和邏輯回歸一樣猜惋,計算精度
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
for i in range(trainingIterations):
batch = mnist.train.next_batch(batchSize)
batchInput = batch[0]
batchLabels = batch[1]
_, trainingLoss = sess.run([opt, loss], feed_dict={X: batchInput, y: batchLabels})
if i%1000 == 0:
trainAccuracy = accuracy.eval(session=sess, feed_dict={X: batchInput, y: batchLabels})
print ("step %d, training accuracy %g"%(i, trainAccuracy))
然后就是老套路了,開辟一個可計算的區(qū)域培愁,進行一個全局變量的初始化著摔,然后再run一下,打印一些日志信息定续,和上面的邏輯回歸操作類似
我們看一下運行的結(jié)果
step 0, training accuracy 0.13
step 1000, training accuracy 0.79
step 2000, training accuracy 0.83
step 3000, training accuracy 0.88
step 4000, training accuracy 0.91
step 5000, training accuracy 0.87
step 6000, training accuracy 0.89
step 7000, training accuracy 0.84
step 8000, training accuracy 0.89
step 9000, training accuracy 1
隨著迭代的進行谍咆,我們的精度值在提升。神經(jīng)網(wǎng)絡(luò)的效果會比邏輯回歸的好很多香罐,因為多了一個非線性以及層次的結(jié)構(gòu)卧波,這會提升它的分類效果。
我們前面做的是單層的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)庇茫,正常我們會設(shè)置多層港粱,因為多層的效果好。畢竟神經(jīng)網(wǎng)絡(luò)做的是一個特征提取的工作,里面的層次越多查坪,它提取的特征就越細(xì)化寸宏,這個特征就越有代表性,所以要設(shè)置多層偿曙。當(dāng)然凡事過猶不及氮凝,設(shè)置過多的層會導(dǎo)致過擬合,反而效果不好望忆,所以要設(shè)置適當(dāng)?shù)碾[藏層數(shù)罩阵。那么我們就以兩個隱藏層舉例,看看如何操作
1.2.4.2 雙層神經(jīng)網(wǎng)絡(luò)
操作的順序是一樣的
1)參數(shù)設(shè)置
numClasses = 10
inputSize = 784
numHiddenUnits = 50
numHiddenUnitsLayer2 = 100
trainingIterations = 10000
batchSize = 100
X = tf.placeholder(tf.float32, shape = [None, inputSize])
y = tf.placeholder(tf.float32, shape = [None, numClasses])
參數(shù)的設(shè)置多了一個隱藏層启摄,也就是這里有兩個隱藏層稿壁,numHiddenUnits和numHiddenUnitsLayer2
2)參數(shù)的初始化
W1 = tf.Variable(tf.random_normal([inputSize, numHiddenUnits], stddev=0.1))
B1 = tf.Variable(tf.constant(0.1), [numHiddenUnits])
W2 = tf.Variable(tf.random_normal([numHiddenUnits, numHiddenUnitsLayer2], stddev=0.1))
B2 = tf.Variable(tf.constant(0.1), [numHiddenUnitsLayer2])
W3 = tf.Variable(tf.random_normal([numHiddenUnitsLayer2, numClasses], stddev=0.1))
B3 = tf.Variable(tf.constant(0.1), [numClasses])
多了一個隱藏層,自然也就多了一組權(quán)重參數(shù)W3和B3
3)網(wǎng)絡(luò)結(jié)構(gòu)
hiddenLayerOutput = tf.matmul(X, W1) + B1
hiddenLayerOutput = tf.nn.relu(hiddenLayerOutput)
hiddenLayer2Output = tf.matmul(hiddenLayerOutput, W2) + B2
hiddenLayer2Output = tf.nn.relu(hiddenLayer2Output)
finalOutput = tf.matmul(hiddenLayer2Output, W3) + B3
這里面也發(fā)生了變化歉备,不過道理是一樣的
4)網(wǎng)絡(luò)迭代
這里和單層的神經(jīng)網(wǎng)絡(luò)是一樣的
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y, logits = finalOutput))
opt = tf.train.GradientDescentOptimizer(learning_rate = .1).minimize(loss)
correct_prediction = tf.equal(tf.argmax(finalOutput,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
for i in range(trainingIterations):
batch = mnist.train.next_batch(batchSize)
batchInput = batch[0]
batchLabels = batch[1]
_, trainingLoss = sess.run([opt, loss], feed_dict={X: batchInput, y: batchLabels})
if i%1000 == 0:
train_accuracy = accuracy.eval(session=sess, feed_dict={X: batchInput, y: batchLabels})
print ("step %d, training accuracy %g"%(i, train_accuracy))
testInputs = mnist.test.images
testLabels = mnist.test.labels
acc = accuracy.eval(session=sess, feed_dict = {X: testInputs, y: testLabels})
print("testing accuracy: {}".format(acc))
運行結(jié)果:
step 0, training accuracy 0.1
step 1000, training accuracy 0.97
step 2000, training accuracy 0.98
step 3000, training accuracy 1
step 4000, training accuracy 0.99
step 5000, training accuracy 1
step 6000, training accuracy 0.99
step 7000, training accuracy 1
step 8000, training accuracy 0.99
step 9000, training accuracy 1
testing accuracy: 0.9700999855995178
我們發(fā)現(xiàn)傅是,效果的確比單層的要好,迭代3000次就已經(jīng)達到很好的效果了蕾羊。無論你設(shè)置多少隱層喧笔,萬變不離其宗,只需修改一下參數(shù)的設(shè)置以及網(wǎng)絡(luò)結(jié)構(gòu)即可龟再。
1.3 總結(jié)
本案例主要目的就是讓大家學(xué)會使用tensorflow书闸,了解它的規(guī)則,然后再用最簡單的案例讓大家深入理解這里面的套路利凑,以便駕馭后面復(fù)雜模型的構(gòu)建梗劫。也粗略的講述了神經(jīng)網(wǎng)絡(luò)的構(gòu)建流程以及原理,沒有那些可怕的數(shù)學(xué)公式截碴。如果大家想要更加深入地去理解神將網(wǎng)絡(luò)梳侨,可以去看一些算法參考書籍,看完之后再回到本案例日丹,相信你會有更大的成長走哺。
以下是我所有文章的目錄,大家如果感興趣哲虾,也可以前往查看
??戳右邊:打開它丙躏,也許會看到很多對你有幫助的文章