1. 程式人生 > >人工智慧學習筆記-TensorFlow(一)

人工智慧學習筆記-TensorFlow(一)

1安裝 TensorFlow

1.1 實驗環境

  • python2.7
  • Tensorflow
  • ubuntu 14.04

1.2 安裝命令

sudo apt-get update
sudo apt-get install python-pip python-dev
#最近開大會,google的網站連結不上去,下面命令會執行失敗
pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.8.0-cp27-none-linux_x86_64.whl

#或者去github上下一份程式碼來自己編譯,這個比較痛苦,編譯需要java8,cmake大於4.6
https://github.com/tensorflow/tensorflow

2 基本使用簡述

2.1 基本概念

  • 使用圖 (graph) 來表示計算任務
  • 在被稱之為 會話 (Session) 的上下文 (context) 中執行圖
  • 使用 tensor 表示資料
  • 通過 變數 (Variable) 維護狀態
  • 使用 feed 和 fetch 可以為任意的操作(arbitrary operation) 賦值或者從其中獲取資料

2.2 簡單計算演示

通過3+4這樣一個最簡單的常量加法運算,來演示tensorflow的計算流程

#這段程式碼描述述了怎麼在tensorflow裡怎麼計算 3+4 這樣一個常量計算
import tensorflow as tf #定義一個常量a為3 a = tf.constant(3.0) #定義一個常量b為4 b = tf.constant(4.0) #定義一個op為常量3+4 c = tf.add(a,b) #以上的程式碼,我們定義了一個常量相加的圖 #啟動一個預設的會話 sess = tf.Session() #用會話來執行我們定義的圖 result = sess.run([c]) print result sess.close()

2.3 傳值計算演示

通過定義a+b這樣一張圖,其中a與b分別是可以被替換的佔位符,在會話運算圖的時候傳入值替換佔位符

#這段程式碼描述了怎麼在tensorflow裡通過傳值來計算 3+4的問題
#首先分別定義可以被替換的op,a與b #然後定義運算a+b #在圖運算op的時候傳值進去 import tensorflow as tf a = tf.placeholder(tf.float32) b = tf.placeholder(tf.float32) c = tf.add(a,b) result = sess.run([c],feed_dict={a:[3.],b[4.]}) print result sess.close()

2.4 變數參與計算演示

通過經過一個變數來計算3+4+5這樣一個運算,首先把3+4計算的值賦給一個變數,然後再將變數與5相加

什麼是變數?
就是在執行的過程中值可以被動態的改變,變數維護圖執行過程中的狀態資訊

#這段程式碼演示怎麼使用變數

import tensorflow as tf
#定義三個相加用的常量:a,b,c
a = tf.constant(3.0)
b = tf.constant(4.0)
c = tf.constant(5.0)
#定義變數v
v = tf.Variable(0.0)
#首先把3與4相加
t = tf.add(a,b)
#把計算得到的t值賦給變數v
update = tf.assign(v,t)
#把變數v的值與5相加
result = tf.add(v,c)
#初始化所有變數的一個操作
init_op = tf.initialize_all_variables()

#啟動一個預設的會話
sess = tf.Session()
#執行初始化變數
sess.run(init_op)
#計算3+4並賦值給變數
sess.run(update)
#變數與5相加
result = sess.run(result)
print result
sess.close()

程式碼中 assign() 操作是圖所描繪的表示式的一部分,正如 add() 操作一樣。所以在呼叫 run() 執行表示式之前,它並不會真正執行賦值操作程式碼中 assign() 操作是圖所描繪的表示式的一部分,正如 add() 操作一樣。所以在呼叫 run() 執行表示式之前,它並不會真正執行賦值操作

2.5 神經網路演示

  1. 定義新增神經層的函式

    (1) 訓練的資料
    (2) 定義節點準備接收資料
    (3) 定義神經層:隱藏層和預測層
    (4) 定義 loss 表示式
    (5) 選擇 optimizer 使 loss 達到最小

  2. 然後對所有變數進行初始化,通過 sess.run optimizer,迭代 1000 次進行學習

程式碼如下所示:

#coding=utf-8

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

#定義神經層
#inputs 輸入資料
#in_size 輸入資料的維度
#out_size 輸出資料的維度
#activation_function 激勵函式
def add_layer(inputs, in_size, out_size, activation_function=None):
    #定義權重a
    weights = tf.Variable(tf.random_normal([in_size, out_size]))
    #定義偏差b
    biases = tf.Variable(tf.zeros([1,out_size])+0.1)
    #定義公式:y=ax+b
    wx_plus_b = tf.matmul(inputs, weights) + biases
    #dropout率等於0.5的時候效果最好,原因是0.5的時候dropout隨機生成的網路結構最多
    #wx_plus_b = tf.nn.dropout(wx_plus_b, keep_prob=0.5)

    if activation_function is None:
        outputs = wx_plus_b
    else:
        outputs = activation_function(wx_plus_b)
    return outputs


#隨機生成一份訓練資料
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape)
y_data = np.square(x_data) - 0.5 + noise


#定義接受資料的節點
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])

