使用TensorFlow實現二分類的方法示例

這篇文章主要介紹了使用TensorFlow實現二分類的方法示例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

使用TensorFlow構建一個神經網絡來實現二分類,主要包括輸入數據格式、隱藏層數的定義、損失函數的選擇、優化函數的選擇、輸出層。下面通過numpy來隨機生成一組數據,通過定義一種正負樣本的區別,通過TensorFlow來構造一個神經網絡來實現二分類。

一、神經網絡結構

輸入數據:定義輸入一個二維數組(x1,x2),數據通過numpy來隨機產生,將輸出定義爲0或1,如果x1+x2<1,則y爲1,否則y爲0。

隱藏層:定義兩層隱藏層,隱藏層的參數爲(2,3),兩行三列的矩陣,輸入數據通過隱藏層之後,輸出的數據爲(1,3),t通過矩陣之間的乘法運算可以獲得輸出數據。

損失函數:使用交叉熵作爲神經網絡的損失函數,常用的損失函數還有平方差。

優化函數:通過優化函數來使得損失函數最小化,這裏採用的是Adadelta算法進行優化,常用的還有梯度下降算法。

輸出數據:將隱藏層的輸出數據通過(3,1)的參數,輸出一個一維向量,值的大小爲0或1。

二、TensorFlow代碼的實現

import tensorflow as tf
from numpy.random import RandomState
 
if __name__ == "__main__":
  #定義每次訓練數據batch的大小爲8,防止內存溢出
  batch_size = 8
  #定義神經網絡的參數
  w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
  w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
  #定義輸入和輸出
  x = tf.placeholder(tf.float32,shape=(None,2),name="x-input")
  y_ = tf.placeholder(tf.float32,shape=(None,1),name="y-input")
  #定義神經網絡的前向傳播過程
  a = tf.matmul(x,w1)
  y = tf.matmul(a,w2)
  #定義損失函數和反向傳播算法
  #使用交叉熵作爲損失函數
  #tf.clip_by_value(t, clip_value_min, clip_value_max,name=None)
  #基於min和max對張量t進行截斷操作,爲了應對梯度爆發或者梯度消失的情況
  cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-10,1.0)))
  # 使用Adadelta算法作爲優化函數,來保證預測值與實際值之間交叉熵最小
  train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
  #通過隨機函數生成一個模擬數據集
  rdm = RandomState(1)
  # 定義數據集的大小
  dataset_size = 128
  # 模擬輸入是一個二維數組
  X = rdm.rand(dataset_size,2)
  #定義輸出值,將x1+x2 < 1的輸入數據定義爲正樣本
  Y = [[int(x1+x2 < 1)] for (x1,x2) in X]
  #創建會話運行TensorFlow程序
  with tf.Session() as sess:
    #初始化變量 tf.initialize_all_variables()
    init = tf.initialize_all_variables()
    sess.run(init)
    #設置神經網絡的迭代次數
    steps = 5000
    for i in range(steps):
      #每次選取batch_size個樣本進行訓練
      start = (i * batch_size) % dataset_size
      end = min(start + batch_size,dataset_size)
      #通過選取樣本訓練神經網絡並更新參數
      sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
      #每迭代1000次輸出一次日誌信息
      if i % 1000 == 0 :
        # 計算所有數據的交叉熵
        total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y})
        # 輸出交叉熵之和
        print("After %d training step(s),cross entropy on all data is %g"%(i,total_cross_entropy))
    #輸出參數w1
    print(w1.eval(session=sess))
    #輸出參數w2
    print(w2.eval(session=sess))
    '''
    After 0 training step(s),cross entropy on all data is 0.0674925
    After 1000 training step(s),cross entropy on all data is 0.0163385
    After 2000 training step(s),cross entropy on all data is 0.00907547
    After 3000 training step(s),cross entropy on all data is 0.00714436
    After 4000 training step(s),cross entropy on all data is 0.00578471
    [[-1.96182752 2.58235407 1.68203771]
     [-3.46817183 1.06982315 2.11788988]]
    [[-1.82471502]
     [ 2.68546653]
     [ 1.41819501]]
    '''

