深度学习入门(4)【深度学习实战】无框架实现两层神经网络的搭建与训练过程

简介: 深度学习入门(4)【深度学习实战】无框架实现两层神经网络的搭建与训练过程

上一篇文章《深度学习入门(3)神经网络参数梯度的计算方式》主要介绍神经网络中的参数梯度是如何计算的。本文将直接使用之前公众号介绍过损失函数、激活函数以及梯度计算直接手动实现一个两层的神经网络训练过程。


也许有人会说使用pytorch或者tensorflow框架,几行代码就可以搭建一个神经网络,为什么要自己手动去实现呢?我觉得使用现成框架确实很容易搭建一个神经网络,但是对于其中的计算原理如果不了解的话,那始终只会停在使用框架的基础上,如果能够自己亲手去了解其中的工作原理,手动去实现一下,也许能够对其有更深刻的理解,这也能够为后续自己去更好的优化一个神经网络提供基础。


本文将介绍一个两层神经网络的搭建过程,并且以手写体数字集Mnist对所搭建的神经网络进行训练。

神经网络的训练过程

20201129225408441.png

20201129225441738.png


神经网络的学习按照上面4个步骤进行。这个方法通过梯度下降法更新参数,不过因为这里使用的数据是随机选择的mini batch数据,所以又称为随机梯度下降法( stochastic gradient descent)—SGD。“随机”指的是“随机选择的”的意思,因此,随机梯度下降法是“对随机选择的数据进行的梯度下降法”。深度学习的很多框架中,随机梯度下降法一般由一个名为SGD的函数来实现。SGD来源于随机梯度下降法的英文名称的首字母。


构建辅助函数


首先我们先将之前文章中的损失函数激活函数以及梯度计算的代码给弄过来,用于辅助神经网络的构建。如果对于这几个函数不太清楚可以点击相应链接,看之前写过的文章。


def sigmoid(x):
    # sigmoid激活函数
    return 1 / (1 + np.exp(-x))
def sigmoid_grad(x):
    # 计算sigmoid激活函数的梯度
    return (1.0 - sigmoid(x)) * sigmoid(x)
def softmax(x):
    # softmax激活函数,用于输出层
    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
def numerical_gradient(f, x):
    # 计算损失函数f的参数x的梯度
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)  # f(x+h)
        x[idx] = tmp_val - h
        fxh2 = f(x)  # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2 * h)
        x[idx] = tmp_val  # 还原值
        it.iternext()
    return grad


二层神经网络的搭建


