Python寫簡單的線性分類器
根據前一篇文章(人工神經元和Delta規則 - 知乎專欄)介紹的神經元和學習規則,我們可以寫一個線性分類器。
import numpynnclass Layer:n # 初始化 dim_out 個神經元構成的單層神經網路,輸出為 dim_in 維n def __init__(self, dim_in, dim_out):n # 隨機初始化權值矩陣 weightn self.weight = numpy.matrix(numpy.random.rand(dim_in, dim_out))n # 初始化神經元的偏置 biasn self.bias = numpy.zeros(dim_out)nn # 計算神經網路在輸入為 x 時的輸出n def compute(self, x):n sum = x * self.weight + self.biasn # 採用 ReLU,將小於零的神經元輸出置為 0n lessThanZero = sum < 0n sum[lessThanZero] = 0n return sumnn # 根據輸入 x 和 輸出 y 進行一輪學習,學習率為 raten def learn(self, x, y, rate):n x = numpy.matrix(x, copy=False)n y1 = self.compute(x)n # 計算激活函數的導數 derivativen derivative = numpy.ones(y1.shape)n isZero = y1 == 0n derivative[isZero] = 0n # 修正權值和偏置n delta = numpy.multiply(y - y1, derivative)n self.weight = self.weight + numpy.transpose(x) * delta * raten self.bias = self.bias + numpy.ones([1, x.shape[0]]) * delta * raten
上面這個「分類器」實際上是對輸入和輸出進行了線性擬合。輸入和輸出的維度是可以任意指定的。神經元的激活函數採用了 Rectifier 函數 (),採用這個函數的神經元叫做 Rectified Linear Unit (ReLU)。這是在深度學習中很常用的一種神經元。傳統的 Sigmoid 函數在兩端導數接近於 0,因此誤差不能有效的進行反向傳播。ReLU 沒有這樣的缺陷,而且導數很好計算 。Softplus 函數是 Rectifier 的平滑版本,適用於需要連續可導的情況。
我們可以用這個線性分類器對一組數據點進行分類,這組點一共有 6 個,分為 2 組。
a = Layer(2, 1)nx = numpy.array([[1, 2], [2, 1], [3, 1], [1, 3], [2, 3], [3, 2]])ny = numpy.array([[0], [0], [0], [1], [1], [1]])nnfor i in range(5000):n print(a.compute(x))n a.learn(x, y, 0.01)n print(a.weight, a.bias)n
經過每一輪學習更新後的 weight 和 bias 都會顯示出來。下面的代碼把結果更加直觀的畫出來,weight 和 bias 對應了一條分割兩組數據點的直線,就是上面那幅圖裡面的黑色虛線。
import matplotlib.pyplotnnfig, ax = matplotlib.pyplot.subplots()nax.plot(x[:3,0], x[:3,1], "bo")nax.plot(x[3:,0], x[3:,1], "ro")nxs = numpy.arange(0, 5)nys = (0.5 - a.bias[0,0] - xs * a.weight[0,0]) / a.weight[1,0]nax.plot(xs, ys, "k--")nmatplotlib.pyplot.show()n
我們當然也可以用 TensorFlow 來解決這個簡單的線性回歸問題。利用 TensorFlow,只需要描述出神經元計算的過程。TensorFlow 會自動為我們計算出梯度下降訓練過程所需要的導數。
import tensorflow as tfnn# 創建 variable 用於表示模型參數nw = tf.Variable([[0.0], [0.0]], dtype=tf.float32)nb = tf.Variable([0.0], dtype=tf.float32)nn# 創建 placeholder 用於表示模型的輸入nx = tf.placeholder(dtype=tf.float32)ny = tf.placeholder(dtype=tf.float32)nn# 將損失函數 loss 定義為誤差的平方和ndelta = tf.squared_difference(y, tf.matmul(x, w) + b)nloss = tf.reduce_sum(delta)nn# 將訓練演算法定義為學習率 0.01 的梯度下降演算法nopt = tf.train.GradientDescentOptimizer(0.01)ntrain = opt.minimize(loss)nn# 初始化全局變數ninit = tf.global_variables_initializer()nsess = tf.Session()nsess.run(init)nn# 訓練 1000 輪nfor i in range(1000):n sess.run(train, {x:[[1, 2], [2, 1], [3, 1], [1, 3], [2, 3], [3, 2]], y:[[0], [0], [0], [1], [1], [1]]})n print(sess.run([w, b]))n
推薦閱讀:
※3blue1brown的神經網路:part1 筆記
※《A COMPARE-AGGREGATE MODEL FOR MATCHING TEXT SEQUENCES》閱讀筆記
※神經網路知識梳理——從神經元到深度學習
※梯度下降演算法在Neural Network下的理解