TensorFlow實現線性迴歸

Harvard_Fly發表於2019-06-05

線性迴歸(Linear regression)是利用迴歸方程(函式)對一個或多個自變數(特徵值)和因變數(目標值)之間關係進行建模的一種分析方式。

特點:只有一個自變數的情況稱為單變數回歸,大於一個自變數情況的叫做多元迴歸

通用公式:h(w) = w1x1+w2x2+w3x3+...+b=wTx + b

根據資料建立迴歸模型,w1x1+w2x2+…..+b = y,通過真實值與預測值之間建立誤差,使用梯度下降優化得到損失最小對應的權重和偏置。最終確定模型的權重和偏置引數,最後可以用這些引數進行預測。

線性迴歸案例:

假設隨機指定100個點,只有一個特徵
資料本身的分佈為 y = 0.7 * x + 0.8
這裡將資料分佈的規律確定,是為了使我們訓練出的引數跟真實的引數(即0.7和0.8)比較是否訓練準確

 

TensorFlow計算API:
運算

矩陣運算
tf.matmul(x, w)
平方
tf.square(error)
均值
tf.reduce_mean(error)


梯度下降優化

tf.train.GradientDescentOptimizer(learning_rate)
梯度下降優化
learning_rate:學習率,一般為0~1之間比較小的值
method:
minimize(loss)
return:梯度下降op

 

步驟分析:
1、準備資料的特徵值和目標值 inputs

獲取特徵值目標值資料資料

    def inputs(self):
        """
        獲取特徵值目標值資料資料
        :return:
        """
        x_data = tf.random_normal([100, 1], mean=1.0, stddev=1.0, name="x_data")
        y_true = tf.matmul(x_data, [[0.7]]) + 0.8

        return x_data, y_true

 

2、根據特徵值建立線性迴歸模型(確定引數個數形狀) inference

根據輸入資料建立模型,模型的引數必須使用變數OP建立

    def inference(self, feature):
        """
        根據輸入資料建立模型
        :param feature:
        :param label:
        :return:
        """
        with tf.variable_scope("linea_model"):
            # 建立迴歸模型,分析別人的資料的特徵數量--->權重數量, 偏置b
            # 由於有梯度下降演算法優化,所以一開始給隨機的引數,權重和偏置
            # 被優化的引數,必須得使用變數op去定義
            # 變數初始化權重和偏置
            # weight 2維[1, 1]    bias [1]
            # 變數op當中會有trainable引數決定是否訓練
            self.weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0),
                                      name="weights")

            self.bias = tf.Variable(0.0, name='biases')

            # 建立迴歸公式去得出預測結果
            y_predict = tf.matmul(feature, self.weight) + self.bias

        return y_predict

  

3、根據模型得出預測結果,建立損失 loss

求出模型跟真實資料之間的損失
 def loss(self, y_true, y_predict):
        """
        目標值和真實值計算損失
        :return: loss
        """
        # 均方誤差公式
        loss = tf.reduce_mean(tf.square(y_true - y_predict))

        return loss

  

4、梯度下降優化器優化損失 sgd_op

使用梯度下降優化器優化
    def sgd_op(self, loss):
        """
        獲取訓練OP
        :return:
        """
        # 填充學習率:0 ~ 1    學習率是非常小,
        # 學習率大小決定你到達損失一個步數多少
        # 最小化損失
        train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

        return train_op

 

學習率的設定、步長的設定與梯度爆炸
學習率越大,訓練到較好結果的步長越小;學習率越小,訓練到較好結果的步長越大。但是學習過大會出現梯度爆炸現象(在極端情況下,權重的值變得非常大,以至於溢位,導致 NaN 值)

如何解決梯度爆炸問題:

1. 重新設計網路

2. 調整學習率

3. 使用梯度截斷(在訓練過程中檢查和限制梯度的大小)

4. 使用啟用函式

 

 

變數的trainable設定觀察
trainable的引數作用,指定是否訓練

weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name="weights", trainable=False)

 

增加變數顯示
目的:在TensorBoard當中觀察模型的引數、損失值等變數值的變化

1、收集變數
tf.summary.scalar(name=’’,tensor) 收集對於損失函式和準確率等單值變數,name為變數的名字,tensor為值
tf.summary.histogram(name=‘’,tensor) 收集高維度的變數引數
tf.summary.image(name=‘’,tensor) 收集輸入的圖片張量能顯示圖片

 

# 收集張量的值
tf.summary.scalar("losses", loss)

tf.summary.histogram("w", self.weight)
tf.summary.histogram('b', self.bias)

2、合併變數寫入事件檔案
merged = tf.summary.merge_all()
執行合併:summary = sess.run(merged),每次迭代都需執行
新增:FileWriter.add_summary(summary,i),i表示第幾次的值

 

# 合併變數
merged = tf.summary.merge_all()
# 生成事件檔案,觀察圖結構

file_writer = tf.summary.FileWriter("./tmp/summary/", graph=sess.graph)

# 執行收集變數的結果
summary = sess.run(merged)

# 新增到檔案
file_writer.add_summary(summary, i)

 

 

