今天我們講一下如何使用Tensorflow實作邏輯回歸,代碼中采用了MNIST資料集。
首先,我們去擷取MNIST資料集(下載下傳連結:http://yann.lecun.com/exdb/mnist/),并将其讀取到程式中。代碼實作如下所示:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('./data/mnist_data/', one_hot=True)
train_img = mnist.train.images
train_label = mnist.train.labels
test_img = mnist.test.images
test_label = mnist.test.labels
我将擷取到的MNIST資料放在了目前目錄下的data/mnist_data檔案夾下,然後利用input_data函數解析該資料集。train_img和train_label構成訓練集,包含60000個手寫體數字圖檔和對應的标簽;test_img和test_label表示測試集,包含10000個樣本和10000個标簽。
根據邏輯回歸的基本公式
,在設計邏輯回歸模型之前,我們先設定模型的輸入和待求變量,代碼如下所示:
x = tf.placeholder("float", [None, 784])
y = tf.placeholder("float", [None, 10])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
其中
是一個placeholder,它用來儲存我們之後喂給模型的手寫體數字圖檔,它的兩個次元中None表示圖檔的數量,784表示每張圖檔的像素個數。第一個次元采用None在Tensorflow裡表示無窮,一開始這樣使用是因為我們還不确定每次給模型喂的資料數量是多少,也友善後面調整其他超參數。
同樣是一個placeholder,它表示圖像的真實分類,因為阿拉伯數字有10個,是以它的第二個次元是10,需要注意的是我們使用了one-hot編碼,也就是說,數字3在這裡會被表示為
。
和
是待求參數,它們再模型的訓練過程中是不斷變化的,是以采用了Variable來實作。
的次元為
,這表示每張圖檔的784個像素都需要被預測到0-9這10個數字上,也就是每個像素都對應一個10為的one-hot向量。而
則表示在這10個數字預測結果上的偏置。
和
可以随機初始化,也可以采用零值初始化,這裡使用零值進行初始化。
下面我們正式建構邏輯回歸模型:
# 邏輯回歸模型
actv = tf.nn.softmax(tf.matmul(x, W) + b)
# 成本函數
cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(actv), reduction_indices=1))
# 優化器
learning_rate = 0.01
optm = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
# 預測結果
pred = tf.equal(tf.argmax(actv, 1), tf.argmax(y, 1))
# 計算準确率
accr = tf.reduce_mean(tf.cast(pred, "float"))
讓我們一行行看這部分代碼,首先
中
就實作了邏輯回歸公式,表示圖檔屬于某一個類别的分數,然後外層我們再使用softmax作為激活函數,将其轉換為每張圖檔屬于10個數字的機率。需要注意的是,多分類任務一般使用softmax作為激活函數,二分類任務采用sigmoid。sotfmax函數将資料進行歸一化處理,使所有資料都在0和1之間,并且求和為1。
再下一行我們定義了成本函數。這裡我們沒有完全依照邏輯回歸的成本函數計算公式,而是使用了較簡易的版本,将每個樣本的損失函數定義為
,其中
表示樣本所屬的真實類别,
表示我們模型的預測類别,然後利用reduce_sum函數将所有樣本的損失函數值相加(注意reduction_indices=1表示将矩陣中的元素按行相加)再取負求平均,就得到了成本函數值。
然後optm使用了梯度下降法來對模型進行拟合,學習率我們設定為0.01,這裡的學習目标是使成本函數值最小。
pred比較了預測結果和實際樣本的類别,這裡使用了argmax擷取了每個向量最大值的索引,因為是one-hot編碼,是以索引也就對應了實際的數字。
最後,accr将比較結果的bool類型變量轉換為float型,再将得到的所有0和1求平均就是模型預測的準确率了。
下面是具體的訓練過程代碼:
init = tf.global_variables_initializer()
training_epochs = 50
batch_size = 100
display_step = 5
sess = tf.Session()
sess.run(init)
for epoch in range(training_epochs):
avg_cost = 0.
num_batch = int(mnist.train.num_examples / batch_size)
for i in range(num_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
feeds_train = {x: batch_xs, y: batch_ys}
sess.run(optm, feed_dict=feeds_train)
avg_cost += sess.run(cost, feed_dict=feeds_train) / num_batch
# 訓練過程輸出
if epoch % display_step == 0:
feeds_test = {x: mnist.test.images, y: mnist.test.labels}
train_acc = sess.run(accr, feed_dict=feeds_train)
test_acc = sess.run(accr, feed_dict=feeds_test)
print("Epoch: %03d/%03d cost: %.9f train_acc: %.3f test_acc: %.3f"
% (epoch, training_epochs, avg_cost, train_acc, test_acc))
print("DONE")
首先,init初始化了所有的變量,training_epochs設定為50表示把所有的樣本疊代50次,batch_size為100表示每個epoch中每次取100個樣本進行訓練,display_step用于輸出訓練過程,這裡設定成每5個epoch輸出一次。
在之後的for循環中,外層的for表示訓練的epoch,在内層for循環之前初始化了avg_cost變量,num_batch計算了每個epoch的batch數量。内層for循環中的batch_xs和batch_ys擷取每個batch的樣本和标簽,然後将其輸入feed_dict來喂給模型,模型訓練需要的一個參數是資料,另外一個就是optm優化器。最後再利用cost函數計算了平均成本函數值。在if條件結構中,我們利用了accr、訓練資料和測試資料計算了模型在訓練集和測試集上的準确率并列印輸出使得我們能夠友善的觀察訓練效果。
這篇文章到這裡就結束了,最後想要說的是實際上有很多人的部落格裡貼出了這份代碼,但是他們都基本沒有對代碼進行解釋,這裡為了幫助新手快速入門,盡可能詳細的解釋了代碼的實作過程。整個解說過程如果有什麼問題,歡迎大家和我交流!