簡單的TensorFlow分類教程

TensorFlow分類教程

本篇文章有2個topic剂桥,簡單的分類器和TensorFlow凯旭。首先,我們會編寫函數(shù)生成三種類別的模擬數(shù)據(jù)芥喇。第一組數(shù)據(jù)是線性可分的西采,第二種是數(shù)據(jù)是月牙形數(shù)據(jù)咬合在一起,第三種是土星環(huán)形數(shù)據(jù)继控。每組數(shù)據(jù)有兩個類型械馆,我們將分別建立模型,對每組數(shù)據(jù)分類武通。
本文的所有代碼在ML-tutorial.

線性可分的數(shù)據(jù)如下:

linear data

月牙形的數(shù)據(jù)如下:

moon data

環(huán)形數(shù)據(jù)如下:

saturn data

很明顯霹崎,第一組數(shù)據(jù)只需要一條直線(高維數(shù)據(jù)為超平面)即可滿足分類需求,所以后面我們會建立一個SoftMax回歸分類模型冶忱。第二組數(shù)據(jù)不可能被一條直線或一個超平面劃分尾菇,同樣,如果用直線劃分第三組數(shù)據(jù)囚枪,最好可以獲得50%的正確率派诬。針對第二組數(shù)據(jù)和第三組數(shù)據(jù)我們使用簡單的神經(jīng)網(wǎng)絡(luò)模型學(xué)習(xí)超曲面來劃分不同的數(shù)據(jù)類別。TensorFlow的使用方法會在建立三個模型的過程中引入链沼,減小學(xué)習(xí)的阻力默赂。

生成模擬數(shù)據(jù)

生成模擬數(shù)據(jù)集的方法很簡單,利用正弦括勺、圓等方程產(chǎn)生有規(guī)律的數(shù)據(jù)缆八,然后加入一些隨機(jī)擾動模擬噪音。所有函數(shù)只用到了Numpy疾捍。例如奈辰,generate_Saturn_data()方法,首先使用np.linspace()方法產(chǎn)生角度變化拾氓,然后確定圓心冯挎,之后生成兩個范圍的半徑底哥,分別用于生成內(nèi)核數(shù)據(jù)和外部的環(huán)形數(shù)據(jù)咙鞍,形狀就像土星和他的衛(wèi)星帶房官。代碼如下:

def generate_Saturn_data(N=100):
    theta = np.linspace(0, 2*PI, N) + PI*(np.random.rand(N))/100
    a = 0.5
    b = 0.5
    r1 = 0.4 + 2*(np.random.rand(N)-0.5)/10
    x1 = a + r1*np.cos(theta) + (np.random.rand(N)-0.5)/50
    y1 = b + r1*np.sin(theta) + (np.random.rand(N)-0.5)/50
    r2 = 0.2*np.random.rand(N)
    x2 = a + r2*np.cos(theta) + (np.random.rand(N)-0.5)/50
    y2 = b + r2*np.sin(theta) + (np.random.rand(N)-0.5)/50
    return x1, y1, x2, y2

代碼中,x1和y1構(gòu)成了第一種類別的樣本续滋,x2翰守、y2是第二種類別的樣本。所以疲酌,把(x1, y1)的標(biāo)簽標(biāo)注為0蜡峰,(x2, y2)的標(biāo)簽標(biāo)注為1,即id為0的類別和id為1的類別朗恳。01只是現(xiàn)實(shí)世界中某兩個關(guān)聯(lián)的類別的代表湿颅,例如人。注意粥诫,參數(shù)N是每個類別的樣本數(shù)油航。
gen_data()方法負(fù)責(zé)把上面生成的模擬數(shù)據(jù)組裝成訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集,每個樣本的標(biāo)注采用了TensorFlow支持的One-Hot編碼格式怀浆。例如谊囚,第一種類別的數(shù)據(jù)樣本(x1, y1)的標(biāo)注應(yīng)該是(1, 0),而第二種類別的數(shù)據(jù)樣本(x2, y2)的標(biāo)注應(yīng)該是(0, 1)执赡。為了滿足隨機(jī)梯度下降的特點(diǎn)镰踏,在gen_data()方法內(nèi)部還對數(shù)據(jù)進(jìn)行了重新隨機(jī)排列,同時也考慮到了每個類別的樣本數(shù)量沙合。

