1. 程式人生 > >吳裕雄 python 機器學習——人工神經網絡與原始感知機模型

吳裕雄 python 機器學習——人工神經網絡與原始感知機模型

res true 組成 param 個數 its import sample gen

import numpy as np

from matplotlib import  pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn.neural_network import MLPClassifier

def creat_data(n):
    ‘‘‘
    創建線性可分數據集

    :param n: 正例樣本的個數(同時也是負例樣本的個數)
    :return: 返回一個線性可分數據集,數據集大小為 2*n
    ‘‘‘
    np.random.seed(
1) x_11=np.random.randint(0,100,(n,1)) # 第一組:第一維坐標值 x_12=np.random.randint(0,100,(n,1,))# 第一組:第二維坐標值 x_13=20+np.random.randint(0,10,(n,1,))#第一組: 第三維坐標值 x_21=np.random.randint(0,100,(n,1)) # 第二組:第一維坐標值 x_22=np.random.randint(0,100,(n,1)) # 第二組:第二維坐標值 x_23=10-np.random.randint(0,10,(n,1,)) #
第二組:第三維坐標值 new_x_12=x_12*np.sqrt(2)/2-x_13*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_13=x_12*np.sqrt(2)/2+x_13*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_22=x_22*np.sqrt(2)/2-x_23*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_23=x_22*np.sqrt(2)/2+x_23*np.sqrt(2)/2## 沿第一維軸旋轉45度 plus_samples=np.hstack([x_11,new_x_12,new_x_13,np.ones((n,1))]) #
拼接成正例數據集 minus_samples=np.hstack([x_21,new_x_22,new_x_23,-np.ones((n,1))]) # 拼接成負例數據集 samples=np.vstack([plus_samples,minus_samples]) # 拼接成完整數據集 np.random.shuffle(samples) # 混洗數據 return samples def creat_data_no_linear(n): ‘‘‘ 創建線性不可分數據集 :param n: 正例樣本的個數(同時也是負例樣本的個數) :return: 返回一個線性不可分數據集,數據集大小為 2*n ‘‘‘ np.random.seed(1) x_11=np.random.randint(0,100,(n,1))# 第一組:第一維坐標值 x_12=np.random.randint(0,100,(n,1,))# 第一組:第二維坐標值 x_13=10+np.random.randint(0,10,(n,1,))#第一組: 第三維坐標值 x_21=np.random.randint(0,100,(n,1))# 第二組:第一維坐標值 x_22=np.random.randint(0,100,(n,1))# 第二組:第二維坐標值 x_23=20-np.random.randint(0,10,(n,1,)) # 第二組:第三維坐標值 new_x_12=x_12*np.sqrt(2)/2-x_13*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_13=x_12*np.sqrt(2)/2+x_13*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_22=x_22*np.sqrt(2)/2-x_23*np.sqrt(2)/2## 沿第一維軸旋轉45度 new_x_23=x_22*np.sqrt(2)/2+x_23*np.sqrt(2)/2## 沿第一維軸旋轉45度 plus_samples=np.hstack([x_11,new_x_12,new_x_13,np.ones((n,1))])# 拼接成正例數據集 minus_samples=np.hstack([x_21,new_x_22,new_x_23,-np.ones((n,1))])# 拼接成負例數據集 samples=np.vstack([plus_samples,minus_samples])# 拼接成完整數據集 np.random.shuffle(samples) # 混洗數據 return samples def plot_samples(ax,samples): ‘‘‘ 繪制樣本點 :param ax: 繪制圖形所在的 Axes :param samples: 樣本數據集 :return: None ‘‘‘ Y=samples[:,-1] # 標記信息 position_p=Y==1 ## 正類位置 position_m=Y==-1 ## 負類位置 # 繪制正類樣本點 ax.scatter(samples[position_p,0],samples[position_p,1],samples[position_p,2],marker=+,label=+,color=b) # 繪制負類樣本點 ax.scatter(samples[position_m,0],samples[position_m,1],samples[position_m,2],marker=^,label=-,color=y)
def run_plot_samples():
    ‘‘‘
    繪制線性可分數據集

    :return: None
    ‘‘‘
    fig=plt.figure()
    ax=Axes3D(fig)
    data=creat_data(100) # 產生線性可分數據集
    plot_samples(ax,data)
    ax.legend(loc=best)
    plt.show()
    
