tensorflow框架學習 兩個簡單的神經網絡示例,迴歸與分類

 

1、迴歸神經網絡

一、神經網絡結構

定義一個簡單的迴歸神經網絡結構:html

  • 數據集爲(xi,yi),數據的特徵數爲1,因此x的維度爲1。
  • 輸入層1個神經元。
  • 隱藏層數爲1,4個神經元。
  • 輸出層1個神經元。
  • 隱藏層的激活函數爲f(x)=x,輸出層的激活函數爲ReLU

結構圖以下:python

 

 

二、代碼示例

相關函數說明:git

  • tf.random_normal :用於生成正太分佈隨機數矩陣的tensor,tensorFlow有不少隨機數函數,能夠查找官方文檔得到。
  • tf.zeros :用於生成0矩陣的tensor,tf.ones能夠用來得到單位矩陣。
  • tf.nn.relu :tensorflow定義的用來實現ReLU激活函數的方法。
  • tf.reduce_sum :求和函數,經過axis來控制在哪一個方向上求和,axis=[0]表示按行求和,axis=[1]表示按列求和。
  • tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) :梯度降低優化函數,learning_rate表示學習率,minimize表示最小化,loss是優化的損失函數。tensorFlow有不少優化函數,能夠查找官方文檔得到。

 

代碼:數組

複製代碼

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# 建立數據訓練數據集,
x_data = np.linspace(-1, 1, 500).reshape(500, 1)
noise = np.random.normal(0, 0.05, [500, 1])  # 製做噪音
y_data = np.square(x_data) + 0.5 + noise

# 建立佔位符用於minibatch的梯度降低訓練,建議數據類型使用tf.float3二、tf.float64等浮點型數據
x_in = tf.placeholder(tf.float32, [None, 1])
y_in = tf.placeholder(tf.float32, [None, 1])


# 定義一個添加層的函數
def add_layer(input_, in_size, out_size, activation_funtion=None):
    '''
    :param input_: 輸入的tensor
    :param in_size: 輸入的維度,即上一層的神經元個數
    :param out_size: 輸出的維度,即當前層的神經元個數即當前層的
    :param activation_funtion: 激活函數
    :return: 返回一個tensor
    '''
    weight = tf.Variable(tf.random_normal([in_size, out_size]))  # 權重,隨機的in_size*out_size大小的權重矩陣
    biase = tf.Variable(tf.zeros([1, out_size]) + 0.01)  # 偏置,1*out_size大小的0.01矩陣,不用0矩陣避免計算出錯
    if not activation_funtion:  # 根據是否有激活函數決定輸出
        output = tf.matmul(input_, weight) + biase
    else:
        output = activation_funtion(tf.matmul(input_, weight) + biase)
    return output


# 定義隱藏層,輸入爲原始數據,特徵爲1,因此輸入爲1個神經元,輸出爲4個神經元
layer1 = add_layer(x_in, 1, 4, tf.nn.relu)

# 定義輸出層,輸入爲layer1返回的tensor,輸入爲4個神經元,輸出爲1個神經元,激活函數爲ReLU
predict = add_layer(layer1, 4, 1)

# 定義損失函數
loss = tf.reduce_mean(tf.reduce_sum(tf.square(y_in - predict), axis=[1]))  # tf.reduce_sum的axis=[1]表示按列求和

# 定義訓練的優化方式爲梯度降低
train = tf.train.GradientDescentOptimizer(0.1).minimize(loss)  # 學習率爲0.1

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    # 訓練1000次
    for step in range(1000):
        # 執行訓練,由於有佔位符因此要傳入字典,佔位符的好處是能夠用來作minibatch訓練,這裏數據量小,直接傳入所有數據來訓練
        sess.run(train, feed_dict={x_in: x_data, y_in: y_data})
        # 每50步輸出一次loss
        if step % 49 == 0:
            print(sess.run(loss, feed_dict={x_in: x_data, y_in: y_data}))

    # 最後畫出實際的散點圖與擬合的折線圖進行對比
    predict_value = sess.run(predict, feed_dict={x_in: x_data})  # 先要得到預測值
    plt.figure()
    plt.scatter(x_data, y_data, c='r', marker='o')
    plt.plot(x_data, predict_value, '--', lw=2, c='b')
    plt.show()

複製代碼

 

 

2、分類神經網絡——mnist手寫字數據

一、網絡結構與數據來源

數據的詳細說明請查看:tensorflow中文社區網絡

