作业2:BP 算法实验报告

作业2:BP 算法实验报告

1. 算法介绍

BP 算法全称叫做误差反向传播(error Back Propagation, 或者叫作误差逆传播)算法。现实任务中使用神经网络时,大多是在是使用 BP 算法进行训练。BP 算法不仅可以用户多层前馈神经网络,还可以用于其它类型的神经网络,例如训练递归神经网络。但通常说“BP 网络”时,一般是指用 BP 算法训练的多层前馈神经网络。

BP 神经网络是这样一种神经网络模型,它是由一个输入层、一个输出层和一个或多个隐层构成,它的激活函数采用 sigmoid 函数,采用 BP 算法训练构成前馈神经网络。
作业2:BP 算法实验报告_第1张图片

上图为一个单隐层前馈神经网络的拓扑结构,BP神经网络算法使用梯度下降法(gradient descent),以单个样本的均方误差的负梯度方向对权重进行调节。可以看出:BP算法首先将误差反向传播给隐层神经元,调节隐层到输出层的连接权重与输出层神经元的阈值;接着根据隐含层神经元的均方误差,来调节输入层到隐含层的连接权值与隐含层神经元的阈值。

2. 算法基本思想

算法基本思想:在前馈网络中,输入信号经过输入层输入,通过隐层计算由输出层输出,输出值与标记值比较,若有误差,将误差反向由输出层向输入层传播,在这个过程中,利用梯度下降算法对神经元权值进行调整。

BP 算法包括信号的向前传播和误差的反向传播两个过程。即计算误差输出时按从输入到输出的方向进行,而调整权值和阈值则从输出到输入的方向进行。

3. 算法流程

  1. 网络初始化:权值初始值使用较小的随机数设定。

  2. 输入 <输入向量>(向前)

    • 首先,将<输入向量>输给传输层;

    • <输入向量>向输出层传播;

    • 各神经元:求来自前层神经元的附加权值和,由传输函数决定输出值。如激活函数为 Gigmoid函数 f(x),则 输出值 = f(输入和)

  3. 向输出层输入 <教师信号>,将与 <输入向量> 对应的 <教师信号> 提供给输出层。

  4. 误差反传的权值学习:

    • 根据:新权值=旧权值×常数××(来自前一层的神经元输出) 进行权值更新。

    • 当激活函数为 Sigmoid 函数时,

    • 输出层:=(输出)×(1−输出)×[(教师信号)−(神经元输出)]

    • 隐层:=(输出)×(1−输出)×(来自紧接其后层的的附加权值和)

  5. 返回到 2,重复 2~4 进行权值学习。

4. 数据集介绍

本次实验采用经典的手写体识别数据集作为实验数据。MINST数据库是由Yann提供的手写数字数据库文件,其官方下载地址http://yann.lecun.com/exdb/mnist/。数据库的里的图像都是28*28大小的灰度图像,每个像素的是一个八位字节(0~255)。这个数据库主要包含了60000张的训练图像和10000张的测试图像,主要是下面的四个文件:

Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)
Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)
Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)
Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)

部分数据集如下:
作业2:BP 算法实验报告_第2张图片

5. 算法实现

5.1. 算法过程

作业2:BP 算法实验报告_第3张图片

网络结构包含一个输入层、一个隐层和一个输出层。其实总共只有两个层级结构。

5.2. 数据集导入

定义一个读取数据集的方法 load_mnist,方法的参数有:normalize 表示将图像的像素值正规化为 0.0~1.0,one_hot_labelTrue 的情况下,标签作为 one-hot 数组返回,one-hot 数组是指[0,0,1,0,0,0,0,0,0,0] 这样的数组;:flatten 表示是否将图像展开为一维数组。最终返回 (训练图像, 训练标签), (测试图像, 测试标签)

def load_mnist(normalize=True, flatten=True, one_hot_label=False):
    if not os.path.exists(save_file):
        init_mnist()
        
    with open(save_file, 'rb') as f:
        dataset = pickle.load(f)
    
    if normalize:
        for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].astype(np.float32)
            dataset[key] /= 255.0
            
    if one_hot_label:
        dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
        dataset['test_label'] = _change_one_hot_label(dataset['test_label'])
    
    if not flatten:
         for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].reshape(-1, 1, 28, 28)

    return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label']) 

5.3. 层级结构设计

定义一个两层的网络,输入层大小 input_size784,隐层大小 hidden_size50,输出层大小 output_size10。权重初始化 weight_init_std 默认设置为 0.01

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

隐层牵涉到权值参数与偏置项的设定。在未运行算法之前,需要对权重参数与偏置项进行初始化。权重初始化如下:

self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) 
self.params['b2'] = np.zeros(output_size)

生成层初始化:

self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = Relu()
self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])

定义损失函数:

def loss(self, x, t):
    y = self.predict(x)
    return self.lastLayer.forward(y, t)

定义精度:

def accuracy(self, x, t):
    y = self.predict(x)
    y = np.argmax(y, axis=1)
    if t.ndim != 1 : t = np.argmax(t, axis=1)
    
    accuracy = np.sum(y == t) / float(x.shape[0])
    return accuracy

定义预测方法:

def predict(self, x):
    for layer in self.layers.values():
        x = layer.forward(x)
    
    return x

定义梯度下降方法 gradientx 表示输入数据。t 表示监督数据。w1b1w2b2:分别代表隐层的突触权重、偏置项,输出层的突触权重、偏置项。激活函数设定为 relu 函数。

def gradient(self, x, t):
    self.loss(x, t)

    dout = 1
    dout = self.lastLayer.backward(dout)
    
    layers = list(self.layers.values())
    layers.reverse()
    for layer in layers:
        dout = layer.backward(dout)

    grads = {}
    grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
    grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db

    return grads

5.4. 算法迭代过程

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    grad = network.gradient(x_batch, t_batch)
    
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
    
    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)
    
    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print(train_acc, test_acc)

5.5. 训练结果

作业2:BP 算法实验报告_第4张图片
从训练结果不难看出,精度不断升,并最终稳定在 0.9797 左右。

你可能感兴趣的:(机器学习课程作业,BP算法)