1. 程式人生 > >深度學習2--tensorflow--Softmax迴歸實現手寫數字識別

深度學習2--tensorflow--Softmax迴歸實現手寫數字識別

使用Softmax迴歸來實現手寫數字識別,即給定一張手寫數字,判斷屬於0--9中哪一個數字。

1.LR邏輯迴歸

先準備一下LR邏輯迴歸:

廣義線性模型:實現x到y的非線性對映:

在LR邏輯迴歸中取g函式:實現0--1對映  輸出值為  預測結果為1的概率

線性模型wx+b:

令h(x)表示結果為1的概率:

極大對數似然:

損失函式:

隨機梯度下降:

2.Softmax迴歸

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)並沒有像之前那樣定義為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 迴歸有一個特點:它有一個“冗餘”的引數集。如果引數 Softmax迴歸 是代價函式 Softmax迴歸 的極小值點,那麼 Softmax迴歸 同樣也是它的極小值點,其中 Softmax迴歸 可以為任意向量。因此使 Softmax迴歸 最小化的解不是唯一的。

證明如下:

權重衰減:

權重衰減項以後 (Softmax迴歸),代價函式就變成了嚴格的凸函式,這樣就可以保證得到唯一的解。 此時的 Hessian矩陣變為可逆矩陣,並且因為Softmax迴歸是凸函式,梯度下降法和 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

https://blog.csdn.net/qq_31589695/article/details/79936938