模型的儲存與載入
tf.train.Saver(var_list=None,max_to_keep=5)
儲存和載入模型(儲存檔案格式:checkpoint檔案)
var_list:指定將要儲存和還原的變數。它可以作為一個dict或一個列表傳遞.
max_to_keep:指示要保留的最近檢查點檔案的最大數量。建立新檔案時,會刪除較舊的檔案。如果無或0,則保留所有檢查點檔案。預設為5(即保留最新的5個檢查點檔案。)

指定目錄+模型名字
saver.save(sess, '/tmp/ckpt/test/myregression.ckpt')
saver.restore(sess, '/tmp/ckpt/test/myregression.ckpt')
如要判斷模型是否存在,直接指定目錄

checkpoint = tf.train.latest_checkpoint("./tmp/model/")

saver.restore(sess, checkpoint)

 

完整程式碼:

import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import tensorflow as tf

# 定義一些常用的命令列引數
# 訓練步數
tf.app.flags.DEFINE_integer("max_step", 10, "訓練模型的步數")
# 定義模型的路徑
tf.app.flags.DEFINE_string("model_dir", "./tmp/model/myregression.ckpt ", "模型儲存的路徑+模型名字")

FLAGS = tf.app.flags.FLAGS


class MyLinearRegression(object):
    """
    自實現線性迴歸
    """

    def __init__(self):
        pass

    def inputs(self):
        """
        獲取特徵值目標值資料
        :return:
        """
        x_data = tf.random_normal([100, 1], mean=1.0, stddev=1.0, name="x_data")
        y_true = tf.matmul(x_data, [[0.7]]) + 0.8

        return x_data, y_true

    def inference(self, feature):
        """
        根據輸入資料建立模型
        建立迴歸模型,分析別人的資料的特徵數量--->權重數量, 偏置b
        :param feature:
        :return:
        """
        with tf.variable_scope("linea_model"):
            # 由於有梯度下降演算法優化,所以一開始給隨機的引數,權重和偏置
            # 被優化的引數,必須得使用變數op去定義
            # 變數初始化權重和偏置
            # weight 2維[1, 1]    bias [1]
            # 變數op當中會有trainable引數決定是否訓練
            self.weight = tf.Variable(
                tf.random_normal([1, 1], mean=0.0, stddev=1.0),
                name="weights"
            )

            self.bias = tf.Variable(0.0, name='biases')

            # 建立迴歸公式去得出預測結果
            y_predict = tf.matmul(feature, self.weight) + self.bias

        return y_predict

    def loss(self, y_true, y_predict):
        """
        目標值和真實值計算損失
        求出我們模型跟真實資料之間的損失
        :return: loss
        """
        # 均方誤差公式
        loss = tf.reduce_mean(tf.square(y_true - y_predict))

        return loss

    def merge_summary(self, loss):

        # 1、收集張量的值
        tf.summary.scalar("losses", loss)

        tf.summary.histogram("w", self.weight)
        tf.summary.histogram('b', self.bias)

        # 2、合併變數
        merged = tf.summary.merge_all()

        return merged

    def sgd_op(self, loss):
        """
        獲取訓練OP
        :return:
        """
        # 使用梯度下降優化器優化
        # 填充學習率:0 ~ 1    學習率是非常小,
        # 學習率大小決定你到達損失一個步數多少
        # 最小化損失
        train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

        return train_op

    def train(self):
        """
        訓練模型
        :param loss:
        :return:
        """

        g = tf.get_default_graph()

        with g.as_default():

            x_data, y_true = self.inputs()

            y_predict = self.inference(x_data)

            loss = self.loss(y_true, y_predict)

            train_op = self.sgd_op(loss)

            # 收集觀察的結果值
            merged = self.merge_summary(loss)

            saver = tf.train.Saver()

            with tf.Session() as sess:

                sess.run(tf.global_variables_initializer())

                # 在沒訓練,模型的引數值
                print("初始化的權重:%f, 偏置:%f" % (self.weight.eval(), self.bias.eval()))

                # 載入模型
                checkpoint = tf.train.latest_checkpoint("./tmp/model/")
                if checkpoint:
                    print('Restoring', checkpoint)
                    saver.restore(sess, checkpoint)

                # 開啟訓練
                # 訓練的步數(依據模型大小而定)
                print(FLAGS.max_step)
                for i in range(FLAGS.max_step):
                    sess.run(train_op)

                    # 生成事件檔案,觀察圖結構
                    file_writer = tf.summary.FileWriter("./tmp/summary/", graph=sess.graph)

                    print("訓練第%d步之後的損失:%f, 權重:%f, 偏置:%f" % (
                        i,
                        loss.eval(),
                        self.weight.eval(),
                        self.bias.eval()))

                    # 執行收集變數的結果
                    summary = sess.run(merged)

                    # 新增到檔案
                    file_writer.add_summary(summary, i)

                    if i % 100 == 0:
                        # 儲存的是會話當中的變數op值,其他op定義的值不儲存
                        print(sess)
                        saver.save(sess, FLAGS.model_dir)


if __name__ == '__main__':
    lr = MyLinearRegression()
    lr.train()

 

訓練結果:

 

相關文章