机器学习之简单神经网络

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

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