線性模型

對于線性可分的數(shù)據(jù)奠伪,只需要SoftMax回歸模型就可以應(yīng)付。

tf.reset_default_graph()
x = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='samples')
y = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='labels')

W = tf.Variable(tf.zeros(shape=(2,2)), name='weight')
b = tf.Variable(tf.zeros(shape=(2)), name='bias')

pred = tf.nn.softmax(tf.matmul(x, W) + b, name='pred')

上面代碼中首先對TensorFlow的graph進(jìn)行了重置首懈,防止環(huán)境中有沖突的graph芳来。也可以實(shí)例化新的graph,然后綁定到后面的session上猜拾,但我們這里堅(jiān)持使用默認(rèn)的graph即舌。
模型的輸入是xy,均為tf.placeholder類型挎袜,相當(dāng)于占位符顽聂,只在訓(xùn)練或推理(只需要x)的時候,真正綁定具體的輸入盯仪。x表示輸入的樣本紊搪,注意每個樣本有兩個數(shù)值,因此xshape[None, 2]全景。同理耀石,樣本只有兩種類型,因此one-hot編碼后的標(biāo)注y也是shape[None, 2]的Tensor爸黄。
接下來滞伟,Wb是模型的參數(shù)揭鳞,經(jīng)過訓(xùn)練,不斷修正梆奈。這類型的數(shù)據(jù)野崇,在TensorFlow中為tf.Variable類型,同時也給定了Wb的初始化方法亩钟,即全部初始化為0.0乓梨。這里,需要特別注意清酥,使用0.0初始化權(quán)重是有風(fēng)險的扶镀,很容易使模型陷于某個非最優(yōu)的鞍點(diǎn),導(dǎo)致無法優(yōu)化模型焰轻。典型的特點(diǎn)是狈惫,不管訓(xùn)練多少輪,loss只在最初有下降鹦马,訓(xùn)練一定輪數(shù)后就無法繼續(xù)下降胧谈。正確率很低,但卻不再提升荸频,一種過擬合的狀態(tài)菱肖。如下圖:
正確率曲線:

accuracy1

loss曲線:
cost1

通常,這個時候最有效但很容易被忽略的的方法可能就是改變初始化方法旭从,例如使用隨機(jī)正態(tài)初始化tf.random_normal()稳强。當(dāng)然,改變激活函數(shù)和悦、loss函數(shù)退疫、權(quán)重更新策略、學(xué)習(xí)率等都可能會產(chǎn)生作用鸽素。本文建立的所有模型褒繁,你都可以自己嘗試修改一些地方,看看能不能得到更高的正確率馍忽、更快的學(xué)習(xí)速度棒坏。不要害怕出錯,盡管試驗(yàn)遭笋,你會學(xué)到一些無法傳授的知識坝冕,這些知識只能通過實(shí)踐產(chǎn)生,所謂實(shí)踐出真知吧瓦呼。下面的accuracy曲線和loss曲線就是修改了初始化方法后的效果喂窟。

accuracy2
cost2

設(shè)定好模型結(jié)構(gòu)之后,還需要設(shè)計(jì)損失函數(shù)和優(yōu)化方法。損失函數(shù)直接定義了模型的學(xué)習(xí)目標(biāo)磨澡,設(shè)置的恰當(dāng)合理碗啄,有助于提升學(xué)習(xí)速度和正確率,這很大一部分取決于我們對整個問題的理解和學(xué)習(xí)過程的把握钱贯。鑒于這只是一組簡單的線性數(shù)據(jù),使用均方差和隨機(jī)梯度下降就可以了侦另。注意秩命,我們的第一個問題全局只有一個最優(yōu)解,所以只要學(xué)習(xí)時間夠長褒傅,總是可以得到很高(甚至100%)的正確率弃锐。有兩個概念要解釋一下,下面代碼中的epochstep殿托。因?yàn)橐M(jìn)行隨機(jī)梯度下降霹菊,我們需要不斷迭代,把整個訓(xùn)練集的樣本分成多個step支竹,逐個送入模型計(jì)算誤差和梯度旋廷、更新權(quán)重。每個epoch完畢礼搁,正好訓(xùn)練集的所有樣本被迭代一遍饶碘。

