機器學習之簡單神經網絡

0、引言

在感知機一節中講到感知機是一種線性模型,存在的缺點是很難解決非線性問題,比如異或(XOR)就是一種典型的線性不可分的問題,因此有了神經網絡,通過在感知機的結構中添加隱藏層來擬合非線性問題。
在這裏插入圖片描述

1、原理

後續補充。。。。。。。。。。。。。。。

2、代碼實現

神經網絡的構建過程:

  • 定義神經網絡結構(指定傳輸層、隱藏層、輸出層大小);
  • 初始化模型參數;
  • 循環操作:執行前向傳播/計算損失/執行反後向傳播/權值矩陣

常見參數優化算法(如:梯度下降法、隨機梯度下降、牛頓法、擬牛頓法、Adam)數學原理可以看下以下的博客:
https://blog.csdn.net/Zjhao666/article/details/88402518

import numpy as np
import matplotlib.pyplot as plt
from statsmodels.gam.tests.test_gam import sigmoid

#生成數據集
def create_dataset():
    np.random.seed(1) #隨機數種子,可以在某個種子堆中調用相同的額隨機數值
    #數據量
    m = 400
    #每個標籤的實例數
    N = int(m/2)
    #數據維度
    D = 2
    X = np.zeros((m, D)) #400*2
    Y = np.zeros((m,1), dtype = 'uint8')
    a = 4

    for j in range(2):
        ix = range(N*j, N*(j+1))
        #linspace(a,b,n) 在[2,3]上生成等間隔的N個數
        t = np.linspace(j * 3.12, (j + 1) * 3.12, N) + np.random.randn(N) * 0.2  # theta
        r = a * np.sin(4 * t) + np.random.randn(N) * 0.2  # radius
        #np.r_是按列連接兩個矩陣,就是把兩矩陣上下相加,要求列數相等。
        #np.c_是按行連接兩個矩陣,就是把兩矩陣左右相加,要求行數相等。
        X[ix] = np.c_[r * np.sin(t), r * np.cos(t)]
        Y[ix] = j

    X = X.T
    Y = Y.T
    return X, Y

#定義一個單隱藏層的神經網絡
def layer_sizes(X, Y):
    n_x = X.shape[0] #輸入層大小
    n_h = 4 #隱藏層大小
    n_y = Y.shape[0] #輸出層大小
    return (n_x, n_h, n_y)

#初始化模型參數
def initialize_parameters(n_x, n_h, n_y):
    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))

    #錯誤檢查,判斷
    assert (W1.shape == (n_h, n_x))
    assert (b1.shape == (n_h, 1))
    assert (W2.shape == (n_y, n_h))
    assert (b2.shape == (n_y, 1))

    #封裝成字典
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}

    return parameters

#前向傳播
def forward_propagation(X, parameters):
    # 獲取各參數初始值
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    # 執行前向計算
    Z1 = np.dot(W1, X) + b1  #dot矩陣點乘
    A1 = np.tanh(Z1)  #隱藏層使用tanh激活
    Z2 = np.dot(W2, A1) + b2
    A2 = sigmoid(Z2) #隱藏層使用sigmoid激活,作爲輸出y
    assert(A2.shape == (1, X.shape[1]))

    #保存前向傳播的結果
    cache = {"Z1": Z1,
             "A1": A1,
             "Z2": Z2,
             "A2": A2}

    return A2, cache

#計算當前訓練損失(交叉熵損失)
def compute_cost(A2, Y):
    # 訓練樣本量
    m = Y.shape[1]
    # 計算交叉熵損失
    logprobs = np.multiply(np.log(A2),Y) + np.multiply(np.log(1-A2), 1-Y)
    cost = -1/m * np.sum(logprobs)
    # 維度壓縮
    cost = np.squeeze(cost)

    assert(isinstance(cost, float))
    return cost

#反向傳播(梯度計算)
def backward_propagation(parameters, cache, X, Y):
    m = X.shape[1]
    # 獲取W1和W2
    W1 = parameters['W1']
    W2 = parameters['W2']
    # 獲取A1和A2
    A1 = cache['A1']
    A2 = cache['A2']
    # 執行反向傳播
    dZ2 = A2-Y
    dW2 = 1/m * np.dot(dZ2, A1.T)
    db2 = 1/m * np.sum(dZ2, axis=1, keepdims=True)
    dZ1 = np.dot(W2.T, dZ2)*(1-np.power(A1, 2))
    dW1 = 1/m * np.dot(dZ1, X.T)
    db1 = 1/m * np.sum(dZ1, axis=1, keepdims=True)

    #保存參數值
    grads = {"dW1": dW1,
             "db1": db1,
             "dW2": dW2,
             "db2": db2}
    return grads

#更新權值,這裏學習率a初始化爲1.2
def update_parameters(parameters, grads, learning_rate=1.2):
    # 獲取參數
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    # 獲取梯度
    dW1 = grads['dW1']
    db1 = grads['db1']
    dW2 = grads['dW2']
    db2 = grads['db2']

    # 參數更新
    W1 -= dW1 * learning_rate
    b1 -= db1 * learning_rate
    W2 -= dW2 * learning_rate
    b2 -= db2 * learning_rate

    #保存新參數
    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}
    return parameters

#組合成model,迭代次數爲10000
def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):
    np.random.seed(3)
    n_x = layer_sizes(X, Y)[0]
    n_y = layer_sizes(X, Y)[2]
    # 初始化模型參數
    parameters = initialize_parameters(n_x, n_h, n_y)

    # 梯度下降和參數更新循環
    for i in range(0, num_iterations):
        # 前向傳播計算
        A2, cache = forward_propagation(X, parameters)
        # 計算當前損失
        cost = compute_cost(A2, Y)
        # 反向傳播
        grads = backward_propagation(parameters, cache, X, Y)
        # 參數更新
        parameters = update_parameters(parameters, grads, learning_rate=1.2)
        # 打印損失
        if print_cost and i % 1000 == 0:
            print("Cost after iteration %i: %f" % (i, cost))

    return parameters

# 預測函數
def predict(parameters, X):
    A2, cache = forward_propagation(X, parameters)
    predictions = (A2>0.5)
    return predictions

#繪製決策邊界
def plot_decision_boundary(model, X, y):
    #邊界最大最小值
    x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1
    y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
    h = 0.01
    #網格圖大小
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = model(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)

#繪圖
def plot_Decision_Answer(X, Y):
    plt.figure(figsize=(16, 32))
    #設置不同隱藏層大小
    hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20]
    for i, n_h in enumerate(hidden_layer_sizes):
        plt.subplot(5, 2, i+1)
        plt.title('Hidden Layer of size %d' % n_h)
        #加載訓練模型
        parameters = nn_model(X, Y, n_h = 4,
                              num_iterations = 10000,
                              print_cost=False)
        plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y[0])
        #預測
        predictions = predict(parameters, X)
        #預測精度計算
        accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
        print ("Accuracy for {} hidden units: {}%".format(n_h, accuracy))
    plt.show()


def main():
    X, Y = create_dataset()
    # 數據可視化
    plt.scatter(X[0, :], X[1, :], c=Y[0], s=40, cmap=plt.cm.Spectral)
    # plt.show()
    #神經網絡
    plot_Decision_Answer(X, Y)


if __name__ == '__main__':
    main()

參考資料:
[1]https://blog.csdn.net/Zjhao666/article/details/88402518
[2]https://github.com/luwill/machine-learning-code-writing

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