第三章.神经网络的学习
3.1 损失函数
损失函数是表示神经网络性能“恶劣程度”的指标,即当前神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。
1.均方误差(mean_squared_error)
1).公式:
- 参数说明:
yk:神经网络输出
tk:监督数据
k:数据维度
2).代码实现:
import numpy as np
# 均方误差
def mean_squared_error(y, t):
return 0.5 * np.sum((y - t) ** 2)
y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
mean_squared_error = mean_squared_error(y, t)
print(mean_squared_error)
3).结果显示:
2.交叉熵误差(cross_entropy_error)
1).公式:
-
单个数据:
-
小批量(mini-bitch):
-
参数说明:
yk :神经网络输出
tk:监督数据
ynk :第n个数据的第k个元素神经网络的值
tnk:第n个数据的第k个元素监督数据的值
k:数据维度
N:N个数据
2).代码实现:
-
注意:
①.函数内部在计算np.log时,加上一个微小值delta=1e-7.(原因:当出现np.log(0)时,np.log(0)会变为负无穷大的-inf,这样一来就会导致后续计算无法进行,作为保护政策,增加一个微小值可以防止负无穷大的发生。)
②.程序中的sample_weight.pkl文件的所在位置在上一章节导入方式中有涉及,放在工程的当前运行目录下: sample_weight.pkl
·代码:
import pickle
import numpy as np
import sys, os
sys.path.append(os.pardir)
from dataset.mnist import load_mnist
# 加载数据
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
return x_train, t_train
# 初始化权重和偏置
def init_network():
with open('sample_weight.pkl', 'rb') as f:
network = pickle.load(f)
return network
# 激活函数:sigmoid
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 输出层函数:softmax
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))
# 正向传播:3层神经元,激活函数:sigmoid函数,输出层函数softmax函数
def predict(network, x):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
# 第一层
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
# 第二层
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
# 输出层
a3 = np.dot(z2, W3) + b3
y = softmax(a3)
return y
# 交叉熵误差
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
# 加载数据
x_train, t_train = get_data()
# 从训练数据中随机抽取10笔数据
train_size = x_train.shape[0]
batch_size = 10
batch_mask = np.random.choice(train_size, batch_size)
print(batch_mask)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
network = init_network()
y_batch = predict(network, x_batch)
print(y_batch.shape)
print(t_batch.shape)
# 交叉熵误差
cross_entropy_error = cross_entropy_error(y_batch, t_batch)
print(cross_entropy_error)
3).结果显示:
3.在神经网络学习时,不能将识别精度作为指标的原因:参数的导数在绝大多数都为0,导致参数无法更新。
1).示意图:
-
识别精度对微小的参数变化基本上没有什么反应,即便有反应,也是不连续的,突然的变化。
-
阶跃函数:在绝大多数地方(除了0以外的地方)均为0,若使用了阶跃函数,即使将损失函数作为指标,参数的微小变化也会被阶跃函数抹杀,导致损失函数的值不会发生任何变化0。
-
sigmoid函数:不仅函数的输出(数轴的值)是连续变化的,导数(曲线的斜率)也是连续变化的,sigmoid函数的导数在任何地方都不为0,神经网络的学习得以正常进行。