BP神经网络初级入门

BP神经网络

  • 实验内容
  1. 构建BP神经网络(不使用任何框架),并完成手写体识别训练;

(2)画出训练轮数与精度(或损失)的曲线图

(3)调整超参数,分析参数对实验结果的影响,并完成实验报告

  • 实验过程

不断修改主要参数,记录识别率和损失率

三、训练、测试与结果展示:

训练参数信息如下:

轮数:共30轮

硬件资源:CPU

学习率:0.01

图片展示([784, 50, 30, 10]) :

图片展示([784, 50, 30, 10]) :

实验序号

(一)

(二)

(三)

(四)

(五)

(六)

参数

学习率

4

5

5

0.01

0.1

1

2

3

网络结构

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

[784, 30, 10]

迭代次数

30

30

100

30

30

30

30

30

batch_size

16

16

16

16

16

16

20

20

识别率

9536/10000

9532/10000

9534/10000

6776/10000

8175/10000

9390/10000

9484/10000

9508/10000

损失率

14.0207770

14.0182550

14.0215084

14.0116001

14.0297372

14.0178559

14.020316

14.022302

实验序号

十一

十二

十三

十四

十五

十六

参数

学习率

4

5

5

0.01

0.1

1

1

1

网络结构

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

[784, 50, 30, 10]

迭代次数

30

30

100

30

30

30

30

30

batch_size

16

16

16

16

16

16

10

25

识别率

9600/10000

9615/10000

9625/10000

6331/10000

9150/10000

9490/10000

9577/10000

9441/10000

损失率

14.0215315

14.0215077

14.0229458

13.9228511

14.00122955

14.018990

14.020514

14.018391

四、实验结论或体会

4.1 实验结论

【分析结果】每一个参数都可能对训练结果产生不一样的影响,要研究其对训练的影响我们需要不断修改各个参数,并观察结果分析其变化。

结论一:

观察实验六七八一二,我们可以发现其他不改变的情况下,只改变学习率的情况下,0.01的学习率下训练效果及其低下,而将其修改为一时训练效果就增加不少。而不断增加学习率训练效果不断增加直到学习率6到7时之间有个极大值,然后再增加学习率训练效果就会减少。而我们可以观察出来损失率几乎不变,或者是改变幅度不大。

结论二:

由实验(二)(三)对比,可以得出训练轮数可以提升训练效果,但是观察实验三的曲线图

可知增加训练轮数在一定程度上时训练效果增加幅度就不明显了。

结论三:

以实验一到六为实验组,九到十四为对照组我们可以发现两组改变了网络结构,其中对照组增加一层隐藏层。观察实验结果发现除了学习率为0.01的那组,其他对照组的识别率都增加很明显。

结论四:

观察实验十四、十五、十六这三组,改变的参数是batch_size——小批量样本大小,在其他参数一定的条件下,减少batch_size值,识别率会增加,但是如果改变学习率或者其他条件下是否还会有这样的结果,有待考证,需要另做实验来验证。

4.2 实验体会

通过本次BP神经网络实验,我深入理解了神经网络的结构和原理,尤其是反向传播算法在训练过程中的作用。在实验过程中,我不仅亲手构建了BP神经网络,还实现了手写体识别的训练,并绘制了训练轮数与精度(或损失)的曲线图,这使我更加直观地感受到了神经网络的学习过程。

在构建BP神经网络时,我遇到了不少挑战。比如,如何选择合适的网络结构(包括输入层、隐藏层和输出层的节点数)、激活函数以及学习率等参数,这些都需要根据具体的问题和数据集进行调试。通过不断调整和优化这些参数,我逐渐提高了模型的识别精度。

在实验过程中,我还深刻体会到了反向传播算法的重要性。通过反向传播,我们可以计算出每一层神经元的误差,并根据这些误差来更新神经元的权重和偏置。这样,网络就能够不断地学习和优化,从而提高识别的准确性。

此外,绘制训练轮数与精度(或损失)的曲线图也让我对神经网络的训练过程有了更直观的认识。通过观察曲线图,我可以清楚地看到模型在训练过程中的收敛情况,以及是否出现了过拟合或欠拟合等问题。

通过这次实验,我不仅掌握了BP神经网络的基本原理和训练方法,还学会了如何调整超参数来优化模型性能。同时,我也认识到了神经网络在实际应用中的潜力和挑战。

总的来说,这次实验让我收获颇丰。我不仅对神经网络有了更深入的理解,还提高了自己的编程和调试能力。我相信,在未来的学习和工作中,我会更加熟练地运用神经网络来解决实际问题。

4.3 实验代码

