1. 程式人生 > >機器學習學習筆記之一——用python實現簡單一元函式、二元函式的梯度下降

機器學習學習筆記之一——用python實現簡單一元函式、二元函式的梯度下降

  今天開始正正經經,好好的寫機器學習的筆記。

  再一次從頭翻過來學機器學習,在有一些python和大學數學的基礎下,首先要搞的果然還是梯度下降,本篇記錄的是用jupyter完成的一次作業:python實現一維陣列和二維陣列的梯度下降,目的只在於熟悉梯度下降。

第一部分:一元函式的資料生成與影象呈現

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import math
from mpl_toolkits.mplot3d import Axes3D
import warnings

# 解決中文顯示問題
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
%matplotlib inline

"""
原影象:
1、構建一個函式為 y = 0.5 * (x-0.25) ** 2 的影象。
2、隨機生成X點,根據X點生成Y點。
3、畫出影象。
"""
# 一維原始影象
# 原函式
def f1(x):
    return 0.5 * (x - 0.25) ** 2

# 構建資料
X = np.arange(-4,4,0.05)
Y = np.array(list(map(lambda t: f1(t),X)))
Y

# 作圖
plt.figure(facecolor='w')
plt.plot(X,Y,'r-',linewidth=2)
plt.title(u'函式$y=0.5 * (x - 0.25)^2$')
plt.show()

結果如圖:

第二部分:一元函式的梯度下降求解過程,以及求解過程影象呈現

"""
對當前一維原始影象求最小點:
1、隨機取一個點(橫座標為x),設定阿爾法引數值。  
2、對這個點求導數 ,x =x - α*(dY/dx)。  
3、重複第二步、設定迭代 y的變化量小於多少時 不再繼續迭代。
"""
# 導數
def h1(x):
    return 0.5 * 2 * (x-0.25)

x = 4
alpha = 0.5
f_change = f1(x) # y的變化量
iter_num = 0 # 迭代次數
GD_X = [x] #儲存梯度下降所經歷的點
GD_Y = [f1(x)]

while(f_change > 1e-10) and iter_num<100:
    tmp = x - alpha * h1(x)
    f_change =  np.abs(f1(x) - f1(tmp))
    x = tmp
    GD_X.append(x)
    GD_Y.append(f1(x))
    iter_num += 1
    
print(u"最終結果為:(%.5f,%.5f)"%(x,f1(x)))
print(u"迭代過程中X的取值,迭代次數:%d" % iter_num)
print(GD_X)

%matplotlib inline
plt.figure(facecolor='w')
plt.plot(X,Y,'r-',linewidth=2) #第三個引數是顏色和形狀,red圈就是ro-,red直線就是r-
plt.plot(GD_X, GD_Y, 'bo-', linewidth=2)
plt.title(u'函式$ y = 0.5 * (x-0.25)^2$;\n學習率%.3f;最終解:(%.3f,%.3f),迭代次數:%d'%(alpha,x,f1(x),iter_num))

結果如圖:

 

第三部分:二元函式的資料生成、影象顯示

"""
二維原始影象
1、構建一個函式為 y = 0.5 (x1+x2)^2 - x1 x2 的影象。
2、隨機生成X1,X2點,根據X1,X2點生成Y點。
3、畫出影象。
"""
def f2(x1,x2):
    return 0.5 * (x1+x2) ** 2 - x1 * x2

X1 = np.arange(-4,4,0.2)
X2 = np.arange(-4,4,0.2)
X1, X2 = np.meshgrid(X1, X2) # 生成xv、yv,將X1、X2變成n*m的矩陣,方便後面繪圖
Y = np.array(list(map(lambda t : f2(t[0],t[1]),zip(X1.flatten(),X2.flatten()))))
Y.shape = X1.shape # 1600的Y圖還原成原來的(40,40)

%matplotlib inline
#作圖
fig = plt.figure(facecolor='w')
ax = Axes3D(fig)
ax.plot_surface(X1,X2,Y,rstride=1,cstride=1,cmap=plt.cm.jet)
ax.set_title(u'$ y = 0.5 (x1+x2)^2 - x1 x2 $')
plt.show()

結果如圖:

 

第四部分:二元函式的梯度下降求結果層

"""
對當前二維影象求最小點¶
1、隨機取一個點(x1,x2),設定α引數值  
2、對這個點分別求關於x1、x2的偏導數,x1 =x1 - α*(dY/dx1),x2 =x2 - α*(dY/dx2)  
3、重複第二補,設定 y的變化量 小於多少時 不再重複。
"""
# 二維原始影象
def f2(x, y):
    return 0.15 * (x + 0.5) ** 2 + 0.25 * (y  - 0.25) ** 2 + 0.35 * (1.5 * x - 0.2 * y + 0.35 ) ** 2  
## 偏函式
def hx1(x, y):
    return 0.15 * 2 * (x + 0.5) + 0.25 * 2 * (1.5 * x - 0.2 * y + 0.35 ) * 1.5
def hx2(x, y):
    return 0.25 * 2 * (y  - 0.25) - 0.25 * 2 * (1.5 * x - 0.2 * y + 0.35 ) * 0.2

x1 = 4
x2 = 4
alpha = 0.5
#儲存梯度下降經過的點
GD_X1 = [x1]
GD_X2 = [x2]
GD_Y = [f2(x1,x2)]
# 定義y的變化量和迭代次數
y_change = f2(x1,x2)
iter_num = 0

while(y_change > 1e-10 and iter_num < 100) :
    tmp_x1 = x1 - alpha * hx1(x1,x2)
    tmp_x2 = x2 - alpha * hx2(x1,x2)
    tmp_y = f2(tmp_x1,tmp_x2)
    
    f_change = np.absolute(tmp_y - f2(x1,x2))
    x1 = tmp_x1
    x2 = tmp_x2
    GD_X1.append(x1)
    GD_X2.append(x2)
    GD_Y.append(tmp_y)
    iter_num += 1
print(u"最終結果為:(%.5f, %.5f, %.5f)" % (x1, x2, f2(x1,x2)))
print(u"迭代過程中X的取值,迭代次數:%d" % iter_num)
print(GD_X1)

# 作圖
fig = plt.figure(facecolor='w',figsize=(20,18))
ax = Axes3D(fig)
ax.plot_surface(X1,X2,Y,rstride=1,cstride=1,cmap=plt.cm.jet)
ax.plot(GD_X1,GD_X2,GD_Y,'ko-')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

ax.set_title(u'函式;\n學習率:%.3f; 最終解:(%.3f, %.3f, %.3f);迭代次數:%d' % (alpha, x1, x2, f2(x1,x2), iter_num))
plt.show()