#新增隱藏層,在隱藏層有10個神經元,使用Relu啟用函式
#輸入1維資料,經過隱藏層輸出10維資料
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)

#新增輸出層,輸入是隱藏層的l1,在預測層輸出1個結果
#從隱藏層輸入得到的10維資料,經輸出層處理輸出1維資料
prediction = add_layer(l1, 10, 1, activation_function=None)

#定義loss(損失函式)表示式,預測計算結果與真實結果的誤差
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-prediction),reduction_indices=[1]))

# 選擇使得損失最小的方法,這裡選擇梯度下降,學習率是0.1
optimizer = tf.train.GradientDescentOptimizer(0.1)
train_step = optimizer.minimize(loss)

#對建立的變數初始化
init = tf.initialize_all_variables()

#啟動圖
sess = tf.Session()
#從這裡開始,tensorflow才真正開始運算

#執行初始化變數操作
sess.run(init)

#迭代訓練1000次
for i in range(1000):
    sess.run(train_step, feed_dict={xs:x_data, ys:y_data})
    if i % 50 == 0:
        print(sess.run(loss, feed_dict={xs:x_data, ys:y_data}))

#生成一份驗證的資料,在我們訓練完的模型上驗證下
#在把驗證的結果畫出線來
plt.scatter(x_data, y_data)
testx = np.linspace(-1,1,1000)[:,np.newaxis]
#print(testx)
testy = sess.run(prediction, feed_dict={xs:testx})
testy = testy.reshape((1000,))
testx = testx.reshape((1000,))
#print(testy)
plt.plot(testx,testy, c='r')
plt.show()

藍色的點表示訓練集上的點,紅色線是驗證結果,最終結果基本一致
這裡寫圖片描述

2.6 視覺化演示

Tensorflow 自帶 tensorboard ,可以自動顯示我們所建造的神經網路流程圖:
就是用 with tf.name_scope 定義各個框架,注意看程式碼註釋中的區別,程式碼是在上一節程式碼的基礎上修改的:

#coding=utf-8

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

#定義神經層
#inputs 輸入資料
#in_size 輸入資料的維度
#out_size 輸出資料的維度
#activation_function 激勵函式
def add_layer(inputs, in_size, out_size, activation_function=None):
    with tf.name_scope('layer'):
        #定義權重a
        with tf.name_scope('weights'):
            weights = tf.Variable(tf.random_normal([in_size, out_size]),name='W')
        #定義偏差b
        with tf.name_scope('biases'):
            biases = tf.Variable(tf.zeros([1,out_size])+0.1, name='b')
        #定義公式:y=ax+b
        with tf.name_scope('wx_plus_b'):
            wx_plus_b = tf.add(tf.matmul(inputs, weights), biases)
        #dropout率等於0.5的時候效果最好,原因是0.5的時候dropout隨機生成的網路結構最多
        #wx_plus_b = tf.nn.dropout(wx_plus_b, keep_prob=0.5)

        if activation_function is None:
            outputs = wx_plus_b
        else:
            outputs = activation_function(wx_plus_b)
        return outputs


#隨機生成一份訓練資料
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape)
y_data = np.square(x_data) - 0.5 + noise


#定義接受資料的節點
with tf.name_scope('inputs'):
    xs = tf.placeholder(tf.float32,[None,1])
    ys = tf.placeholder(tf.float32,[None,1])

#新增隱藏層,在隱藏層有10個神經元,使用Relu啟用函式
#輸入1維資料,經過隱藏層輸出10維資料
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)

#新增輸出層,輸入是隱藏層的l1,在預測層輸出1個結果
#從隱藏層輸入得到的10維資料,經輸出層處理輸出1維資料
prediction = add_layer(l1, 10, 1, activation_function=None)

#定義loss(損失函式)表示式,預測計算結果與真實結果的誤差
with tf.name_scope('loss'):
    loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-prediction),reduction_indices=[1]))

# 選擇使得損失最小的方法,這裡選擇梯度下降,學習率是0.1
with tf.name_scope('train'):
    train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

#對建立的變數初始化
init = tf.initialize_all_variables()

#啟動圖
sess = tf.Session()
#從這裡開始,tensorflow才真正開始運算

writer = tf.summary.FileWriter("logs/", sess.graph)

#執行初始化變數操作
sess.run(init)

#迭代訓練1000次
#for i in range(1000):
#    sess.run(train_step, feed_dict={xs:x_data, ys:y_data})
#    if i % 50 == 0:
#        print(sess.run(loss, feed_dict={xs:x_data, ys:y_data}))

#
#plt.scatter(x_data, y_data)
#testx = np.linspace(-1,1,1000)[:,np.newaxis]
#print(testx)
#testy = sess.run(prediction, feed_dict={xs:testx})
#testy = testy.reshape((1000,))
#testx = testx.reshape((1000,))
#print(testy)
#plt.plot(testx,testy, c='r')
#plt.show()

執行完上面程式碼後,執行命令 tensorboard –logdir=’logs/’ 後會返回一個地址,然後用瀏覽器開啟這個地址,點選 graph 標籤欄下就可以看到流程圖了:
這裡寫圖片描述

