1.1. 邏輯回歸原理
1.1.1. 邏輯回歸
在現實生活中,我們遇到的數據大多數都是非線性的,因此我們不能用上一章線性回歸的方法來進行數據擬合。但是我們仍然可以從線性模型着手開始第一步,首先對輸入的數據進行加權求和。
線性模型:
其中w我們稱為“權重”,b為偏置量(bias),\({x}\)為輸入的樣本數據,三者均為向量的形式。
我們先在二分類中來討論,假如能創建一個模型,如果系統輸出1,我們認為是第一類,如果系統輸出0,我們認為是第二類,這種輸出需求有點像階躍函數(海維塞德階躍函數),但是階躍函數是間斷函數,y的取值在x=0處突然跳躍到1,在實際的建模中,我們很難在模型中處理這種情況,所以我們使用Sigmoid函數來代替階躍函數。
Sigmoid函數:
Sigmoid函數是激活函數其中的一種,當x=0時,函數值為0.5,隨着x的增大,對應的Sigmoid值趨近1,而隨着x的減小,Sigmoid值趨近0。通過這個函數,我們可以得到一系列0—1之間的數值,接着我們就可以把大於0.5的數據分為1類,把小於0.5的數據分為0類。
這種方式等價於是一種概率估計,我們把y看作服從伯努利分布,在給定x條件下,求解每個\(y_i\)為1或0的概率。此時,邏輯回歸這個抽象的名詞,在這里我們把它轉化成了能夠讓人容易理解的概率問題。接着通過最大對數似然函數估計w值,就解決問題了。
\(y_i\)等於1的概率為:$$sigmoid(w{x_i}+b)$$
\(y_i\)等於0的概率為:$$1-sigmoid(w{x_i}+b)$$
以上對Sigmoid函數描述可以看出該函數多用於二分類,而我們會經常遇到多分類問題,這時,Softmax函數的就派上用場了。
Softmax函數:
Softmax函數也是激活函數的一種,主要用於多分類,把輸入的線性模型當成冪指數求值,最后把輸出值歸一化為概率,通過概率來把對象分類,而每個對象之間是不相關的,所有的對象的概率之和為1。對於Softmax函數,如果j=2的話,Softmax和Sigmoid是一樣的,同樣解決的是二分類問題,這時用兩種函數都能進行很好的二分類。
以上公式可以理解為,樣本為類別\(i\)的概率。即:
對於Softmax回歸模型的解釋,在這里引用一下別人的圖,一張圖片就勝過千言萬語。
如果寫成多項式,可以是這樣:
如果換成我們常用的矩陣的形式,可以是這樣:
1.1.2. 損失函數
在線性回歸中,我們定義了一個由和方差組成的損失函數,並使該函數最小化來找到\(\theta\)的最優解。同樣的,在邏輯回歸中我們也需要定義一個函數,通過最小化這個函數來解得我們的權重w值和偏差b值。在機器學習中,這種函數可以看做是表示一個模型的好壞的指標,這種指標可以叫做成本函數(Cost)或損失函數(Loss),然后最小化這兩種函數,這兩種方式都是一樣的。
這里介紹一個常見的損失函數——“交叉熵”,在后面的實例代碼中我們會用到。交叉熵產生於信息論里面的信息壓縮編碼技術,后來慢慢演變成從博弈論到機器學習等其他領域的重要技術,它用來衡量我們的預測用於描述真相的低效性。它的定義如下:
它是怎么推導出來的呢,我們先來討論一下Sigmoid的損失函數,接着再來對比理解。在上面的二分類中問題中,我們使用Sigmoid函數,同時我們也假定預測值\(y_i\)服從伯努利分布,則\(y_i\)等於1的概率為:
\(y_i\)等於0的概率為:
則概率密度函數為:
上式中的\(y_{_{label}}\)是樣本為類別1的實際概率。接着我們取對數似然函數,然后最小化似然函數進行參數估計(這里省略似然函數和一系列文字)。
而我們把問題泛化為多分類時,同樣可以得出我們的概率密度函數:
我們對概率密度取自然對數的負數,就得到了我們的似然函數,即我們這里稱為交叉熵的函數,其中\({y_i}\)是樣本為類別\(i\)的預測概率,\({y_{_{label}}}\)是樣本為類別\(i\)的實際概率。
最后,通過最小化該交叉熵,找出最優的w和b值。
1.2. 實例:手寫識別系統
了解了邏輯回歸的工作原理以后,現在我們用tensorflow來實現一個手寫識別系統。首先我們必須去挖掘一些數據,我們使用現成的MNIST數據集,它是機器學習入門級的數據集,它包含各種手寫數字圖片和每張圖片對應的標簽,即圖片對應的數字(0~9)。你可以通過一段代碼把它下載下來,在下載之前記得安裝python-mnist:
import input_data
mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)
下載下來的數據總共有60000行的訓練數據集(mnist.train),和10000行的測試數據集(mnist.test),同時我們把圖片設為x,x是一個shape=[None,784]的一個張量,None表示任意長度,比如它可以小於或等於mnist.train里面的60000張圖片。另外,每一張圖片包含28像素X28像素,向量長度為28*28=789,表示圖片是由784維向量空間的點組成的。然后,我們把圖片的標簽設為y_張量,shape=[None,10],這個y_的值就是圖片原本對應的標簽(0~9的數字)。
用代碼來表示可以參考:
x = tf.placeholder("float", [None, 784]) # x定義為占位符,待計算圖運行的時候才去讀取數據圖片
W = tf.Variable(tf.zeros([784, 10])) # 權重w初始化為0
b = tf.Variable(tf.zeros([10])) # b也初始化為0
y = tf.nn.softmax(tf.matmul(x, W) + b) # 創建線性模型
y_ = tf.placeholder("float", [None, 10]) # 圖片的實際標簽,為0~9的數字
數據都准備好以后,就開始訓練我們的模型了。之前我們講了Softmax函數,用該函數來做邏輯回歸,我們可以通過這樣的代碼來表示:
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
但是Tensorflow已經實現好了這個Softmax函數,即:tf.nn.softmax_cross_entropy_with_logits()
,而無需我們自己這樣定義(-tf.reduce_sum(y_ * tf.log(y))
)。為什么使用Tensorflow的呢,是因為我們在使用該函數的時候,可能會出現數值不穩定的問題,需要自己在Softmax函數中加一些trick,這樣做起來比較麻煩,又把模型復雜化了,所以我們推薦使用Tensorflow自帶的交叉熵函數,它會幫你處理數值不穩定的問題。
-tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
邏輯回歸確定好各項函數后,我們還是用梯度下降的方式去尋找那個最優的w和b值,最后,整個手寫圖片識別系統的代碼如下:
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
from mnist import MNIST
mndata = MNIST('MNIST_data')
sess = tf.Session()
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.matmul(x, W) + b
y_ = tf.placeholder("float", [None, 10])
# 使用Tensorflow自帶的交叉熵函數
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.global_variables_initializer()
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(500)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
images, labels = mndata.load_testing()
num = 9000
image = images[num]
label = labels[num]
# 打印圖片
print(mndata.display(image))
print('這張圖片的實際數字是: ' + str(label))
# 測試新圖片,並輸出預測值
a = np.array(image).reshape(1, 784)
y = tf.nn.softmax(y) # 為了打印出預測值,我們這里增加一步通過softmax函數處理后來輸出一個向量
result = sess.run(y, feed_dict={x: a}) # result是一個向量,通過索引來判斷圖片數字
print('預測值為:')
print(result)
--result
............................
............................
............................
............................
............................
...............@@@..........
............@@@@@@@.........
...........@@@....@@........
..........@@......@@........
.................@@.........
................@@@.........
..............@@@@..........
............@@@@@@..........
...........@@@@.@@@.........
..................@@........
..................@@........
...................@@.......
...................@@.......
..................@@........
.......@..........@@........
.......@.........@@.........
.......@........@@@.........
.......@@.....@@@...........
........@@@@@@@.............
..........@.................
............................
............................
............................
這張圖片的實際數字是: 3
預測值為:
[[ 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]]
讀者可以通過改變不同的圖片來試試預測的結果,可以看出上面的預測情況還是很不錯的。但是我們模型的性能到底如何,還是需要數據來說話,測試性能的代碼如下:
# 檢測預測和真實標簽的匹配程度
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
# 轉換布爾值為浮點數,並取平均
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
# 計算模型在測試數據集上的正確率
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
--result
0.9022
這個結果真的不怎么樣,不過我們可以通過采用其他算法和模型來改進我們的性能,但這已超過了本節要講的范圍,我們僅需通過本章內容了解邏輯回歸的工作原理就好了。以后我們可以共同探討改進一下,從而進一步提升模型的准確率。
作者:帥蟲哥 出處: hhttp://www.cnblogs.com/vipyoumay/p/7507149.html