run_plot_samples()

技術分享圖片

def run_plot_samples_no_linear():
    ‘‘‘
    繪制線性不可分數據集

    :return: None
    ‘‘‘
    data=creat_data_no_linear(100)# 產生線性不可分數據集
    fig=plt.figure()
    ax=Axes3D(fig)
    plot_samples(ax,data)
    ax.legend(loc=best)
    plt.show()
    
run_plot_samples_no_linear()

技術分享圖片

def perceptron(train_data,eta,w_0,b_0):
    ‘‘‘
    感知機的原始算法

    :param train_data: 訓練數據集
    :param eta: 學習率
    :param w_0: 初始權重向量
    :param b_0: 初始的 b
    :return: 一個元組,依次為:最終的權重向量,最終的 b 值,叠代次數
     ‘‘‘
    x=train_data[:,:-1]  # x 數據
    y=train_data[:,-1]  #  對應的標記
    length= train_data.shape[0] #樣本集大小
    w=w_0
    b=b_0
    step_num=0
    while True:
        i=0
        while(i< length): ## 遍歷一輪樣本集中的所有的樣本點
            step_num+=1
            ‘‘‘
          當應用於線性不可分數據集時,用下面4行代替上面的 step_num+=1 這一行。如果不這麽做,那麽當用於線性
          不可分數據集時,叠代永遠不會停止。
            step_num+=1
            if step_num>=10000000:
                print("failed!,step_num =%d"%step_num)
                return
          ‘‘‘
            x_i=x[i].reshape((x.shape[1],1)) # 變成列向量,因為需要執行 np.dot 函數
            y_i=y[i]
            if y_i*(np.dot(np.transpose(w),x_i)+b) <=0: # 該點是誤分類點
                w=w+eta*y_i*x_i  # 梯度下降
                b=b+eta*y_i      # 梯度下降
                break # 執行下一輪篩選
            else:#該點不是誤分類點,選取下一個樣本點
                i=i+1
        if(i== length): #沒有誤分類點,結束循環
            break
    return (w,b,step_num)
    

def creat_hyperplane(x,y,w,b):
    ‘‘‘
    創建分離超平面

    :param x: 分離超平面上的點的x坐標組成的數組
    :param y: 分離超平面上的點的y坐標組成的數組
    :param w: 超平面的法向量,它是一個列向量
    :param b: 超平面的截距
    :return: 分離超平面上的點的z坐標組成的數組
    ‘‘‘
    return (-w[0][0]*x-w[1][0]*y-b)/w[2][0] # w0*x+w1*y+w2*z+b=0
def run_perceptron():
    ‘‘‘
    對線性可分數據集執行感知機的原始算法並繪制分離超平面
    ‘‘‘
    data=creat_data(100) #產生線性可分數據集
    eta,w_0,b_0=0.1,np.ones((3,1),dtype=float),1 # 初始化 學習率、權重、 b
    w,b,num=perceptron(data,eta,w_0,b_0) # 執行感知機的原始形式
    ### 繪圖
    fig=plt.figure()
    plt.suptitle("perceptron")
    ax=Axes3D(fig)

    ### 繪制樣本點
    plot_samples(ax,data)

    ##  繪制分離超平面
    x=np.linspace(-30,100,100)  # 分離超平面的 x坐標數組
    y=np.linspace(-30,100,100) # 分離超平面的 y坐標數組
    x,y=np.meshgrid(x,y) # 劃分網格
    z=creat_hyperplane(x,y,w,b)  # 分離超平面的 z坐標數組
    ax.plot_surface(x, y, z, rstride=1, cstride=1,color=g,alpha=0.2)

    ax.legend(loc="best")
    plt.show()
    
