MNIST数据集,图像识别(四)

        接下来,我们来训练神经网络模型,但在此之前,需要介绍一下反向传播算法。

        反向传播(backpropagation),简称为BP算法,是一种能够计算网络梯度的算法,使用求导的链式法则计算神经网络相对于权重的损失梯度,它工作的原理可以理解为是逐层求导,就是链式法则求导。我们使用BP算法就是用来计算神经网络中权重的梯度,从而进行模型的训练。但是,这与我们之前所用的梯度下降法是有区别的。

        我们知道,正向传播的方向是从输入到输出,反向传播的方向是从损失回到权重,通过链式法则积累局部梯度。

        接下,我们编写训练模型的代码,我们需要初始化权重,使用随机数值,破坏对称性,否则的权重都是一样的;采用较小的数值,加速训练,要避免模型训练的速度异常的缓慢,将会在代码中注释出来。

import numpy as np
import mnist as mi

def sigmoid(z):
    return 1 / (1 + np.exp(-z))


def softmax(logits):
    exponentials = np.exp(logits)
    return exponentials / np.sum(exponentials, axis=1).reshape(-1, 1)


# 从S型函数输出计算S型函数的梯度,帮助计算w1与w2
def sigmoid_gradient(sigmoid):
    return np.multiply(sigmoid, (1 - sigmoid))


def loss(Y, y_hat):
    return -np.sum(Y * np.log(y_hat)) / Y.shape[0]


def prepend_bias(X):
    return np.insert(X, 0, 1, axis=1)


def forward(X, w1, w2):
    h = sigmoid(np.matmul(prepend_bias(X), w1))
    y_hat = softmax(np.matmul(prepend_bias(h), w2))
    return (y_hat, h)


# 反向传播算法
def back(X, Y, y_hat, w2, h):
    w2_gradient = np.matmul(prepend_bias(h).T, (y_hat - Y)) / X.shape[0]
    w1_gradient = np.matmul(prepend_bias(X).T, np.matmul(y_hat - Y, w2[1:].T)
                            * sigmoid_gradient(h)) / X.shape[0]
    return w1_gradient, w2_gradient


def classify(X, w1, w2):
    y_hat, _ = forward(X, w1, w2)
    labels = np.argmax(y_hat, axis=1)
    return labels.reshape(-1, 1)


# 初始化权重,采用w=正负根号下r分之一,r是权重矩阵的行数
# n_hidden_nodes是隐藏节点
def initialize_weights(n_input_variables, n_hidden_nodes, n_classes):
    w1_rows = n_input_variables + 1
    w1 = np.random.randn(w1_rows, n_hidden_nodes) * np.sqrt(1 / w1_rows)  # 从标准正态分布中抽取一个随机数矩阵

    w2_rows = n_hidden_nodes + 1
    w2 = np.random.randn(w2_rows, n_classes) * np.sqrt(1 / w2_rows)

    return w1, w2


def report(iteration, X_train, Y_train, X_test, Y_test, w1, w2):
    y_hat, _ = forward(X_train, w1, w2)
    training_loss = loss(Y_train, y_hat)
    classifications = classify(X_test, w1, w2)
    accuracy = np.average(classifications == Y_test) * 100.0
    print("Iteration: %5d, Loss: %.8f, Accuracy: %.2f%%" %
          (iteration, training_loss, accuracy))


def train(X_train, Y_train, X_test, Y_test, n_hidden_nodes, iterations, lr):
    n_input_variables = X_train.shape[1]
    n_classes = Y_train.shape[1]
    w1, w2 = initialize_weights(n_input_variables, n_hidden_nodes, n_classes)
    for iteration in range(iterations):
        y_hat, h = forward(X_train, w1, w2)
        w1_gradient, w2_gradient = back(X_train, Y_train, y_hat, w2, h)
        w1 = w1 - (w1_gradient * lr)
        w2 = w2 - (w2_gradient * lr)
        report(iteration, X_train, Y_train, X_test, Y_test, w1, w2)
    return (w1, w2)




w1, w2 = train(mi.X_train, mi.Y_train,
               mi.X_test, mi.Y_test,
               n_hidden_nodes=200, iterations=10000, lr=0.01)

        至此,我们的训练模型已经完成,但需要说明的是权重是随机的,这种随机性不要担心,因为我们已经使它的随机性的值变得足够小了。可能最让人头疼的是原理的理解以及代码地编写,还有最令人费解的是超参数的选取,这些我们以后定能够处理!

        超参数是不断试出来的!

        预测可能需要耗费些时间,大约三个小时,我们来看下预测的结果: 

         这样的预测结果比我们之前处理的有所提高,但依旧还能改进。比如我们可以使用多层全连接神经网络以及卷积神经网络等,这就过渡到了深度学习,后续我们就可以把训练模型放到GPU上进行训练。

参考文献:

Programming Machine Learning: Form Coding to Deep Learning.[M],Paolo Perrotta,2021.6. 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值