tensorflow手動實現算法之一線性迴歸

0.前言

現在算法相關的框架與工具,封裝得越來越好,調用越來越方便,以至於很多算法工程師被嘲笑或者自嘲爲"調包俠",“調參俠”。確實在實際工作中,需要自己從頭到尾實現算法的機會越來越少,尤其是分佈式的系統,最多就是在框架實現的基礎之上拉出一部分邏輯進行二次開發重新封裝一下。即便如此,弄清楚算法的原理與流程,也還是有必要的,這樣更方便實際中debug,定位問題,調整參數等等。因此,本人打算基於tensorflow來實現一下各種常用的算法,包括深度學習的各種算法,網絡結構,以及傳統的機器學習算法。

1.線性迴歸

線性迴歸算是最簡單的一種數據模擬方式了,有過初中數學基礎的同學都能理解。現在我們考慮一種最簡單的情況:單變量的線性迴歸。
假設
y=2x+0.1y = 2x + 0.1
有一組數據滿足以上的解析關係,然後現在求解線性迴歸,求參數wwbb

先看我們不使用tensorflow,只使用numpy求解的解法。

import numpy as np

# simulate y = 2x + 0.1
def linear_reg_gd():
    x = np.array([1, 2, 3, 4, 5])
    y = np.array([2.1, 4.1, 6.1, 8.1, 10.1])

    w = np.random.rand()
    b = np.random.rand()

    learning_rate = 0.02
    for i in range(3000):
        ww = np.array([w] * len(x))
        bb = np.array([b] * len(x))

        loss = np.linalg.norm(ww * x + bb - y, 2)

        if loss < 0.00001:
            break
        if i % 100 == 0:
            print("第 %d 次loss爲: %f" % (i, loss))

        grad_w = np.sum((ww * x + bb - y) * x) / len(x)
        grad_b = np.sum(ww * x + bb - y) / len(x)

        w -= learning_rate * grad_w
        b -= learning_rate * grad_b

    print(w)
    print(b)

上面的代碼幾個關鍵步驟:

        loss = np.linalg.norm(ww * x + bb - y, 2)

本行定義了損失函數,爲MSE。

        grad_w = np.sum((ww * x + bb - y) * x) / len(x)
        grad_b = np.sum(ww * x + bb - y) / len(x)

分別計算wwbb的梯度,然後進行迭代梯度下降即可。

2.tensorflow進行線性迴歸

import numpy as np
import tensorflow as tf

def linear_reg_tf():
    x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
    y = np.array([2.1, 4.1, 6.1, 8.1, 10.1])

    n = x.shape[0]

    W = tf.Variable(np.random.rand())
    b = tf.Variable(np.random.rand())

    X = tf.placeholder(tf.float32, name='X')
    Y = tf.placeholder(tf.float32, name='Y')
	
	# model
    pred = tf.add(tf.multiply(X, W), b)

	# loss
    loss = tf.reduce_sum(tf.pow(pred - Y, 2)) / (2 * n)

	# optmize
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

    init = tf.global_variables_initializer()

    with tf.Session() as sess:
        sess.run(init)
        for i in range(3000):
            l, _ = sess.run([loss, optimizer], feed_dict={X: x, Y: y})
            print("第 %d 次loss: %f" %(i, l))

            if l < 0.000001:
                break

        print("W is: ", W.eval())
        print("b is: ", b.eval())

linear_reg_tf()
...
第 2998 次loss: 0.000004
第 2999 次loss: 0.000004
W is:  1.9981396
b is:  0.10671652

首先看最終的結果,w=1.998,b=0.1067w=1.998, b = 0.1067,已經比較接近準確的數值了。

代碼結構:
1.定義W, b變量。
2.聲名X, Y的placeholder。
3.pred爲模型,其實就是y=wx+by = wx + b
4.loss爲MSE損失函數
5.optimizer爲優化器,這裏選的是梯度下降。
6.然後起個sess開始run即可。

可以看出,tf的代碼結構還是比較簡單清晰的,實現起來確實也比較快。

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