【深度学习基础】神经网络的学习(1)
神经网络解决问题时,一般分为两个阶段:
1. 模型训练阶段。模型训练会基于训练集获取最佳的权重和偏置,这也是模型构建、学习的过程。
2. 预测阶段。预测就是根据学习到的最优参数,对测试集或新数据集上的数据进行回归预测或分类,这是模型的使用过程。
本文主要重点在模型的学习过程,也就是最优参数的确定的过程。
人工指定参数 && 特征选择 && 自动提取有效信息
在处理手写数字识别的问题中,我们可以采用多种处理方式:
1. 人工指定参数。类似于感知机设计与门、与非门、或门,需要我们根据经验和理论推导尝试、验证参数,才能很好的构造出模型,并且,对复杂的场景,人工确定参数的确效率很低。
2. 特征选择。由人指定核心的特征,使用SIFT、SURF、HOG等算法,提取图像中的有效信息,基于SVN,KNN等算法进行数字识别,这是机器学习的路子。
3. 自动提取有效信息。基于神经网络的学习,可以直接把图像作为输入,无需我们人工指定有效信息,有效特征是什么,让模型自己从数据中学习。

由此看来,神经网络的学习,就是一种从输入数据中自动提取有效信息,构造出最佳参数模型的过程。
训练数据、测试数据
什么是训练数据?什么是测试数据?
训练数据是神经网络在学习过程中使用的数据,这些数据用于最优参数的确定,达到学习的目的。
测试数据是在模型构建好以后,用于验证模型性能好坏的数据。
为什么要划分训练数据和测试数据?
训练和测试是神经网络解决问题的两个阶段,我们不能在训练数据上构建模型的同时,再同样在训练数据上验证我们模型的好坏,这是容易导致过拟合的。
什么是过拟合?
过拟合就是模型在训练集上效果显著,在测试集上效果很差的现象。
代价函数(损失函数)
代价函数是用于在神经网络模型构建的过程中,去判断当前的参数是否更加接近最优,或者偏离了最优的一种衡量工具。常用的损失函数有:均方误差、交叉熵误差。
均方误差

均方误差的公式如上,它的计算就是,对预测值和真实值直接的差的平方求和再乘以1/2.均方误差越小,参数越接近最优值。
例如在手写数字识别中,输出是10个值:
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
那么代价的计算为:

代码实现更加简单:
def mean_squared_error(y, t):
return 0.5 * np.sum((y-t)**2)
这里采用的是预测值与真实值差的平方,为何要进行平方计算呢?直接作差不行吗?
使用平方可以解决正负误差抵消的问题。
[0.5, 0, 0.5]
[1, 0, 0]
如果直接使用差计算,(0.5-1) + (0-0) + (0.5 - 0) = 0, 实际上第一个和第三个值误差很大,这里却把误差给抵消了。而求平方却没有这个问题。
交叉熵误差
交叉熵误差也常用于计算损失函数,

取的是真实值与预测值的对数乘积求和的相反数,误差越小,参数越精准。
以手写数字识别为例:
>>> y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
>>> t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
其代价计算为:

我们发现,只有标签为1的一项起到作用。
代码实现:
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
为了避免溢出,这里在计算对数值时,加上了一个很小的数。
mini-batch
在实际的训练过程中,我们需要计算训练样本的整体的误差,而不仅仅是单个样本的误差,以交叉熵误差函数为例,实际的误差计算应该是:

无非是对每个样本的误差求和,再求平均值。
但是如果训练集很大,对每个样本进行训练会很繁琐,一般会抽取一部分数据进行学习和验证计算:
1. 加载数据
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000, 10)
我们发现训练数据有60000条
2. 抽取训练数据
# 训练集的大小
train_size = x_train.shape[0]
# mini-batch大小
batch_size = 10
# 产生随机的索引
batch_mask = np.random.choice(train_size, batch_size)
# mini-batch的训练数据
x_batch = x_train[batch_mask]
# mini-batch的标签
t_batch = t_train[batch_mask]
对于上面的交叉熵的计算实现,仅仅针对单个样本的损失进行计算,下面改造一下,可以适用于多个样本:
def cross_entropy_error(y, t):
# 如果是单个样本
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
# 获取样本数量
batch_size = y.shape[0]
# 计算批量的交叉熵误差
return -np.sum(t * np.log(y + 1e-7)) / batch_size
更多推荐
所有评论(0)