【TensorFlow篇】--Tensorflow框架初始,實現機器學習中多元線性迴歸

LHBlog發表於2018-03-27

一、前述

TensorFlow是谷歌基於DistBelief進行研發的第二代人工智慧學習系統,其命名來源於本身的執行原理。Tensor(張量)意味著N維陣列,Flow(流)意味著基於資料流圖的計算,TensorFlow為張量從流圖的一端流動到另一端計算過程。TensorFlow是將複雜的資料結構傳輸至人工智慧神經網中進行分析和處理過程的系統。

二、相關概念和安裝

TensorFlow中的計算可以表示為一個有向圖(DirectedGraph)
或者稱計算圖(ComputationGraph)
其中每一個運算操作(operation)將作為一個節點(node)
計算圖描述了資料的計算流程,也負責維護和更新狀態
使用者通過python,C++,go,Java語言設計這個這個資料計算的有向圖
計算圖中每一個節點可以有任意多個輸入和任意多個輸出
每一個節點描述了一種運算操作,節點可以算是運算操作的例項化(instance)
計算圖中的邊裡面流動(flow)的資料被稱為張量(tensor),故得名TensorFlow

安裝流程:

pip install tensorflow==1.1.0

三、程式碼規範

詳細原始碼在本人github上https://github.com/LhWorld/AI_Project.git

程式碼一:tensorflow 基本語法

 

import tensorflow as tf

x = tf.Variable(3, name='x') #Variable建立一個變數
y = tf.Variable(4, name='y')
f = x*x*y + y + 2

# 可以不分別對每個變數去進行初始化
# 並不立即初始化,在run執行的時候才初始化
init = tf.global_variables_initializer()

with tf.Session() as sess:
    init.run()
    result = f.eval()
    print(result)

 

程式碼二:Variable的宣告週期

 

import tensorflow as tf

# 當去計算一個節點的時候,TensorFlow自動計算它依賴的一組節點,並且首先計算依賴的節點
w = tf.constant(3)
x = w + 2
y = x + 5
z = x * 3

with tf.Session() as sess:
    print(y.eval())
    # 這裡為了去計算z,又重新計算了x和w,除了Variable值,tf是不會快取其他比如contant等的值的
    # 一個Variable的生命週期是當它的initializer執行的時候開始,到會話session close的時候結束
    print(z.eval())

# 如果我們想要有效的計算y和z,並且又不重複計算w和x兩次,我們必須要求TensorFlow計算y和z在一個圖裡
with tf.Session() as sess:
    y_val, z_val = sess.run([y, z])
    print(y_val)
    print(z_val)

 程式碼三:Tensorflow手動實現多元線性迴歸中解析解求解過程

import tensorflow as tf
import numpy as np
from sklearn.datasets import fetch_california_housing

# 立刻下載資料集
housing = fetch_california_housing()
print(housing)
# 獲得X資料行數和列數
m, n = housing.data.shape
# 這裡新增一個額外的bias輸入特徵(x0=1)到所有的訓練資料上面,因為使用的numpy所有會立即執行
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]#np.c_整合combine np.ones((m, 1)是x0=1這一列
#以上程式碼會立即執行 因為不是tf的函式
# 建立兩個TensorFlow常量節點X和y,去持有資料和標籤
X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name='X')#延遲執行,只是做了一下標記
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name='y')#reshape(-1,1)把行向量轉變成列向量  -1代表隨便行 不限制行數 最終m行一列
#以上y是真實的資料
# 使用一些TensorFlow框架提供的矩陣操作去求theta
XT = tf.transpose(X)
# 解析解一步計算出最優解
theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)#解析解公式
with tf.Session() as sess:
    theta_value = theta.eval()  # 與sess.run(theta)等價 theta相當於一個圖通過DAG構建
    print(theta_value)

 

程式碼四:Tensorflow手動實現多元線性迴歸中梯度下降求解過程

 

import tensorflow as tf
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.preprocessing import StandardScaler