結構說明:

  • 數據集(xi,yi):數據共有60000張圖。其中xi是表示的是每個圖片的數據,長度爲28x28 = 784,即一張圖片特徵爲784列;yi有0-9共10種結果,因爲是分類,因此使用softmax函數,則yi最後對應的輸出層須要有10個神經元對應,有幾個類就有幾個神經元。
  • 隱藏層:個數爲0,定義隱藏層擬合效果較差,因此這裏不定義。
  • 輸出層:爲10個神經元,激活函數爲softmax。
  • 損失函數loss:交叉熵損失函數。(交叉熵損失請查閱:詳解機器學習中的熵、條件熵、相對熵和交叉熵
  • 迭代方法:因爲數據集過大,使用minbtach方法。
  • 準確度的計算 :tensorflow中文社區中有詳細說明。

 

二、代碼示例

相關函數說明:

  • input_data.read_data_sets(train_dir='MNIST_data',one_hot=True) :函數做用說明,讀取數據,代碼會自動下載數據(若網絡緣由可自行下載),下載的是數據文件夾,在當前工做目錄下,裏面包含訓練集mnist.train(包含特徵mnist.train.images與標籤mnist.train.labels)與測試集mnist.test(包含特徵mnist.test.images與標籤mnist.test.labels)。參數說明,train_dir:數據相對路徑,one_hot:是否爲獨熱編碼。mnist.train.next_batch。dom

  • tf.argmax(input,dimension) :返回input張量的最大值所在的位置,dimension=1爲列最大。
  • tf.equal(x,y) :返回一個bool數組,當x==y則值爲True。
  • mnist.train.next_batch(batch_size) :用來獲取mnist每批次的數據,每次使用會自動獲取下一批batch_size大小的數據集。機器學習

代碼:

複製代碼

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# 讀取數據,代碼會自動下載數據,下載的是數據文件夾,在當前工做目錄下,裏面包含訓練集與測試集,train_dir:數據路徑,one_hot:是否爲獨熱編碼。
mnist = input_data.read_data_sets(train_dir='MNIST_data', one_hot=True)

# 數據較大,所以用minbatch,batch_size每一個批次的數據個數,batch_num爲批次個數
batch_size = 1000
batch_num = mnist.train.num_examples // batch_size

# 建立佔位符用於minibatch的梯度降低訓練,建議數據類型使用tf.float3二、tf.float64等浮點型數據
x_in = tf.placeholder(tf.float32, [None, 784])
y_in = tf.placeholder(tf.float32, [None, 10])


# 定義一個添加層的函數
def add_layer(input_, in_size, out_size, activation_funtion=None):
    '''
    :param input_: 輸入的tensor
    :param in_size: 輸入的維度,即上一層的神經元個數
    :param out_size: 輸出的維度,即當前層的神經元個數即當前層的
    :param activation_funtion: 激活函數
    :return: 返回一個tensor
    '''
    weight = tf.Variable(tf.random_normal([in_size, out_size]))  # 權重,隨機的in_size*out_size大小的權重矩陣
    biase = tf.Variable(tf.zeros([1, out_size]) + 0.01)  # 偏置,1*out_size大小的0.01矩陣,不用0矩陣避免計算出錯
    if not activation_funtion:  # 根據是否有激活函數決定輸出
        output = tf.matmul(input_, weight) + biase
    else:
        output = activation_funtion(tf.matmul(input_, weight) + biase)
    return output


# 定義輸出層,輸入爲layer1返回的tensor,輸入爲784個神經元,輸出爲10個神經元,激活函數爲softmax。
prediction = add_layer(x_in, 784, 10)  # 這個對應下一步定義交叉熵損失函數的method1,不須要激活函數softmax

# 定義交叉熵損失函數,這裏用method1
# method1:用自帶的函數,這個函數會自動對prediction進行softmax操做因此不須要前面定義prediction不須要激活函數
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

# #method2:手動計算,這裏tf.clip_by_value函數的做用是爲了不輸入爲負數或者0,log函數的定義域是大於0的,不這麼作會出現LOSS=NAN且模型準確度不變的狀況,這個坑會在代碼示例後面說明。
# cross_entropy = -tf.reduce_sum(y_in * tf.log(tf.clip_by_value(prediction,1e-8,1.0)))


# 定義訓練的優化方式爲梯度降低
train = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)  # 學習率爲0.1

