关于本章之前内容可以参考以下之前文章:
1 https://blog.csdn.net/Raine_Yang/article/details/128473486?spm=1001.2014.3001.5501
2 https://blog.csdn.net/Raine_Yang/article/details/128584916?spm=1001.2014.3001.5501
神经网络的输出层设计
机器学习问题一般分为分类问题和回归问题。分类文件判断数据属于哪一类别,输出层一般使用softmax函数。回归问题即根据输入预测一个连续的数值,输出层一般使用恒等函数
设有n个输出层,其中第k个神经元的输出值yk
softmax函数表达式:
在实际应用中,由于e ^ x 的值往往较大,容易导致变量溢出。利用以下简单变换可以很好避免这一问题:
这里我们将分数上下同乘以常数C,把ln©代入到指数函数内,最后把ln©即为C’。我们将C’取输入数据最大值即可很好避免溢出
程序实现如下:
def softmax(a):
c = np.max(a)
exp_a = np.exp(a - c)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
2 softmax函数特征
softman函数输出是0到1之间实数,并且输出值总和恒为1。这一性质使得我们将softmax函数输出解释为分类问题各项的概率
network = init_network()
x = np.array([1.6, 5.5])
y = forward(network, x)
print(y)
# output: [0.36750414 0.63249586]
将x代入我们上一篇文章中搭建的神经网络里得到以下结果,输出可以被解释为x[0]的概率是0.36,x[1]的概率是0.63
输出层的神经元个数又问题而定,一般来说对于分类问题神经元个数即为类别的个数,而每个输出值即为对应类别的概率
3 手写数字识别
要实现首先数字识别,我们先引入常用的手写数字库mnist用于训练。运行下面程序前需要先将mnist库下载到该程序文件父文件夹下
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
img = x_train[0]
label = t_train[0]
print(label) # 5
print(img.shape) # (784,)
img = img.reshape(28, 28) # 把图像的形状变为原来的尺寸
print(img.shape) # (28, 28)
img_show(img)
1
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
load_mnist方法以(训练图像,训练标签),(测试图像,测试标签)的形式返回mnist数据。其参数flatten为是否将二维图像展开为一维数组,normalize为是否将图像正规化为0.0-1.0的值,属于对图像的一种预处理
2
def img_show(img):
pil_img = Image.fromarray(np.uint8(img))
pil_img.show()
Image.fromaeeay方法将Numpy数组图像转换为PIL数据类型
注:如报错不存在PIL可以下载库Pillow,下载时切换清华源加速
打开cmd,输入
pip install Pillow -i https://pypi.tuna,tsinghua.edu.cn/simple
神经网络的推理处理
该神经网络输入层有784个神经元(来源于展开图像28 * 28),输出层有10个神经元(代表结果0-10),其中隐藏层我们使用两层,第一层50个神经元,第二次100个神经元
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
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
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p= np.argmax(y) # 获取概率最高的元素的索引
if p == t[i]:
accuracy_cnt += 1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
1
def init_network():
with open("sample_weight.pkl", 'rb') as f:
network = pickle.load(f)
return network
这里我们直接使用已经训练好的权重和偏置。使用pickle方法加载sample_weight.pkl文件里面的权重值
pickle方法可以将程序运行中对象保存为文件。加载pickle方法可以复原程序运行中的对象
predict函数实现一个两次隐藏层的神经网络
2
x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p= np.argmax(y) # 获取概率最高的元素的索引
if p == t[i]:
accuracy_cnt += 1
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
predict得到网络输出结果,为一个长度为10的一维数组,其中每个元素索引为预测的数字,而元素值为该元素判定概率。np.argmax()找到最大值(即出现概率最大的数)的索引
批处理
在我们上一个例子中,我们一次处理一张展开的图像,相当于处理一个长为784 (28 X 28)的一维数组,数组在神经网络中形状变化如下
如果我们一次输入100张图片,即相当于输入一个100 X 784的数组,这使得输出也将为一个100 X 10的数组
这种打包式输入数据被称为批(batch)。批处理可以节省数据传输时间,使得效率高于分开处理
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax
def get_data():
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
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
x, t = get_data()
network = init_network()
batch_size = 100 # 批数量
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
x_batch = x[i:i+batch_size]
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i+batch_size])
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
该程序中每次将100个数据x输入神经网络并得到结果y。np.argmax参数axis = 1指取每一维的最大值