前言
這幾天caffe2發布了,支持移動端,我理解是類似單片機的物聯網吧應該不是手機之類的,試想iphone7跑CNN,畫面太美~
作為一個剛入坑的,甚至還沒入坑的人,咱們還是老實研究下tensorflow吧,雖然它沒有caffe好上手。tensorflow的特點我就不介紹了:
- 基于Python,寫的很快并且具有可讀性。
- 支持CPU和GPU,在多GPU系統上的運行更為順暢。
- 代碼編譯效率較高。
- 社區發展的非常迅速并且活躍。
- 能夠生成顯示網絡拓撲結構和性能的可視化圖。
tensorflow(tf)運算流程:
tensorflow的運行流程主要有2步,分別是構造模型和訓練。
在構造模型階段,我們需要構建一個圖(Graph)來描述我們的模型,tensoflow的強大之處也在這了,支持tensorboard:
就類似這樣的圖,有點像流程圖,這里還推薦一個google的tensoflow游樂場,很有意思。
然后到了訓練階段,在構造模型階段是不進行計算的,只有在tensoflow.Session.run()
時會開始計算。
先給出代碼,然后我們在一一做解釋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# -*- coding: utf-8 -*- import pandas as pd import numpy as np import tensorflow as tf from collections import Counter from sklearn.datasets import fetch_20newsgroups def get_word_2_index(vocab): word2index = {} for i,word in enumerate (vocab): word2index[word] = i return word2index def get_batch(df,i,batch_size): batches = [] results = [] texts = df.data[i * batch_size : i * batch_size + batch_size] categories = df.target[i * batch_size : i * batch_size + batch_size] for text in texts: layer = np.zeros(total_words,dtype = float ) for word in text.split( ' ' ): layer[word2index[word.lower()]] + = 1 batches.append(layer) for category in categories: y = np.zeros(( 3 ),dtype = float ) if category = = 0 : y[ 0 ] = 1. elif category = = 1 : y[ 1 ] = 1. else : y[ 2 ] = 1. results.append(y) return np.array(batches),np.array(results) def multilayer_perceptron(input_tensor, weights, biases): #hidden層RELU函數激勵 layer_1_multiplication = tf.matmul(input_tensor, weights[ 'h1' ]) layer_1_addition = tf.add(layer_1_multiplication, biases[ 'b1' ]) layer_1 = tf.nn.relu(layer_1_addition) layer_2_multiplication = tf.matmul(layer_1, weights[ 'h2' ]) layer_2_addition = tf.add(layer_2_multiplication, biases[ 'b2' ]) layer_2 = tf.nn.relu(layer_2_addition) # Output layer out_layer_multiplication = tf.matmul(layer_2, weights[ 'out' ]) out_layer_addition = out_layer_multiplication + biases[ 'out' ] return out_layer_addition #main #從sklearn.datas獲取數據 cate = [ "comp.graphics" , "sci.space" , "rec.sport.baseball" ] newsgroups_train = fetch_20newsgroups(subset = 'train' , categories = cate) newsgroups_test = fetch_20newsgroups(subset = 'test' , categories = cate) # 計算訓練和測試數據總數 vocab = Counter() for text in newsgroups_train.data: for word in text.split( ' ' ): vocab[word.lower()] + = 1 for text in newsgroups_test.data: for word in text.split( ' ' ): vocab[word.lower()] + = 1 total_words = len (vocab) word2index = get_word_2_index(vocab) n_hidden_1 = 100 # 一層hidden層神經元個數 n_hidden_2 = 100 # 二層hidden層神經元個數 n_input = total_words n_classes = 3 # graphics, sci.space and baseball 3層輸出層即將文本分為三類 #占位 input_tensor = tf.placeholder(tf.float32,[ None , n_input],name = "input" ) output_tensor = tf.placeholder(tf.float32,[ None , n_classes],name = "output" ) #正態分布存儲權值和偏差值 weights = { 'h1' : tf.Variable(tf.random_normal([n_input, n_hidden_1])), 'h2' : tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])), 'out' : tf.Variable(tf.random_normal([n_hidden_2, n_classes])) } biases = { 'b1' : tf.Variable(tf.random_normal([n_hidden_1])), 'b2' : tf.Variable(tf.random_normal([n_hidden_2])), 'out' : tf.Variable(tf.random_normal([n_classes])) } #初始化 prediction = multilayer_perceptron(input_tensor, weights, biases) # 定義 loss and optimizer 采用softmax函數 # reduce_mean計算平均誤差 loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = prediction, labels = output_tensor)) optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(loss) #初始化所有變量 init = tf.global_variables_initializer() #部署 graph with tf.Session() as sess: sess.run(init) training_epochs = 100 display_step = 5 batch_size = 1000 # Training for epoch in range (training_epochs): avg_cost = 0. total_batch = int ( len (newsgroups_train.data) / batch_size) for i in range (total_batch): batch_x,batch_y = get_batch(newsgroups_train,i,batch_size) c,_ = sess.run([loss,optimizer], feed_dict = {input_tensor: batch_x,output_tensor:batch_y}) # 計算平均損失 avg_cost + = c / total_batch # 每5次epoch展示一次loss if epoch % display_step = = 0 : print ( "Epoch:" , '%d' % (epoch + 1 ), "loss=" , "{:.6f}" . format (avg_cost)) print ( "Finished!" ) # Test model correct_prediction = tf.equal(tf.argmax(prediction, 1 ), tf.argmax(output_tensor, 1 )) # 計算準確率 accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float" )) total_test_data = len (newsgroups_test.target) batch_x_test,batch_y_test = get_batch(newsgroups_test, 0 ,total_test_data) print ( "Accuracy:" , accuracy. eval ({input_tensor: batch_x_test, output_tensor: batch_y_test})) |
代碼解釋
這里我們沒有進行保存模型的操作。按代碼流程,我解釋下各種函數和選型,其實整個代碼是github的已有的,我也是學習學習~
數據獲取,我們從sklearn.datas獲取數據,這里有個20種類的新聞文本,我們根據每個單詞來做分類:
1
2
3
4
5
6
7
8
9
10
11
12
|
# 計算訓練和測試數據總數 vocab = Counter() for text in newsgroups_train.data: for word in text.split( ' ' ): vocab[word.lower()] + = 1 for text in newsgroups_test.data: for word in text.split( ' ' ): vocab[word.lower()] + = 1 total_words = len (vocab) word2index = get_word_2_index(vocab) |
根據每個index轉為one_hot型編碼,One-Hot編碼,又稱為一位有效編碼,主要是采用N位狀態寄存器來對N個狀態進行編碼,每個狀態都由他獨立的寄存器位,并且在任意時候只有一位有效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
def get_batch(df,i,batch_size): batches = [] results = [] texts = df.data[i * batch_size : i * batch_size + batch_size] categories = df.target[i * batch_size : i * batch_size + batch_size] for text in texts: layer = np.zeros(total_words,dtype = float ) for word in text.split( ' ' ): layer[word2index[word.lower()]] + = 1 batches.append(layer) for category in categories: y = np.zeros(( 3 ),dtype = float ) if category = = 0 : y[ 0 ] = 1. elif category = = 1 : y[ 1 ] = 1. else : y[ 2 ] = 1. results.append(y) return np.array(batches),np.array(results) |
在這段代碼中根據自定義的data的數據范圍,即多少個數據進行一次訓練,批處理。在測試模型時,我們將用更大的批處理來提供字典,這就是為什么需要定義一個可變的批處理維度。
構造神經網絡
神經網絡是一個計算模型(一種描述使用機器語言和數學概念的系統的方式)。這些系統是自主學習和被訓練的,而不是明確編程的。下圖是傳統的三層神經網絡:
而在這個神經網絡中我們的hidden層拓展到兩層,這兩層是做的完全相同的事,只是hidden1層的輸出是hidden2的輸入。
1
2
3
4
5
6
7
8
9
10
|
weights = { 'h1' : tf.Variable(tf.random_normal([n_input, n_hidden_1])), 'h2' : tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])), 'out' : tf.Variable(tf.random_normal([n_hidden_2, n_classes])) } biases = { 'b1' : tf.Variable(tf.random_normal([n_hidden_1])), 'b2' : tf.Variable(tf.random_normal([n_hidden_2])), 'out' : tf.Variable(tf.random_normal([n_classes])) } |
在輸入層需要定義第一個隱藏層會有多少節點。這些節點也被稱為特征或神經元,在上面的例子中我們用每一個圓圈表示一個節點。
輸入層的每個節點都對應著數據集中的一個詞(之后我們會看到這是怎么運行的)
每個節點(神經元)乘以一個權重。每個節點都有一個權重值,在訓練階段,神經網絡會調整這些值以產生正確的輸出。
將輸入乘以權重并將值與偏差相加,有點像y = Wx + b 這種linear regression。這些數據也要通過激活函數傳遞。這個激活函數定義了每個節點的最終輸出。有很多激活函數。
- Rectified Linear Unit(RELU) - 用于隱層神經元輸出
- Sigmoid - 用于隱層神經元輸出
- Softmax - 用于多分類神經網絡輸出
- Linear - 用于回歸神經網絡輸出(或二分類問題)
這里我們的hidden層里面使用RELU,之前大多數是傳統的sigmoid系來激活。
由圖可知,導數從0開始很快就又趨近于0了,易造成“梯度消失”現象,而ReLU的導數就不存在這樣的問題。 對比sigmoid類函數主要變化是:1)單側抑制 2)相對寬闊的興奮邊界 3)稀疏激活性。這與人的神經皮層的工作原理接近。
為什么要加入偏移常量?
以sigmoid為例
權重w使得sigmoid函數可以調整其傾斜程度,下面這幅圖是當權重變化時,sigmoid函數圖形的變化情況:
可以看到無論W怎么變化,函數都要經過(0,0.5),但實際情況下,我們可能需要在x接近0時,函數結果為其他值。
當我們改變權重w和偏移量b時,可以為神經元構造多種輸出可能性,這還僅僅是一個神經元,在神經網絡中,千千萬萬個神經元結合就能產生復雜的輸出模式。
輸出層的值也要乘以權重,并我們也要加上誤差,但是現在激活函數不一樣。
你想用分類對每一個文本進行標記,并且這些分類相互獨立(一個文本不能同時屬于兩個分類)。
考慮到這點,你將使用 Softmax 函數而不是 ReLu 激活函數。這個函數把每一個完整的輸出轉換成 0 和 1 之間的值,并且確保所有單元的和等于一。
在這個神經網絡中,output層中明顯是3個神經元,對應著三種分本分類。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#初始化所有變量 init = tf.global_variables_initializer() #部署 graph with tf.Session() as sess: sess.run(init) training_epochs = 100 display_step = 5 batch_size = 1000 # Training for epoch in range (training_epochs): avg_cost = 0. total_batch = int ( len (newsgroups_train.data) / batch_size) for i in range (total_batch): batch_x,batch_y = get_batch(newsgroups_train,i,batch_size) c,_ = sess.run([loss,optimizer], feed_dict = {input_tensor: batch_x,output_tensor:batch_y}) # 計算平均損失 avg_cost + = c / total_batch # 每5次epoch展示一次loss if epoch % display_step = = 0 : print ( "Epoch:" , '%d' % (epoch + 1 ), "loss=" , "{:.6f}" . format (avg_cost)) print ( "Finished!" ) |
這里的 參數設置:
- training_epochs = 100 #100次遞歸訓練
- display_step = 5 # 每5次print 一次當前的loss值
- batch_size = 1000 #訓練數據的分割
為了知道網絡是否正在學習,需要比較一下輸出值(Z)和期望值(expected)。我們要怎么計算這個的不同(損耗)呢?有很多方法去解決這個問題。
因為我們正在進行分類任務,測量損耗的最好的方式是 交叉熵誤差。
通過 TensorFlow 你將使用 tf.nn.softmax_cross_entropy_with_logits()
方法計算交叉熵誤差(這個是 softmax 激活函數)并計算平均誤差 (tf.reduced_mean()
) 。
通過權重和誤差的最佳值,以便最小化輸出誤差(實際得到的值和正確的值之間的區別)。要做到這一點,將需使用 梯度下降法。更具體些是,需要使用 隨機梯度下降。
對應代碼:
1
2
|
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = prediction, labels = output_tensor)) optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(loss) |
tensoflow已經將這些發雜的算法封裝為函數,我們只需要選取特定的函數即可。
tf.train.AdamOptimizer(learning_rate).minimize(loss)
方法是一個 語法糖,它做了兩件事情:
compute_gradients(loss, <list of variables>) 計算
apply_gradients(<list of variables>) 展示
這個方法用新的值更新了所有的 tf.Variables ,因此我們不需要傳遞變量列表。
運行計算
Epoch: 0001 loss= 1133.908114347
Epoch: 0006 loss= 329.093700409
Epoch: 00011 loss= 111.876660109
Epoch: 00016 loss= 72.552971845
Epoch: 00021 loss= 16.673050320
........
Finished!
Accuracy: 0.81
Accuracy: 0.81 表示置信度在81%,我們通過調整參數和增加數據量(本文沒做),置信度會產生變化。
結束
就是這樣!使用神經網絡創建了一個模型來將文本分類到不同的類別中。采用GPU或者采取分布式的TF可以提升訓練速度和效率~
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.jianshu.com/p/f762ab9fe68d