在看交叉熵误差公式前,先来熟悉一下自然对数,自然对数是以常数e为底数的对数,数学中常见以logx表示自然对数。e是一个无限不循环小数,其值约等于2.718281828459…,是一个超越数。看代码,分析图:
代码不写注释,因为很明显了。之所以加了负号画出红线图形,是因为这个解释起来更容易一些,而且交叉熵误差函数也确实是取了负号的。
前文深度学习入门初探——多层感知机的神经网络式实现已经介绍过了,神经网络的输出softmax,值在0到1之间,1就是100%的,当输出1的时候就是百分百确认,误差为0。当输出趋于0的时候误差就越大,越不能确认。
图中红色曲线在输入是0到1时,误差是负无穷到0。
# coding: utf-8
import math
import numpy as np
import matplotlib.pylab as plt
X = np.arange(0.0000001, 5.0, 0.01)
Y = np.arange(0.0000001, 5.0, 0.01)
for i in range(0,X.shape[0]):
Y[i] = math.log(X[i])
l0x = np.arange(0, 5.0, 0.1)
liney0 = np.zeros(l0x.shape)
plt.plot(l0x, liney0, color='red', linewidth=1.0, linestyle='--')
l0y = np.arange(-3, 5.0, 0.1)
linex0 = np.zeros(l0y.shape)
plt.plot(linex0, l0y, color='red', linewidth=1.0, linestyle='--')
plt.plot(X, Y)
plt.plot(X, -Y, color='red')
plt.ylim(-3, 3)
plt.show()
再来学习下交叉熵误差这个损失函数是怎么计算的:
y表示测试数据经过预测得到的结果,t表示测试数据的正确结果,k表示数据的维度。下面是numpy实现的代码:
def cross_entropy_error(yp, tp):
delta = 0.0000001
return -np.sum(tp*np.log(yp+delta))
为了更好地学习这个损失函数的指标性质,在这里拿深度学习入门初探——hello word式的手写数字识别中的数据做个演示:很明显可以看出哪个数据吻合得更好。
# coding: utf-8
import sys, os
sys.path.append(os.pardir)
import numpy as np
import pickle
from common.functions import sigmoid, softmax
def _change_one_hot_label(X):
T = np.zeros((X.size, 10))
for idx, row in enumerate(T):
row[X[idx]] = 1
return T
def load_mnist(normalize=True, flatten=True, one_hot_label=False):
"""读入MNIST数据集
Parameters
----------
normalize : 将图像的像素值正规化为0.0~1.0
one_hot_label :
one_hot_label为True的情况下,标签作为one-hot数组返回
one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组
flatten : 是否将图像展开为一维数组
Returns
-------
(训练图像, 训练标签), (测试图像, 测试标签)
"""
with open("mnist.pkl", 'rb') as f:
dataset = pickle.load(f)
if normalize:
for key in ('train_img', 'test_img'):
dataset[key] = dataset[key].astype(np.float32)
dataset[key] /= 255.0
if one_hot_label:
dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
dataset['test_label'] = _change_one_hot_label(dataset['test_label'])
if not flatten:
for key in ('train_img', 'test_img'):
dataset[key] = dataset[key].reshape(-1, 1, 28, 28)
return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label'])
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=True)
return x_test, t_test
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
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(yp, tp):
delta = 0.0000001
return -np.sum(tp*np.log(yp+delta))
np.set_printoptions(formatter={'float': '{: 0.9f}'.format})
network = init_network()
x, t = get_data()
y = predict(network, x[10])
print("\n数据10预测的输出:\n",y, "\n")
print("数据10实际的结果:\n",t[10], "\n")
cer0 = cross_entropy_error(y, t[10])
print("数据10预测输出与实际结果的交叉熵误差:",cer0, "\n")
y = predict(network, x[1])
print("数据1预测的输出:\n",y, "\n")
print("数据1实际的结果:\n",t[1], "\n")
cer1 = cross_entropy_error(y, t[1])
print("数据0预测输出与实际结果的交叉熵误差:",cer1, "\n")