run_perceptron()

技術分享圖片

def perceptron_nolinear(train_data,eta,w_0,b_0):
    ‘‘‘
    感知機的原始算法

    :param train_data: 訓練數據集
    :param eta: 學習率
    :param w_0: 初始權重向量
    :param b_0: 初始的 b
    :return: 一個元組,依次為:最終的權重向量,最終的 b 值,叠代次數
     ‘‘‘
    x=train_data[:,:-1]  # x 數據
    y=train_data[:,-1]  #  對應的標記
    length= train_data.shape[0] #樣本集大小
    w=w_0
    b=b_0
    step_num=0
    while True:
        i=0
        while(i< length): ## 遍歷一輪樣本集中的所有的樣本點
            step_num+=1
            if step_num>=10000000:
                print("failed!,step_num =%d"%step_num)
                return
            x_i=x[i].reshape((x.shape[1],1)) # 變成列向量,因為需要執行 np.dot 函數
            y_i=y[i]
            if y_i*(np.dot(np.transpose(w),x_i)+b) <=0: # 該點是誤分類點
                w=w+eta*y_i*x_i  # 梯度下降
                b=b+eta*y_i      # 梯度下降
                break # 執行下一輪篩選
            else:#該點不是誤分類點,選取下一個樣本點
                i=i+1
        if(i== length): #沒有誤分類點,結束循環
            break
    return (w,b,step_num)
    

def creat_hyperplane(x,y,w,b):
    ‘‘‘
    創建分離超平面

    :param x: 分離超平面上的點的x坐標組成的數組
    :param y: 分離超平面上的點的y坐標組成的數組
    :param w: 超平面的法向量,它是一個列向量
    :param b: 超平面的截距
    :return: 分離超平面上的點的z坐標組成的數組
    ‘‘‘
    return (-w[0][0]*x-w[1][0]*y-b)/w[2][0] # w0*x+w1*y+w2*z+b=0
def run_perceptron_no_linear():
    ‘‘‘
    對線性不可分數據集執行感知機的元素算法
    ‘‘‘
    data=creat_data_no_linear(100)#產生線性不可分數據集
    perceptron_nolinear(data,eta=0.1,w_0=np.zeros((3,1)),b_0=0)
    
run_perceptron_no_linear()

技術分享圖片

def creat_w(train_data,alpha):
    ‘‘‘
    根據訓練數據集和 alpha向量 創建 權重向量

    :param train_data: 訓練數據集
    :param alpha: alpha 向量
    :return: 權重向量
    ‘‘‘
    x=train_data[:,:-1]  # x 數據
    y=train_data[:,-1]  #  對應的分類
    N= train_data.shape[0] #樣本集大小
    w=np.zeros((x.shape[1],1))
    for i in range(0,N):
        w=w+alpha[i][0]*y[i]*(x[i].reshape(x[i].size,1))
    return w
def perceptron_dual(train_data,eta,alpha_0,b_0):
    ‘‘‘
    感知機的對偶形式算法

    :param train_data: 訓練數據集
    :param eta: 學習率
    :param alpha_0: 初始的 alpha 向量
    :param b_0: 初始的 b 值
    :return: 一個元組,依次為:最終的alpha 向量、最終的 b 值、叠代次數
    ‘‘‘
    x=train_data[:,:-1]  # x 數據
    y=train_data[:,-1]  #  對應的分類
    length= train_data.shape[0] #樣本集大小
    alpha=alpha_0
    b=b_0
    step_num=0
    while True:
        i=0
        while(i< length):
            step_num+=1
            x_i=x[i].reshape((x.shape[1],1)) # 變形為列向量,因為需要調用 np.dot
            y_i=y[i]
            w=creat_w(train_data,alpha)
            z=y_i*(np.dot(np.transpose(w),x_i)+b)
            if z <=0: # 該點是誤分類點
                alpha[i][0]+=eta  # 梯度下降
                b+=eta*y_i  # 梯度下降
                break # 梯度下降了,從頭開始,執行下一輪篩選
            else:
                i=i+1 #該點不是誤分類點,選取下一個樣本點
        if(i== length ): #沒有誤分類點,結束循環
            break
    return (alpha,b,step_num)