# 準確度,先獲得bool型的數組correct_prediction ,再計算值爲True的平均值即爲準確率
correct_prediction = tf.equal(tf.argmax(y_in, 1), tf.argmax(prediction, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    # 訓練20代
    for epoch in range(20):
        # 每代對數據進行一輪minibatch
        for batch in range(batch_num):
            batch_x, batch_y = mnist.train.next_batch(batch_size)  # 每一個循環讀取batch_size大小批次的數據
            sess.run(train, feed_dict={x_in: batch_x, y_in: batch_y})

            acc = sess.run(accuracy, feed_dict={x_in: mnist.test.images, y_in: mnist.test.labels})  # 用測試數據計算準確度
            print('第%d代%d批次,準確率爲%.6f' % (epoch + 1, batch + 1, acc))

複製代碼

 

三、 使用交叉商的坑

第一個坑:

使用method1計算較差熵時,定義prediction不能有激活函數tf.nn.softmax,由於tf.nn.softmax_cross_entropy_with_logits函數會自動對prediction進行softmax處理,因此正確的代碼以下:函數

複製代碼

#定義輸出層
prediction = add_layer(x_in, 784, 10)  

#定義交叉熵
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

複製代碼

能夠嘗試使用method1計算交叉熵,並定義prediction的時候傳入激活函數,會發現擬合效果變差,代碼以下學習

複製代碼

#定義輸出層
prediction = add_layer(x_in, 784, 10, tf.nn.softmax)  

#定義交叉熵
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

複製代碼

 

第二個坑:

先來看一下,當使用method2手動計算交叉熵時,不使用tf.clip_by_value時候的代碼的時候運行是什麼樣子的,代碼修改以下:測試

#method2:手動計算,這裏tf.clip_by_value函數的做用是爲了不輸入爲負數或者0,log函數的定義域是大於0的,不這麼作會出現LOSS=NAN且模型準確度不變的狀況,這個坑會在代碼示例後面說明。
cross_entropy = -tf.reduce_sum(y_in * tf.log(prediction))

運行結果爲:

複製代碼

C:\Users\EDZ\PycharmProjects\DY\Scripts\python.exe C:/Users/EDZ/.PyCharm2019.1/config/scratches/tf.py
Extracting MNIST_data\train-images-idx3-ubyte.gz
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
第1代1批次,準確率爲0.098000
第1代2批次,準確率爲0.098000
第1代3批次,準確率爲0.098000
第1代4批次,準確率爲0.098000
第1代5批次,準確率爲0.098000
第1代6批次,準確率爲0.098000
第1代7批次,準確率爲0.098000

複製代碼

能夠看出準確率徹底沒有變化,準確率沒有變化說明cross_entropy沒有變,沒有進行訓練,因而輸出每次迭代cross_entropy的值,代碼修改以下:

# print('第%d代%d批次,準確率爲%.6f' % (epoch + 1, batch + 1, acc))
            loss = sess.run(cross_entropy, feed_dict={x_in: mnist.test.images, y_in: mnist.test.labels})
            print('第%d代%d批次,loss爲%.6f' % (epoch + 1, batch + 1, loss))

運行結果爲:

複製代碼

C:\Users\EDZ\PycharmProjects\DY\Scripts\python.exe C:/Users/EDZ/.PyCharm2019.1/config/scratches/tf.py
Extracting MNIST_data\train-images-idx3-ubyte.gz
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
第1代1批次,loss爲nan
第1代2批次,loss爲nan
第1代3批次,loss爲nan
第1代4批次,loss爲nan
第1代5批次,loss爲nan
第1代6批次,loss爲nan
第1代7批次,loss爲nan

複製代碼

出現這樣的結果是由於,log函數的定義域是x>0,可是傳入的數據predicttion可能含有0或者負數,此時就會出現計算結果爲NAN的狀況,爲了不這個狀況就須要用到tf.clip_by_value函數將數據限制在0-1之間,下面是這個函數的介紹:

tf.clip_by_value(t,clip_value_min,clip_value_max,name=None)

  • tTensor or IndexedSlices.
  • clip_value_min: A 0-D (scalar) Tensor, or a Tensor with the same shape as t. The minimum value to clip by.
  • clip_value_max: A 0-D (scalar) Tensor, or a Tensor with the same shape as t. The maximum value to clip by.
  • name: A name for the operation (optional).

做用:截斷tensor數據的值,讓數據的值在區間 [clip_value_min , clip_value_max] 內。若tensor的值value<clip_value_min,則返回value=clip_value_min;若clip_value_min<=value<=clip_value_max,則返回value;若clip_value_max<value,則返回clip_value_max。

相關文章
相關標籤/搜索