class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 初始化权重
        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)
    def predict(self, x):
        # 对输入x进行预测,并输出预测值y
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        return y
    # x:输入数据, t:监督数据
    def loss(self, x, t):
        y = self.predict(x)
        # 使用交叉熵误差作为目标损失函数
        return cross_entropy_error(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
    # x:输入数据, t:监督数据
    def numerical_gradient(self, x, t):
        # 使用数值微分来计算梯度
        # loss_W为损失函数
        loss_W = lambda W: self.loss(x, t)
        grads = {}
        # 计算各个参数的梯度
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        return grads
    def gradient(self, x, t):
        # 使用误差的反向传播来计算梯度
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        grads = {}
        batch_num = x.shape[0]
        # forward
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        # backward
        dy = (y - t) / batch_num
        grads['W2'] = np.dot(z1.T, dy)
        grads['b2'] = np.sum(dy, axis=0)
        da1 = np.dot(dy, W2.T)
        dz1 = sigmoid_grad(a1) * da1
        grads['W1'] = np.dot(x.T, dz1)
        grads['b1'] = np.sum(dz1, axis=0)
        return grads


各个参数说明如下:


20201129225528325.png

20201129225554135.png

该代码中包含两种参数梯度的计算方式numerical_gradient与gradient,其中numerical_gradient是使用的之前文章讲过的数值微分的方式计算参数梯度值的,而gradient则是使用的误差的反向传播来计算梯度值的,这种计算方式比微分方式计算梯度值更加快速。因此,在使用神经网络梯度计算通常会使用误差的反向传播来计算梯度。这个后续文章会进行详细讲解。


神经网络的训练


以上两层的神将网络已经搭建好了,下面我们以经典的手写体数字识别mnist数字集,使用上述神经网络进行训练,过程如下:


# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
x_train = x_train[:5000] #仅选择前5000个数据进行训练测试
x_test = x_test[:5000]
train_loss_list = [] # 记录误差的变化情况
# 超参数
iters_num = 6000  # 设定迭代的次数
train_size = x_train.shape[0]
batch_size = 100 # 每一批取100个样本
learning_rate = 0.1
# 设置输入层784, 隐藏层50,层50
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
    # 获取mini-batch
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    # 计算梯度
    #数值方式计算梯度
    # grad = network.net_numerical_gradient(x_batch, t_batch) 
    # 误差的反向传播方式计算梯度
    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:
        print("train loss," + str(loss))
# 将每一步训练的结果得到的损失函数值打印出来
x = np.arange(len(train_loss_list))
plt.plot(x, train_loss_list, label='train loss')
plt.xlabel("iteration")
plt.ylabel("loss")
plt.show()


上述得到损失函数值随训练的推移如下:


2020112922591614.png

由上图可以发现随着学习的进行,损失函数的值在不断减小。说明神经网络的权重参数在逐渐拟合数据,并逐渐向最优参数靠近。

然后使用训练得到的神经网络,即可对未知的数据集进行预测。下一篇文章会介绍对神经网络的评估过程。

相关文章
|
4天前
|
网络协议 安全 Linux
网络入门基础
网络入门基础
5 0
|
5天前
|
存储 网络协议 Linux
RTnet – 灵活的硬实时网络框架
本文介绍了开源项目 RTnet。RTnet 为以太网和其他传输媒体上的硬实时通信提供了一个可定制和可扩展的框架。 本文描述了 RTnet 的架构、核心组件和协议。
18 0
RTnet – 灵活的硬实时网络框架
|
5天前
|
机器学习/深度学习 算法 TensorFlow
Python深度学习基于Tensorflow(6)神经网络基础
Python深度学习基于Tensorflow(6)神经网络基础
16 2
Python深度学习基于Tensorflow(6)神经网络基础
|
12天前
|
机器学习/深度学习 自然语言处理 搜索推荐
|
14天前
|
机器学习/深度学习 自然语言处理 语音技术
【Python 机器学习专栏】Python 深度学习入门:神经网络基础
【4月更文挑战第30天】本文介绍了Python在深度学习中应用于神经网络的基础知识,包括神经网络概念、基本结构、训练过程,以及Python中的深度学习库TensorFlow和PyTorch。通过示例展示了如何使用Python实现神经网络,并提及优化技巧如正则化和Dropout。最后,概述了神经网络在图像识别、语音识别和自然语言处理等领域的应用,并强调掌握这些知识对深度学习的重要性。随着技术进步,神经网络的应用将持续扩展,期待更多创新。
|
14天前
|
机器学习/深度学习 人工智能 自然语言处理
工智能基础:神经网络与深度学习
【4月更文挑战第30天】本文探讨了神经网络和深度学习在AI中的核心作用。深度学习,特别是CNN和RNN/LSTM,用于图像和序列数据处理。训练过程涉及前向传播、损失函数和反向传播。关键技术包括梯度下降、正则化和批量归一化。应用广泛,如图像识别、自然语言处理、推荐系统和游戏。随着技术发展,深度学习的应用将持续增长。
|
14天前
|
存储 监控 安全
【亮剑】指导初学者如何搭建和使用网络视频监控系统。
【4月更文挑战第30天】本文指导初学者如何搭建和使用网络视频监控系统。核心设备包括摄像头(如固定、PTZ、多目、夜视)、存储选项(NVR、DVR、云存储)及网络交换机等。安装配置步骤涉及规划布局、安装摄像头、设置存储设备和软件配置。实时监控包括实时查看、接收警报和录像回放。理解设备功能、合理布局并细心操作,就能建立稳定监控体系。随着技术进步,未来监控系统将更智能、高效,保障安全。
|
16天前
|
机器学习/深度学习 算法 TensorFlow
TensorFlow 2keras开发深度学习模型实例:多层感知器(MLP),卷积神经网络(CNN)和递归神经网络(RNN)
TensorFlow 2keras开发深度学习模型实例:多层感知器(MLP),卷积神经网络(CNN)和递归神经网络(RNN)
|
16天前
|
机器学习/深度学习 算法 数据可视化
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究
|
3天前
|
网络协议 Linux 网络架构