# for train
cost = tf.reduce_mean(tf.square(y-pred))
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train = optimizer.minimize(cost)
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accurary = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
init_op = tf.global_variables_initializer()

saver = tf.train.Saver()
with tf.Session() as sess:
    tf.summary.scalar('cost', cost)
    tf.summary.histogram('weight', W)
    tf.summary.scalar('accurary', accurary)
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter('./log/linear_model/train', sess.graph)
    test_writer = tf.summary.FileWriter('./log/linear_model/test', sess.graph)
    sess.run(init_op)
    x_train, y_train = data_linear['train_set']
    x_test, y_test = data_linear['test_set']
    num_samples = len(x_train)
    for epoch in range(epochs):
        steps = int(num_samples / batch_size)
        indices = np.random.permutation(num_samples)
        x_train_ = x_train[indices]
        y_train_ = y_train[indices]
        for step in range(steps):
            start = step*batch_size
            end = start + batch_size
            x_ = x_train_[start:end,:]
            y_ = y_train_[start:end,:]
            summary, _, c = sess.run([merged, train, cost], feed_dict={x:x_, y:y_})
            train_writer.add_summary(summary)
        if epoch%100 == 99:
            summary, acc = sess.run([merged, accurary], feed_dict={x:x_test, y:y_test})
            test_writer.add_summary(summary, epoch)
            print("Epoch:{:5d}, Accurary:{:.2f}".format(epoch, acc))
    print('W:', W.eval())
    print('b:', b.eval())
    train_writer.close()
    test_writer.close()
    print("Training Finished!")
    save_path = saver.save(sess, './log/linear_model/linear_model.ckpt')
    print('model saved in path: ', save_path)

為了使用TensorBoard可視化學(xué)習(xí)過程,例如監(jiān)控Accuracy的變化馒吴、loss的變化扎运。TensorFlow和TensorBoard為開發(fā)者提供了很多功能。使用方法是

  1. 實(shí)例化tf.summary.FileWriter()
  2. 把需要監(jiān)控的參數(shù)加入到隊(duì)列中饮戳,標(biāo)量用tf.summary.scalar豪治,張量用tf.summary.histogram
  3. 合并所有監(jiān)控的結(jié)點(diǎn)到graph上,建立依賴關(guān)系merged = tf.summary.merge_all()
  4. 調(diào)用filewriter的add_summary()
  5. 在terminal中啟動tensorboard tensorboard --logdir=...

最終扯罐,可以在瀏覽器中看到上面的曲線了负拟。
訓(xùn)練之后,可視化模型的決策結(jié)果

linear

參數(shù)Wb的值如下:(你如果動手做一下歹河,結(jié)果會有些變動齿椅,因?yàn)閿?shù)據(jù)是隨機(jī)的,初始化也是隨機(jī)的启泣,但樣本的整體面貌不會有大的改變涣脚,所以最后的參數(shù)也會相近)
WB

可以看到,我們最后學(xué)到的其實(shí)是一條直線寥茫。

類多項(xiàng)式模型

一個簡單的兩個隱藏層的神經(jīng)網(wǎng)絡(luò)分類器模型遣蚀,第一層隱層有32個神經(jīng)元,激活函數(shù)為tanh,第二個隱層有8個神經(jīng)元芭梯,激活函數(shù)同樣為tanh险耀。
接下來的損失函數(shù)采用了交叉熵函數(shù)。

x = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='samples')
y = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='labels')

W1 = tf.Variable(tf.random_normal(shape=(2,32), mean=0.0, stddev=1), name='weight1')
b1 = tf.Variable(tf.zeros(shape=[32]), name='bias1')
W2 = tf.Variable(tf.random_normal(shape=(32,8)), name='weight2')
b2 = tf.Variable(tf.zeros(shape=[8]), name='bias2')
W3 = tf.Variable(tf.random_normal(shape=(8,2)), name='weight3')
b3 = tf.Variable(tf.zeros(shape=[2]), name='bias3')
z = tf.matmul(x, W1) + b1
layer1 = tf.tanh(z, name='layer1')
z = tf.matmul(layer1, W2) + b2
layer2 = tf.tanh(z, name='layer2')
out = tf.matmul(layer2, W3) + b3
pred = tf.nn.softmax(out, name='pred')
# for train
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=out))
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train = optimizer.minimize(cost)
# for test
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accurary = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

