线性拟合和梯度下降python代码实现—面向对象(二)
最近看到了一個系列博客,寫的不錯,就拿來學習了下。一來加深理解,二來鍛煉自己編寫代碼的能力。
關于基礎的理論知識就不重述了,網上資源很多,這里推薦:https://www.zybuluo.com/hanbingtao/note/448086,因為我就是學習的這個系列博客。
這里只對比和上篇python 實現感知器之間的聯系和代碼復用的地方。
這里只更新下激活函數即可,而且這里的激活函數相當于什么也沒做,原樣輸出,即保持線性的形式。
代碼如下:
#!/usr/bin/env python # -*- coding: UTF-8 -*-from perceptron import Perceptron#定義激活函數f f = lambda x: x # 相當于原樣輸出class LinearUnit(Perceptron):def __init__(self, input_num):'''初始化線性單元,設置輸入參數的個數'''Perceptron.__init__(self, input_num, f)def get_training_dataset():'''捏造5個人的收入數據'''# 構建訓練數據# 輸入向量列表,每一項是工作年限input_vecs = [[5], [3], [8], [1.4], [10.1]]# 期望的輸出列表,月薪,注意要與輸入一一對應labels = [5500, 2300, 7600, 1800, 11400]return input_vecs, labels def train_linear_unit():'''使用數據訓練線性單元'''# 創建感知器,輸入參數的特征數為1(工作年限)lu = LinearUnit(1)# 訓練,迭代10輪, 學習速率為0.01input_vecs, labels = get_training_dataset()lu.train(input_vecs, labels, 10, 0.01)#返回訓練好的線性單元return ludef plot(linear_unit):import matplotlib.pyplot as pltinput_vecs, labels = get_training_dataset()fig = plt.figure()ax = fig.add_subplot(111)ax.scatter(map(lambda x: x[0], input_vecs), labels)# 訓練得到權重和偏置weights = linear_unit.weightsbias = linear_unit.biasx = range(0,12,1)y = map(lambda x:weights[0] * x + bias, x)ax.plot(x, y)plt.show()if __name__ == '__main__': '''訓練線性單元'''linear_unit = train_linear_unit()# 打印訓練獲得的權重print linear_unit# 測試print 'Work 3.4 years, monthly salary = %.2f' % linear_unit.predict([3.4])print 'Work 15 years, monthly salary = %.2f' % linear_unit.predict([15])print 'Work 1.5 years, monthly salary = %.2f' % linear_unit.predict([1.5])print 'Work 6.3 years, monthly salary = %.2f' % linear_unit.predict([6.3])plot(linear_unit)運行結果:
weights :[1124.0634970262222] bias :85.485289Work 3.4 years, monthly salary = 3907.30 Work 15 years, monthly salary = 16946.44 Work 1.5 years, monthly salary = 1771.58 Work 6.3 years, monthly salary = 7167.09模型很簡單,激活函數和學習算法也很簡單,但這里我覺得最大的值得學習的地方就在于面向對象編程范式的便利。
這里導入了Perceptron類:
# 這里定義一個感知器的類 class Perceptron(object):def __init__(self, input_num, activator):'''初始化感知器,設置輸入參數的個數,以及激活函數。激活函數的類型為double -> double'''self.activator = activator# 權重向量初始化為0.0self.weights = [0.0 for _ in range(input_num)]# 偏置項初始化為0.0self.bias = 0.0def __str__(self): # __str__:類實例字符串化函數'''打印學習到的權重、偏置項'''return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)def predict(self, input_vec):'''輸入向量,輸出感知器的計算結果'''# 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起# 變成[(x1,w1),(x2,w2),(x3,w3),...]# 然后利用map函數計算[x1*w1, x2*w2, x3*w3]# 最后利用reduce求和:reduce()還可以接收第3個可選參數,作為計算的初始值xi_wi=map(lambda (x, w): x * w,zip(input_vec, self.weights))# 激活函數的輸入為w_1*x_1+w_2*x_2+biasreturn self.activator(reduce(lambda a, b: a + b,xi_wi , 0.0) + self.bias)def train(self, input_vecs, labels, iteration, rate):'''輸入訓練數據:一組向量、與每個向量對應的label;以及訓練輪數、學習率'''# 每次迭代都把所有的樣本輸入for i in range(iteration):self._one_iteration(input_vecs, labels, rate)def _one_iteration(self, input_vecs, labels, rate):'''一次迭代,把所有的訓練數據過一遍'''# 把輸入和輸出打包在一起,成為樣本的列表[(input_vec, label), ...]# 而每個訓練樣本是(input_vec, label)samples = zip(input_vecs, labels)# 對每個樣本,按照感知器規則更新權重for (input_vec, label) in samples:# 計算感知器在當前權重下的輸出output = self.predict(input_vec)# 更新權重self._update_weights(input_vec, output, label, rate)def _update_weights(self, input_vec, output, label, rate):'''按照感知器規則更新權重'''# 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起# 變成[(x1,w1),(x2,w2),(x3,w3),...]# 然后利用感知器規則更新權重delta = label - outputself.weights = map(lambda (x, w): w + rate * delta * x,zip(input_vec, self.weights))# 更新biasself.bias += rate * delta而該類定義了
- 初始化:初始化權重、偏置、激活函數;
- 打印輸出函數:打印學習到的權重和偏置
- 訓練參數的類方法
- 預測的類方法
- 一次迭代的類方法(隨機梯度下降)
- 更新參數的類方法
其中參數更新的遞推公式是:
這里的更新方式是批梯度下降,但算法里采用的是隨機梯度下降,更新公式為:
wnew=wold+η(y(i)?y?)x(i)wnew=wold+η(y(i)?y^)x(i)
注意:
Python中lambda表達式
看幾個例子
map(lambda (x, w): x * w,zip(input_vec, self.weights))的用法
首先這里的lambda (x, w): x * w,zip(input_vec, self.weights)中的lambda (x, w)的用法要注意,這里代表的是一個參數。而正確的lmbda參數形式其實是這樣的lambda x,y:x+y,x,y是它的2個形參,所以這里 lambda (x,w)其實就只有一個參數,那就是一個tuple類型的參數。
看幾個例子:
面向對象編程。面向對象是特別好的管理復雜度的工具,應對復雜問題時,用面向對象設計方法很容易將復雜問題拆解為多個簡單問題,從而解救我們的大腦。
還有就是numpy實現了很多基礎算法,對于實現機器學習算法來說是個必備的工具,這里沒有使用numpy,從而對算法原理有更深入的理解。
總結
以上是生活随笔為你收集整理的线性拟合和梯度下降python代码实现—面向对象(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 朋友餐饮店开业+万事俱备就差一位尊贵的老
- 下一篇: 3.分析新疆的羊肉抓饭中主要食材(1)大