python实现两层神经网络识别手写数字体(2)

# coding: utf-8
from collections import OrderedDict

try:
    import urllib.request
except ImportError:
    raise ImportError('You should use Python 3.x')

import numpy as np
import mnist


def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x-np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
    return y.T

    x = x-np.max(x)
    return np.exp(x) / np.sum(np.exp(x))


def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

        # 监督数据是one-hot-vector的情况下,转换为正确解标签的索引
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size


class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None

    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x * y
        return out

    def backward(self, dout):
        dx = dout * self.y # 翻转x和y
        dy = dout * self.x
        return dx, dy


class Relu:
    def __init__(self):
        self.mask = None

    def forward(self, x):
        # 获取x数组中小于0的元素的索引
        self.mask = (x <= 0)
        out = x.copy()    # out变量表示要正向传播给下一层的数据,即上图中的y
        # ##请补充代码将x数组中小于0的元素赋值为0
        out[self.mask] = 0
        return out

    def backward(self, dout):
        dout[self.mask] = 0
        # ##请补充代码完成Relu层的反向传播
        dx = dout
        return dx


class Linear:
    def __init__(self, W, b):
        self.W = W  # 权重参数
        self.b = b  # 偏置参数
        self.x = None  # 用于保存输入数据
        # 定义成员变量用于保存权重和偏置参数的梯度
        self.dW = None
        self.db = None

    # 全连接层的前向传播
    def forward(self, x):
        # 保存输入数据到成员变量用于backward中的计算
        self.x = x
        # ##请补充代码求全连接层的前向传播的输出保存到变量out中
        out = np.dot(self.x,self.W) + self.b
        return out

    # 全连接层的反向传播
    def backward(self, dout):
        # ##请同学补充代码完成求取dx,dw,db,dw,db保存到成员变量self.dW,self.db中
        self.dW = np.dot(self.x.T, dout)
        dx = np.dot(dout, self.W.T)
        db = np.sum(dout, axis=0)

        return dx


class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None  # softmax的输出
        self.t = None  # 监督数据

    # SoftmaxWithLoss层的前向传播函数
    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)  # ## 请补充代码获取预测值
        self.loss = cross_entropy_error(self.y, self.t)  # ## 请补充代码获取模型损失
        return self.loss

    # SoftmaxWithLoss层的反向传播函数
    def backward(self, dout=1):
        # ##请补充代码完成求取SoftmaxWithLoss层的反向传播的输出
        # 注意:反向传播时将要传播的值除以批的大小,传递给前面层的是单个数据的误差
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        return dx


class TwoLayerNet:
    # 模型初始化
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 初始化权重
        self.params = {'W1': weight_init_std * np.random.randn(input_size, hidden_size), 'b1': np.zeros(hidden_size),
                       'W2': weight_init_std * np.random.randn(hidden_size, output_size), 'b2': np.zeros(output_size)}
        # 获取第一层权重和偏置
        # 获取第二层权重和偏置

        # 生成层
        # 将神经网络的层保存为有序字典OrderedDict
        self.layers = OrderedDict()
        # 添加第一个全连接层到有序字典中
        self.layers['Linear1'] = Linear(self.params['W1'], self.params['b1'])
        # ##请补充代码添加激活函数层和第二个全连接层到有序字典中
        self.layers['Linear2'] = Linear(self.params['W2'], self.params['b2'])
        # 将SoftmaxWithLoss类实例化为self.lastLayer
        self.lastLayer = SoftmaxWithLoss()

    # 通过前向传播获取预测值

    def predict(self, x):
        # 遍历有序字典
        for layer in self.layers.values():
            x = layer.forward(x)  # ## 请补充代码完成神经网络层的前向传播
        return x

    # x:输入数据, t:监督数据
    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)
        t = np.argmax(t, axis=1)
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

        # 求梯度

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

        # backward
        dout = 1
        # ##请补充代码求最后SoftmaxWithLoss层的反向传播输出

        # 从后往前遍历有序字典
        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            # ##请补充代码获取正在被遍历的层的反向传播输出
            dout = layer.backward(dout)
        # 设定
        grads = {}
        # 获取第一层网络参数的梯度
        grads['W1'], grads['b1'] = self.layers['Linear1'].dW, self.layers['Linear1'].db
        # ##请补充代码获取第二层网络参数的梯度
        grads['W2'], grads['b2'] = self.layers['Linear2'].dW, self.layers['Linear2'].db
        return grads

    # 主函数


if __name__ == '__main__':
    mnist.init_mnist()
(x_train, t_train), (x_test, t_test) = mnist.load_mnist(flatten=True, normalize=True, one_hot_label=True)
# print(t_train[0])
print(t_test[0])
# ##请补充实例化TwoLayerNet类创建network对象的代码
network = TwoLayerNet(input_size=784, hidden_size=100, output_size=10)  # 在这里调整参数
# 定义训练循环迭代次数
iters_num = 1000
# 获取训练数据规模
train_size = x_train.shape[0]
# 定义训练批次大小
batch_size = 100
# 定义学习率
learning_rate = 0.1

# 创建记录模型训练损失值的列表
train_loss_list = []
# 创建记录模型在训练数据集上预测精度的列表
train_acc_list = []
# 创建记录模型在测试数据集上预测精度的列表
test_acc_list = []

# 计算一个epoch所需的训练迭代次数(一个epoch定义为所有训练数据都遍历过一次所需的迭代次数)
iter_per_epoch = max(train_size / batch_size, 1)
# print(train_size)
# ##请补充创建训练循环的代码
for i in range(int(iters_num)):
    for j in range(int(iter_per_epoch)):
        # 在每次训练迭代内部选择一个批次的数据
        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]
# ##请补充向train_loss_list列表添加本轮迭代的模型损失值的代码
        loss = network.loss(x_batch, t_batch)
        train_loss_list.append(loss)

    # ##请补充向train_acc_list列表添加当前模型对于训练集预测精度的代码
    train_acc = network.accuracy(x_train, t_train)
    train_acc_list.append(train_acc)
    # ##请补充向test_acc_list列表添加当前模型对于测试集预测精度的代码
    test_acc = network.accuracy(x_test, t_test)
    test_acc_list.append(test_acc)
    # 输出一个epoch完成后模型分别在训练集和测试集上的预测精度以及损失值
    print("iteration:{} ,train acc:{}, test acc:{} ,loss:{}|".format(i, train_acc, test_acc, loss))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值