最后玖喘,模型的分類效果大致如下:

moon

類圓模型

第三組數(shù)據(jù)是環(huán)形數(shù)據(jù)甩牺,為了得到一個類圓的分類邊界,我們需要增加神經(jīng)網(wǎng)絡(luò)的隱藏層數(shù)量累奈,一個有四個隱藏層的神經(jīng)網(wǎng)絡(luò)分類器贬派。

x = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='samples')
y = tf.placeholder(dtype=tf.float32, shape=(None, 2), name='labels')

W1 = tf.Variable(tf.random_normal(shape=(2,3), mean=0.0, stddev=1), name='weight1')
b1 = tf.Variable(tf.zeros(shape=(3)), name='bias1')
W2 = tf.Variable(tf.random_normal(shape=(3,6)), name='weight2')
b2 = tf.Variable(tf.zeros(shape=(6)), name='bias2')
W3 = tf.Variable(tf.random_normal(shape=(6,9)), name='weight3')
b3 = tf.Variable(tf.zeros(shape=(9)), name='bias3')
W4 = tf.Variable(tf.random_normal(shape=(9,2)), name='weight4')
b4 = tf.Variable(tf.zeros(shape=(2)), name='bias4')
z = tf.matmul(x, W1) + b1
# layer1 = tf.nn.relu(z, name='layer1')
# layer1 = tf.tanh(z, name='layer1')
layer1 = tf.tanh(z, name='layer1')
z = tf.matmul(layer1, W2) + b2
layer2 = tf.tanh(z, name='layer2')
z = tf.matmul(layer2, W3) + b3
layer3 = tf.tanh(z, name='layer3')
out = tf.matmul(layer3, W4) + b4
pred = tf.nn.softmax(out, name='pred')
# for train
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=out))
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train = optimizer.minimize(cost)
# for test
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accurary = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

最后,分類結(jié)果如下:

saturn2

當(dāng)然澎媒,建模過程肯定不是一帆風(fēng)順的搞乏,往往需要我們根據(jù)學(xué)習(xí)過程不斷調(diào)試模型的結(jié)構(gòu)和超參數(shù)的設(shè)定。例如戒努,一不小心就學(xué)習(xí)到了下面的結(jié)果请敦。。储玫。


saturn1

不要灰心侍筛,保持前進(jìn)的勇氣,這就是深度學(xué)習(xí)撒穷。

參考:
Simple end-to-end TensorFlow examples
Implementing a Neural Network from Scratch in Python – An Introduction
Implementing a Neural Network from Scratch in Python - Source Code

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勾笆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子桥滨,更是在濱河造成了極大的恐慌窝爪,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齐媒,死亡現(xiàn)場離奇詭異蒲每,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)喻括,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門邀杏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唬血,你說我怎么就攤上這事望蜡。” “怎么了拷恨?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵脖律,是天一觀的道長。 經(jīng)常有香客問我腕侄,道長小泉,這世上最難降的妖魔是什么芦疏? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮微姊,結(jié)果婚禮上酸茴,老公的妹妹穿的比我還像新娘。我一直安慰自己兢交,他們只是感情好薪捍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著配喳,像睡著了一般酪穿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上界逛,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天昆稿,我揣著相機(jī)與錄音纺座,去河邊找鬼息拜。 笑死,一個胖子當(dāng)著我的面吹牛净响,可吹牛的內(nèi)容都是我干的少欺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼馋贤,長吁一口氣:“原來是場噩夢啊……” “哼赞别!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起配乓,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤仿滔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犹芹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崎页,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年腰埂,在試婚紗的時候發(fā)現(xiàn)自己被綠了飒焦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡屿笼,死狀恐怖牺荠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驴一,我是刑警寧澤休雌,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站肝断,受9級特大地震影響挑辆,放射性物質(zhì)發(fā)生泄漏例朱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一鱼蝉、第九天 我趴在偏房一處隱蔽的房頂上張望洒嗤。 院中可真熱鬧,春花似錦魁亦、人聲如沸渔隶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽间唉。三九已至,卻和暖如春利术,著一層夾襖步出監(jiān)牢的瞬間呈野,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工印叁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留被冒,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓轮蜕,卻偏偏與公主長得像昨悼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子跃洛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容