4.1 从数据中学习
深度学习的特点是数据驱动,端到端,极力避免人为干预。
将数据分为两拨
【 训练数据 || 测试数据 】
- 确保神经网络具有泛化能力。
- 避免过拟合(只对训练时采用的数据集效果较好)。
4.2 单个损失函数
loss:度量神经网络性能有多差,所以损失函数越小越好
损失函数类型:
- 均方误差:
E = \frac{1}{2}\sum_k(y_k-t_k)^2
- 交叉熵误差:
E = -\sum_kt_klog(y_k)
k : 输出量个数
y :输出量
t : 正确解标签
对比两种误差
输入:
import numpy as np
from functions import cross_entropy_error,mean_squared_error
y=np.array([0.02,0.9,0.01,0.01,0.06])
t=np.array([0,1,0,0,0])
sum1=mean_squared_error(y,t)
sum2=cross_entropy_error(y,t)
print("mean_squared_error:"+str(sum1))
print("cross_entropy_error:"+str(sum2))
输出:
mean_squared_error:0.007099999999999997
cross_entropy_error:0.1053604045467214
均方误差涉及到所有的输出及其对应的正确解标签
但是在one hot表示方法下,非正确解对应的标签tk=0,只有正确解对应的标签tk=1,所以交叉熵误差只关注正确解标签对应的输出
4.3 mini-batch学习
神经网络的是从总数据集中,随机抽出一批(mini-batch)数据进行学习,每学习一次,计算一次损失函数,再随机抽出一批数据进行学习,再计算损失函数,循环,追求损失函数最小化。
随机抽出一批数据的代码:
batch_mask = np.random.choice(train_size,batch_size) #从所有的索引中,随机抽出一批大小的索引
x_batch = x_train(batch_mask) #根据索引抽出对应的训练数据
y_batch = y_train(batch_mask) #根据索引抽出对应的正确解标签
计算每个mini-batch的交叉熵公式:
E = -\frac{1}{N}\sum_n\sum_kt_{nk}log(y_k)
N为每个mini-batch的数据个数,tnk为第n个数据对应标签(one hot类型)的第k个元素。
实现代码:
def cross_entropy_error(y, t):
if y.ndim == 1: #用if分类,使得单个数据也可以计算交叉熵
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
#log(0)为-∞,为防止溢出,y通常加上一个很小的数
4.4 为什么要设定损失函数
神经网络的学习主要是通过梯度下降法实现的,即当我们更改神经网络中的一些参数(权重,偏置),我们希望有一个量,能够反映出神经网络是变好了还是变差了。即使参数只是微调,也可以观察到这个量的变化。所以我们使用损失函数来度量。
作为对比,如果使用正确率作为度量的量,一个mini-batch有100个数据,假设正确分类32个数据,通过微调参数,正确率依旧是32%,参数的微调效果被正确率抹杀。
使用阶跃函数作为激活函数同样会抹杀参数的微调效果。
而sigmoid函数连续,且任何点的导数不为0,所以它可以作为激活函数。并使用sigmoid函数的输出来计算损失函数。
总结:保留微调效果,实现可导
4.5 数值微分
4.5.1导数
原始的求导公式:
观察图像:
用这种方法求出来的导数所对应的切线,与真正的切线存在误差,所以将公式改良为:
因为左边的误差和右边的误差抵消了一部分,所以使用这个公式求出来的导数更为精确。
代码实现:
def numerical_diff(f, x):
h = 1e-4 # 0.0001
return (f(x+h) - f(x-h)) / (2*h)
4.5.2