深度學習2--tensorflow--Softmax迴歸實現手寫數字識別
使用Softmax迴歸來實現手寫數字識別,即給定一張手寫數字,判斷屬於0--9中哪一個數字。
1.LR邏輯迴歸
先準備一下LR邏輯迴歸:
廣義線性模型:實現x到y的非線性對映:
在LR邏輯迴歸中取g函式:實現0--1對映 輸出值為 預測結果為1的概率
線性模型wx+b:
令h(x)表示結果為1的概率:
極大對數似然:
損失函式:
隨機梯度下降:
2.Softmax迴歸
softmax屬於多分類問題,多分類問題符合多項分佈。可用於解決多分類問題,像決策樹、樸素貝葉斯等。
首先證明多項分佈屬於指數分佈族,這樣就可以使用廣義線性模型來擬合這個多項分佈,由廣義線性模型推匯出的目標函式
2.1指數分佈族:
η被稱為分佈的自然引數(也稱為規範引數);T(y)是充分統計量(對於我們所考慮的分佈,通常情況下有T(y)=y);a(η)被稱為對數劃分函式。這一項本質上是起到了正則化常數的作用,確保了分佈p(y;η)的總和或是積分在y到1上。
2.2證明多項分佈屬於指數分佈族
多分類模型的輸出結果為該樣本屬於k個類別的概率,從這k個概率中我們選擇最優的概率對應的類別(通常選概率最大的類別),作為該樣本的預測類別。這k個概率用k個變數,…,表示。這個k變數和為1,即滿足:
可以用前k-1個變數來表示,即:
使用廣義線性模型
在這裡,統計分量T(y)並沒有像之前那樣定義為T(y)=y,因為T(y)不是一個數值,而是一個k-1維的向量。使用符號表示向量T(y)的第i個元素。在這裡引入一個新符號:,如果括號內為true則這個符號取1,反之取0,即,。所以,T(y)與y的關係就可以表示為
與關係為:
即:
多項分佈表示式轉化為指數分佈族表示式過程如下:
其中:
變換過程:
第一步:取值為,…,中的一個,取決於y的取值。當y=i時,這一步可以理解為
第二步:消去
第三步:根據
第四、五步:轉換為廣義線性模型的表達格式。
2.3softmax函式表示式推導
多項分佈表示式可以表示為指數分佈族表示式的格式,所以它屬於指數分佈族,那麼就可以用廣義線性模型來擬合這個多項式分佈模型。
由η表示式可得:
這是關於的表示式,把它轉化為關於的表示式過程為:
為了方便,令,那麼
因為:
所以:
這個關於的的函式稱為Softmax函式(Softmax Function)
2.4Softmax迴歸以及求解:
訓練集 x0=1對應學習模型的截距
將x分類為j的概率為:
令h(x):
代價函式:
梯度下降求解:
Softmax 迴歸有一個特點:它有一個“冗餘”的引數集。如果引數 是代價函式 的極小值點,那麼 同樣也是它的極小值點,其中 可以為任意向量。因此使 最小化的解不是唯一的。
證明如下:
權重衰減:
權重衰減項以後 (),代價函式就變成了嚴格的凸函式,這樣就可以保證得到唯一的解。 此時的 Hessian矩陣變為可逆矩陣,並且因為是凸函式,梯度下降法和 L-BFGS 等演算法可以保證收斂到全域性最優解。
梯度下降公式:
3.tensorflow實現softmax迴歸
手寫字型資料集的載入:
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
從MNIST_data目錄下載入訓練集,如果不存在則下載訓練集。
讀取資料集程式碼如下:
最終返回資料集格式:
data_sets.train |
55000 組 圖片和標籤, 用於訓練 |
data_sets.validation |
5000 組 圖片和標籤, 用於迭代驗證訓練的準確性 |
data_sets.test |
10000 組 圖片和標籤, 用於最終測試訓練的準確性 |
def read_data_sets(train_dir, fake_data=False, one_hot=False):
class DataSets(object):
#python裡pass用來佔位
pass
data_sets = DataSets()
if fake_data:
data_sets.train = DataSet([], [], fake_data=True)
data_sets.validation = DataSet([], [], fake_data=True)
data_sets.test = DataSet([], [], fake_data=True)
return data_sets
TRAIN_IMAGES = 'train-images-idx3-ubyte.gz'
TRAIN_LABELS = 'train-labels-idx1-ubyte.gz'
TEST_IMAGES = 't10k-images-idx3-ubyte.gz'
TEST_LABELS = 't10k-labels-idx1-ubyte.gz'
VALIDATION_SIZE = 5000
local_file = maybe_download(TRAIN_IMAGES, train_dir)
train_images = extract_images(local_file)
local_file = maybe_download(TRAIN_LABELS, train_dir)
train_labels = extract_labels(local_file, one_hot=one_hot)
local_file = maybe_download(TEST_IMAGES, train_dir)
test_images = extract_images(local_file)
local_file = maybe_download(TEST_LABELS, train_dir)
test_labels = extract_labels(local_file, one_hot=one_hot)
validation_images = train_images[:VALIDATION_SIZE]
validation_labels = train_labels[:VALIDATION_SIZE]
train_images = train_images[VALIDATION_SIZE:]
train_labels = train_labels[VALIDATION_SIZE:]
data_sets.train = DataSet(train_images, train_labels)
data_sets.validation = DataSet(validation_images, validation_labels)
data_sets.test = DataSet(test_images, test_labels)
return data_sets
從指定目錄下尋找資料集,如果不存在則下載:
def maybe_download(filename, work_directory):
"""Download the data from Yann's website, unless it's already here."""
if not os.path.exists(work_directory):
os.mkdir(work_directory)
filepath = os.path.join(work_directory, filename)
if not os.path.exists(filepath):
filepath, _ = urllib.request.urlretrieve(SOURCE_URL + filename, filepath)
statinfo = os.stat(filepath)
print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
return filepath
如果是圖片,則處理圖片資料
#提取圖片到四維uint8陣列
def extract_images(filename):
"""Extract the images into a 4D uint8 numpy array [index, y, x, depth]."""
print('Extracting', filename)
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2051:
raise ValueError(
'Invalid magic number %d in MNIST image file: %s' %
(magic, filename))
num_images = _read32(bytestream)
rows = _read32(bytestream)
cols = _read32(bytestream)
buf = bytestream.read(rows * cols * num_images)
data = numpy.frombuffer(buf, dtype=numpy.uint8)
data = data.reshape(num_images, rows, cols, 1)
return data
如果是標籤,則處理標籤:數字標籤資料被解壓稱1維的tensor: [image index]
,它定義了每個樣本數值的類別分類
def extract_labels(filename, one_hot=False):
"""Extract the labels into a 1D uint8 numpy array [index]."""
print('Extracting', filename)
with gzip.open(filename) as bytestream:
magic = _read32(bytestream)
if magic != 2049:
raise ValueError(
'Invalid magic number %d in MNIST label file: %s' %
(magic, filename))
num_items = _read32(bytestream)
buf = bytestream.read(num_items)
labels = numpy.frombuffer(buf, dtype=numpy.uint8)
if one_hot:
return dense_to_one_hot(labels)
return labels
函式——read32需要修改如下;numpy.frombuffer返回為一個數組,這裡只需要返回陣列值即可。
def _read32(bytestream):
#採用大尾端儲存
dt = numpy.dtype(numpy.uint32).newbyteorder('>')
#此處需要修改只返回[0]位置結果 numpy.frombuffer函式返回時一個數組
return numpy.frombuffer(bytestream.read(4), dtype=dt)[0]
使用tensorflow程式碼如下:
載入資料集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
構造線性模型 z=wx+b ,預測輸出為y=softmax(z)=softmax(wx+b)
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W)+b)
代價函式使用交叉熵
yi 為預測的分佈 yi`為真實分佈
y = tf.nn.softmax(tf.matmul(x, W)+b)
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
梯度下降演算法來求解最優值
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 18 19:46:33 2018
@author: chen
"""
import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder("float", [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W)+b)
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
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}))
隨機梯度下降訓練:每次選取100樣本執行隨機梯度下降,迭代1000次
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
計算準確率:
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
argmax函式作用:
Returns the index with the largest value across axes of a tensor. (deprecated arguments)
結果correct_prediction為1*10維bool向量,將其轉化為為float求其平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
y為n*10維矩陣,第i行儲存著模型對於第i張圖片的各種類別預測值
y_儲存著第i張圖片的類別真實值
最終結果:準確率約為91%
tensorflow的使用規則得學習一下,直接只需定義變數以及代價函式,可用自帶演算法來執行優化求解真的是牛,以後有機會把演算法求解過程原始碼看一下。
參考地址:
https://www.cnblogs.com/BYRans/p/4905420.html
https://yq.aliyun.com/ziliao/571823
http://www.tensorfly.cn/tfdoc/tutorials/mnist_beginners.html