# 定义神经网络结构
import numpy as np
from random import random
from tqdm import trange
import matplotlib.pyplot as plt


class Network(object):
    def __init__(self, sizes):  # [3,2,2]
        # 网络层数
        self.num_layers = len(sizes)
        # 每层神经元个数
        self.sizes = sizes
        # 初始化每层的偏置
        self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
        # 初始化每层权重
        self.weights = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])]

    def feedforward(self, x):
        for b, w in zip(self.biases, self.weights):
            x = sigmoid(np.dot(w, x) + b)
        return x


    def SGD(self, training_data, epochs, eta, mini_batch_size, test_data=None):
        global n_test
        if test_data:
            n_test = len(test_data)
        n = len(training_data)
        accuracies = []
        losses = []
        for j in trange(epochs, desc='training', unit='epoch'):
            np.random.shuffle(training_data)
            n = len(training_data)
            mini_batches = [training_data[k:k + mini_batch_size] for k in range(0, n, mini_batch_size)]
            for mini_batch in mini_batches:
                nabla_b = [np.zeros(b.shape) for b in self.biases]
                nabla_w = [np.zeros(w.shape) for w in self.weights]
                for x, y in mini_batch:
                    delta_nabla_b, delta_nabla_w = self.backprop(x, y)
                    nabla_b = [nb + dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
                    nabla_w = [nw + dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
                self.biases = [b - (eta / len(mini_batch)) * nb for b, nb in zip(self.biases, nabla_b)]
                self.weights = [w - (eta / len(mini_batch)) * nw for w, nw in zip(self.weights, nabla_w)]

            if test_data:
                acc = self.evaluate(test_data)
                accuracies.append(acc / n_test)
                loss = self.total_loss(test_data)
                losses.append(loss)
                print(f"Epoch {j}: Accuracy {acc}/{n_test}, Loss: {loss}")

            print(f"Epoch {j} complete.")

        return accuracies, losses

    def total_loss(self, test_data):
        loss = 0.0
        for x, y in test_data:
            a = self.feedforward(x)
            loss += np.linalg.norm(a - y)  # L2 norm
        return loss / len(test_data)

    def evaluate(self, test_data):  # 计算正确识别的总量
        test_results = []
        for x, y in test_data:
            y_hat = np.argmax(self.feedforward(x))
            test_results.append((y_hat, y))
        return sum((int(y_hat == y)) for y_hat, y in test_results)

    # 反向传播求每层偏导
    def backprop(self, x, y):
        # 保存每一层偏导,初始化为全0
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        zs = []
        activation = x
        activations = [x]
        for b, w in zip(self.biases, self.weights):
            z = np.dot(w, activation) + b
            zs.append(z)
            activation = sigmoid(z)
            activations.append(activation)
        # 反向更新
        # 从最后一层开始,反着更新每一层的w,b
        # 最后一层
        delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(zs[-1])
        # 最后一层权重和偏执的导数
        nabla_b[-1] = delta
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())
        # 从倒数第二层到输入层
        for l in range(2, self.num_layers):
            sp = sigmoid_prime(zs[-l])
            # 计算当前层的误差
            delta = np.dot(self.weights[-l + 1].transpose(), delta) * sp
            # 保存当前层的偏置和权重的导数
            nabla_b[-l] = delta
            nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose())
        return nabla_b, nabla_w

    def cost_derivative(self, output_activation, y):
        return output_activation - y


# sigmoid函数
def sigmoid(z):
    return 1.0 / (1.0 + np.exp(-z))


def sigmoid_prime(z):
    return sigmoid(z) * (1 - sigmoid(z))


import mnist_loader



if __name__ == '__main__':
    net = Network([784, 50, 10])#神经元数量,输入层784个神经元,隐藏层30个,输出层10个
    training_data, test_data, _ = mnist_loader.load_data_wrapper()
    training_data = list(training_data)
    test_data = list(test_data)
    accuracies, losses = net.SGD(training_data, 30, 7, 16, test_data=test_data)
    #accuracies精度、losses损失

    # 训练轮数、学习效率、小批量样本大小
    # Plotting the results
    epochs = range(1, 31)
    plt.figure(figsize=(10, 5))
    batch_size = 0
    plt.subplot(1, 2, 1)
    plt.plot(epochs, accuracies, marker='o', linestyle='-')
    plt.title('Accuracy vs. Epochs')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')

    plt.subplot(1, 2, 2)
    plt.plot(epochs, losses, marker='o', linestyle='-')
    plt.title('Loss vs. Epochs')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')

    plt.tight_layout()
    plt.show()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值