上面的TensorFlow二分類我是參考Google深度學習框架,al_kk評論說這個損失函數的定義存在問題,之前沒有仔細的去考慮這個問題,al_kk提醒之後,我發現這個損失函數的定義的確存在問題,經過測試發現這個模型也存在一些問題。其實,我們的主要目的是想去學習一個x1+x2=1的直線,來區分0和1兩類不同的類別,下面我對這個模型進行了一些修改並說明一下爲什麼這個損失函數的定義存在問題。

一、爲什麼說這個損失函數的定義存在問題呢?

上面程序中定義的輸入的y的shape爲[1],也就是y的類別爲0或1,對於單分類問題交叉熵損失函數的定義應該爲

其中n爲y的種類,在上面的例子中需要包含0和1的y_*log(y)(y_表示真實類別,y表示預測類別),而上面的例子中只包含了一個y_*log(y),在上例中正確的損失函數定義應該爲loss = y_*log(y) + (1-y_) * log(1-y)。爲了便於大家理解,我引用al_kk:“如果只有一個類別的交叉熵即y_ * log(y),如果真實類別y_爲0,那麼無論預測值y爲任何值的時候,損失函數始終爲0”。除此之外,大家可以想一下,當預測值始終爲1的時候,那麼損失函數是不是就會一直爲0,這也是爲什麼輸出預測值y的時候,y的值都是大於1的。如果將y的shape改爲[2]的話,就可以使用y_*log(y)。

二、修改之後的二分類程序

import tensorflow as tf
import numpy as np
from numpy.random import RandomState
import matplotlib.pyplot as plt
 
if __name__ == "__main__":
  #定義神經網絡的參數
  w = tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
  b = tf.Variable(tf.random_normal([1],stddev=1,seed=1))
  #定義輸入和輸出
  x = tf.placeholder(tf.float32,shape=(None,2),name="x-input")
  y_ = tf.placeholder(tf.float32,shape=(None,1),name="y-input")
  #定義神經網絡的前向傳播過程
  y = tf.nn.sigmoid(tf.matmul(x,w) + b)
  #基於min和max對張量t進行截斷操作,爲了應對梯度爆發或者梯度消失的情況
  cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y,1e-10,1.0))+(1-y_) * tf.log(tf.clip_by_value(1-y,1e-10,1.0)))
  # 使用Adadelta算法作爲優化函數,來保證預測值與實際值之間交叉熵最小
  train_step = tf.train.AdamOptimizer(0.01).minimize(cross_entropy)
  #通過隨機函數生成一個模擬數據集
  rdm = RandomState(1)
  # 定義數據集的大小
  dataset_size = 100
  # 模擬輸入是一個二維數組
  X = rdm.rand(dataset_size,2)
  #定義輸出值,將x1+x2 < 1的輸入數據定義爲正樣本
  Y = [[int(x1+x2 < 1)] for (x1,x2) in X]
  #創建會話運行TensorFlow程序
  with tf.Session() as sess:
    #初始化變量 tf.initialize_all_variables()
    init = tf.initialize_all_variables()
    sess.run(init)
    #設置神經網絡的迭代次數
    steps = 500
    for i in range(steps):
      #通過選取樣本訓練神經網絡並更新參數
      for (input_x,input_y) in zip(X,Y):
        input_x = np.reshape(input_x,(1,2))
        input_y = np.reshape(input_y,(1,1))
        sess.run(train_step,feed_dict={x:input_x,y_:input_y})
      #每迭代1000次輸出一次日誌信息
      if i % 100 == 0:
        # 計算所有數據的交叉熵
        total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y})
        # 輸出交叉熵之和
        print("After %d training step(s),cross entropy on all data is %g"%(i,total_cross_entropy))
    #預測輸入X的類別
    pred_Y = sess.run(y,feed_dict={x:X})
    index = 1
    for pred,real in zip(pred_Y,Y):
      print(pred,real)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章