#多元線性迴歸是一個凸函式 ,所以能找到全域性最優解
#神經網路只有區域性最優解
n_epochs = 1000#把樣本集資料學習1000次
learning_rate = 0.01 #步長 學習率 不能太大 太大容易來回震盪 太小 耗時間,跳不出區域性最優解
#可以寫learn_rate動態變化,隨著迭代次數越來越大 ,學習率越來越小 learning_rate/n_epoches
housing = fetch_california_housing()
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]
# 可以使用TensorFlow或者Numpy或者sklearn的StandardScaler去進行歸一化
#歸一化可以最快的找到最優解
#常用的歸一化方式:
# 最大最小值歸一化 (x-min)/(max-min)
# 方差歸一化 x/方差
# 均值歸一化 x-均值 結果有正有負 可以使調整時的速度越來越快。
scaler = StandardScaler().fit(housing_data_plus_bias) #建立一個歸一化物件
scaled_housing_data_plus_bias = scaler.transform(housing_data_plus_bias) #真正執行 因為來源於sklearn所以會直接執行,不會延遲。


X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name='X')
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name='y')

# random_uniform函式建立圖裡一個節點包含隨機數值,給定它的形狀和取值範圍,就像numpy裡面rand()函式
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0), name='theta') #theta是引數 W0-Wn 一列 按照-1.0到1.0隨機給
y_pred = tf.matmul(X, theta, name="predictions")#相乘 m行一列
error = y_pred - y #列向量和列向量相減 是一組數
mse = tf.reduce_mean(tf.square(error), name="mse")#誤差平方加和,最小二乘 平方均值損失函式 手動實現
# 梯度的公式:(y_pred - y) * xj  i代表行 j代表列
gradients = 2/m * tf.matmul(tf.transpose(X), error)#矩陣和向量相乘會得到新的向量 一組梯度
# 賦值函式對於BGD來說就是 theta_new = theta - (learning_rate * gradients)
training_op = tf.assign(theta, theta - learning_rate * gradients)#assigin賦值 算一組w
# training_op實際上就是需要迭代的公式

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init) #初始化

    for epoch in range(n_epochs):#迭代1000次
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE = ", mse.eval())#每執行100次的時候輸出
        sess.run(training_op)

    best_theta = theta.eval()#最後的w引數值
    print(best_theta)

 

通過Tensorflow執行機器學習可以實現分散式運算,提高速度。

程式碼五:使用tensorflow本身API實現

 

import tensorflow as tf
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.preprocessing import StandardScaler


# TensorFlow為我們去計算梯度,但是同時也給了我們更方便的求解方式
# 它提供給我們與眾不同的,有創意的一些優化器,包括梯度下降優化器
# 替換前面程式碼相應的行,並且一切工作正常


n_epochs = 1000
learning_rate = 0.01

housing = fetch_california_housing()
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]
# 可以使用TensorFlow或者Numpy或者sklearn的StandardScaler去進行歸一化
scaler = StandardScaler().fit(housing_data_plus_bias)
scaled_housing_data_plus_bias = scaler.transform(housing_data_plus_bias)

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name='X')
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name='y')

# random_uniform函式建立圖裡一個節點包含隨機數值,給定它的形狀和取值範圍,就像numpy裡面rand()函式
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0), name='theta')
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
# 梯度的公式:(y_pred - y) * xj
# gradients = 2/m * tf.matmul(tf.transpose(X), error)
# gradients = tf.gradients(mse, [theta])[0]
# 賦值函式對於BGD來說就是 theta_new = theta - (learning_rate * gradients)
# training_op = tf.assign(theta, theta - learning_rate * gradients)

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
# MomentumOptimizer收斂會比梯度下降更快
# optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9)
training_op = optimizer.minimize(mse)#去減小誤差

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE = ", mse.eval())
        sess.run(training_op)

    best_theta = theta.eval()
    print(best_theta)

 程式碼六:placeholder的使用

 

import tensorflow as tf

# 讓我們修改前面的程式碼去實現Mini-Batch梯度下降
# 為了去實現這個,我們需要一種方式去取代X和y在每一次迭代中,使用一小批資料
# 最簡單的方式去做到這個是去使用placeholder節點
# 這些節點特點是它們不真正的計算,它們只是在執行過程中你要它們輸出資料的時候去輸出資料
# 它們會傳輸訓練資料給TensorFlow在訓練的時候
# 如果在執行過程中你不給它們指定資料,你會得到一個異常

# 需要做的是使用placeholder()並且給輸出的tensor指定資料型別,也可以選擇指定形狀
# 如果你指定None對於某一個維度,它的意思代表任意大小
A = tf.placeholder(tf.float32, shape=(None, 3))
B = A + 5

with tf.Session() as sess:
    B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})#等價於session.run(B)一行資料三個維度
    B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})#兩行資料,三個維度

print(B_val_1)
print(B_val_2)

 

相關文章