1 螺旋数据集

import sys
sys.path.append('..') # 为了引入父目录的文件而进行的设定
from dataset import spiral
import matplotlib.pyplot as plt


x, t = spiral.load_data()
print('x', x.shape) # (300, 2)
print('t', t.shape) # (300, 3)

x 是输入数据,t 是监督标签。观察 x 和 t 的形状,可知它们各自有 300 笔样本数据,其中 x 是二维数据,t 是三维数据。另外,t 是 one-hot 向量,对应的正确解标签的类标记为 1,其余的标记为 0。

下面,我们把这些数据绘制在图上,

# 绘制数据点
N = 100
CLS_NUM = 3
markers = ['o', 'x', '^']
for i in range(CLS_NUM):
    plt.scatter(x[i*N:(i+1)*N, 0], x[i*N:(i+1)*N, 1], s=40, marker=markers[i])
plt.show()

结果如图 1-31 所示。
在这里插入图片描述

图 1-31 学习用的螺旋状数据集(用×▲●分别表示 3 个类)
如图 1-31 所示,输入是二维数据,类别数是 3。观察这个数据集可知,它不能被直线分割。因此,我们需要学习非线性的分割线。那么,我们的神经网络(具有使用非线性的 sigmoid 激活函数的隐藏层的神经网络)能否正确学习这种非线性模式呢?让我们实验一下。

2 神经网络的实现

现在,我们来实现一个具有一个隐藏层的神经网络。首先,import 语句和初始化程序的__init__() 如下所示

import sys
sys.path.append('..')
import numpy as np
from common.layers import Affine, Sigmoid, SoftmaxWithLoss


class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size):
        I, H, O = input_size, hidden_size, output_size

        # 初始化权重和偏置
        W1 = 0.01 * np.random.randn(I, H)
        b1 = np.zeros(H)
        W2 = 0.01 * np.random.randn(H, O)
        b2 = np.zeros(O)

        # 生成层
        self.layers = [
            Affine(W1, b1),
            Sigmoid(),
            Affine(W2, b2)
        ]
        self.loss_layer = SoftmaxWithLoss()

        # 将所有的权重和梯度整理到列表中
        self.params, self.grads = [], []
        for layer in self.layers:
            self.params += layer.params
            self.grads += layer.grads        

初始化程序接收 3 个参数。input_size 是输入层的神经元数,hidden_size 是隐藏层的神经元数,output_size 是输出层的神经元数。在内部实现中,首先用零向量(np.zeros())初始化偏置,再用小的随机数(0.01 * np.random.randn())初始化权重。通过将权重设成小的随机数,学习可以更容易地进行。接着,生成必要的层,并将它们整理到实例变量 layers 列表中。最后,将这个模型使用到的参数和梯度归纳在一起。

接着,我们为 TwoLayerNet 实现 3 个方法,即进行推理的 predict() 方法、正向传播的 forward() 方法和反向传播的 backward() 方法

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

def forward(self, x, t): 
    score = self.predict(x)
    loss = self.loss_layer.forward(score, t)
    return loss

def backward(self, dout=1):
    dout = self.loss_layer.backward(dout)
    for layer in reversed(self.layers): 
        dout = layer.backward(dout)
    return dout

如上所示,这个实现非常清楚。因为我们已经将神经网络中要用的处理模块实现为了层,所以这里只需要以合理的顺序调用这些层的 forward() 方法和 backward() 方法即可。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