def run_perceptron_dual():
    ‘‘‘
    對線性可分數據集執行感知機的原始算法和對偶形式算法,並繪制分離超平面
    ‘‘‘
    data=creat_data(100)
    eta,w_0,b_0=0.1,np.ones((3,1),dtype=float),1
    w_1,b_1,num_1=perceptron(data,eta,w_0,b_0) ##執行原始形式的算法
    alpha,b_2,num_2=perceptron_dual(data,eta=0.1,alpha_0=np.zeros((data.shape[0]*2,1)),
        b_0=0) # 執行對偶形式的算法
    w_2=creat_w(data,alpha)

    print("w_1,b_1",w_1,b_1)
    print("w_2,b_2",w_2,b_2)

    ## 繪圖
    fig=plt.figure()
    plt.suptitle("perceptron")
    ax=Axes3D(fig)

    ### 繪制樣本點
    plot_samples(ax,data)

    ##  繪制分離超平面
    x=np.linspace(-30,100,100)  # 分離超平面的 x坐標數組
    y=np.linspace(-30,100,100) # 分離超平面的 y坐標數組
    x,y=np.meshgrid(x,y) # 劃分網格
    z=creat_hyperplane(x,y,w_1,b_1)  # 原始形式算法的分離超平面的 z坐標數組
    z_2=creat_hyperplane(x,y,w_2,b_2)  # 對偶形式算法的分離超平面的 z坐標數組
    ax.plot_surface(x, y, z, rstride=1, cstride=1,color=g,alpha=0.2)
    ax.plot_surface(x, y, z_2, rstride=1, cstride=1,color=c,alpha=0.2)
    ax.legend(loc="best")
    plt.show()
    
run_perceptron_dual()

技術分享圖片

def test_eta(data,ax,etas,w_0,alpha_0,b_0):
    ‘‘‘
    測試學習率對於感知機兩種形式算法的收斂速度的影響

    :param data:  訓練數據集
    :param ax: Axes實例,負責繪制圖形
    :param etas: 候選的學習率的值組成的列表
    :param w_0: 原始算法用到的初始權重向量
    :param alpha_0: 對偶形式用到的初始 alpha 向量
    :param b_0: 初始 b 值
    :return: None
    ‘‘‘
    nums1=[]
    nums2=[]
    for eta in etas:
        _,_,num_1=perceptron(data,eta,w_0=w_0,b_0=b_0) # 獲取原始形式算法的叠代次數
        _,_,num_2=perceptron_dual(data,eta=0.1,alpha_0=alpha_0,b_0=b_0) # 獲取對偶形式算法的叠代次數
        nums1.append(num_1)
        nums2.append(num_2)
    ax.plot(etas,np.array(nums1),label=orignal iteraton times)
    ax.plot(etas,np.array(nums2),label=dual iteraton times)
    
def run_test_eta():
    fig=plt.figure()
    fig.suptitle("perceptron")
    ax=fig.add_subplot(1,1,1)
    ax.set_xlabel(r$\eta$)

    data=creat_data(20) # 創建線性可分數據集
    etas=np.linspace(0.01,1,num=25,endpoint=False)
    w_0,b_0,alpha_0=np.ones((3,1)),0,np.zeros((data.shape[0],1))
    test_eta(data,ax,etas,w_0,alpha_0,b_0)

    ax.legend(loc="best",framealpha=0.5)
    plt.show()
    
run_test_eta()

技術分享圖片

吳裕雄 python 機器學習——人工神經網絡與原始感知機模型