2.7 儲存和載入

訓練好了一個神經網路後,可以儲存起來下次使用時再次載入,但是TensorFlow 現在只能儲存 variables,還不能儲存整個神經網路的框架,所以再使用的時候,需要重新定義框架,然後把 variables 放進去學習

# -*- coding: UTF-8 -*- 
import tensorflow as tf
import numpy as np

## Save to file
# remember to define the same dtype and shape when restore
W = tf.Variable([[1,2,3],[3,4,5]], dtype=tf.float32, name='weights')
b = tf.Variable([[1,2,3]], dtype=tf.float32, name='biases')

init= tf.initialize_all_variables()

saver = tf.train.Saver()

# 用 saver 將所有的 variable 儲存到定義的路徑
with tf.Session() as sess:
  sess.run(init)
  save_path = saver.save(sess, "my_net/save_net.ckpt")
  print("Save to path: ", save_path)
# -*- coding: UTF-8 -*- 
import tensorflow as tf
import numpy as np

# restore variables
# redefine the same shape and same type for your variables
W = tf.Variable(np.arange(6).reshape((2, 3)), dtype=tf.float32, name="weights")
b = tf.Variable(np.arange(3).reshape((1, 3)), dtype=tf.float32, name="biases")

# not need init step

saver = tf.train.Saver()
# 用 saver 從路徑中將 save_net.ckpt 儲存的 W 和 b restore 進來
with tf.Session() as sess:
    saver.restore(sess, "my_net/save_net.ckpt")
    print("weights:", sess.run(W))
    print("biases:", sess.run(b))

3 啟用函式

3.1 什麼是啟用函式

啟用函式(Activation functions)對於人工神經網路模型去學習、理解非常複雜和非線性的函式來說具有十分重要的作用。它們將非線性特性引入到我們的網路中。其主要目的是將A-NN模型中一個節點的輸入訊號轉換成一個輸出訊號。該輸出訊號現在被用作堆疊中下一個層的輸入。啟用函式(Activation functions)對於人工神經網路模型去學習、理解非常複雜和非線性的函式來說具有十分重要的作用。它們將非線性特性引入到我們的網路中。其主要目的 是將A-NN模型中一個節點的輸入訊號轉換成一個輸出訊號。該輸出訊號現在被用作堆疊中下一個層的輸入。
而在A-NN中的具體操作是這樣的,我們做輸入(X)和它們對應的權重(W)的乘積之和,並將啟用函式f(x)應用於其獲取該層的輸出並將其作為輸入饋送到下一個層。而在A-NN中的具體操作是這樣的,我們做輸入(X)和它們對應的權重(W)的乘積之和,並將啟用函式f(x)應用於其獲取該層的輸出並將其作為輸入饋送到下一個層。

3.2 為什麼需要啟用函式

如果我們不運用啟用函式的話,則輸出訊號將僅僅是一個簡單的線性函式。線性函式一個一級多項式。現如今,線性方程是很容易解決的,但是它們的複雜性有限,並且從資料中學習複雜函式對映的能力更小。一個沒有啟用函式的神經網路將只不過是一個線性迴歸模型(Linear regression Model)罷了,它功率有限,並且大多數情況下執行得並不好。我們希望我們的神經網路不僅僅可以學習和計算線性函式,而且還要比這複雜得多。同樣是因為沒有啟用函式,我們的神經網路將無法學習和模擬其他複雜型別的資料,例如影象、視訊、音訊、語音等。這就是為什麼我們要使用人工神經網路技術,諸如深度學習(Deep learning),來理解一些複雜的事情,一些相互之間具有很多隱藏層的非線性問題,而這也可以幫助我們瞭解複雜的資料。

3.3 簡介啟用的函式的作用

啟用函式是用來加入非線性因素的,因為線性模型的表達能力不夠。

以下,同種顏色為同類資料。
某些資料是線性可分的,意思是,可以用一條直線將資料分開。比如下圖:
這裡寫圖片描述

但是有些資料不是線性可分的。比如如下資料:

這裡寫圖片描述
我們可以設計一種神經網路,通過啟用函式來使得這組資料線性可分。
啟用函式我們選擇閥值函式(threshold function),也就是大於某個值輸出1(被激活了),小於等於則輸出0(沒有啟用)。這個函式是非線性函式。

神經網路示意圖如下:
這裡寫圖片描述

其中直線上的數字為權重。圓圈中的數字為閥值。第二層,如果輸入大於1.5則輸出1,否則0;第三層,如果輸入大於0.5,則輸出1,否則0.

我們來一步步算。
第一層到第二層(閥值1.5)

這裡寫圖片描述

第二層到第三層(閥值0.5)第二層到第三層(閥值0.5)

這裡寫圖片描述

可以看到第三層輸出就是我們所要的xor的答案。
經過變換後的資料是線性可分的(n維,比如本例中可以用平面),如圖所示:

這裡寫圖片描述

總而言之,啟用函式可以引入非線性因素,解決線性模型所不能解決的問題。

關於啟用函式的內容來自知乎,更多內容參考:知乎-神經網路激勵函式

參考文件