神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。
用图来表示神经网络的话,如图3-1所示。我们把最左边的一列称为 输入层,最右边的一列称为输出层,中间的一列称为中间层。中间层有时也称为隐藏层。“隐藏”一词的意思是,隐藏层的神经元(和输入层、输出层不同)肉眼看不见。
神经网络的激活函数必须使用非线性函数。线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无 隐藏层的神经网络”。
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
X = np.arange(-5.0, 5.0, 0.1)
Y = sigmoid(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1)
"""
xlim([xl xr]);
ylim([yl yr]);
用于限定x轴 y轴上线限制,其中,
xl:x轴下限
xr:x轴上限
yl:y轴下限
yr:y轴上限
"""
plt.show()
阶跃函数以0为界,输出从0切换为1(或者从1切换为0)。
它的值呈阶梯式变化,所以称为阶跃函数。
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x > 0, dtype=np.int)
# 筛选条件是x>0,当x大于0的话,返回值为true,小于的话,返回值为false
# dtype = np.int 指将值转换为int类型
X = np.arange(-5.0, 5.0, 0.1)
Y = step_function(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1) # 指定图中绘制的y轴的范围
plt.show()
阶跃函数和sigmoid函数还有其他共同点,就是两者均为非线性函数。
sigmoid函数是一条曲线,阶跃函数是一条像阶梯一样的折线,两者都属于非线性的函数。
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def step_function(x):
return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1)
y1 = sigmoid(x)
y2 = step_function(x)
plt.plot(x, y1)
plt.plot(x, y2, 'k--')
plt.ylim(-0.1, 1.1) # 指定图中绘制的y轴的范围
plt.show()
如果把这两个函数与水联系起来,则阶跃函数可以比作“竹筒敲石”。sigmoid函数可以比作“水车”。阶跃函数就像竹筒敲石一样,只做是否传送
水(0或1)两个动作,而sigmoid函数就像水车一样,根据流过来的水量相应
地调整传送出去的水量。
接着说一下阶跃函数和sigmoid函数的共同性质。阶跃函数和sigmoid
函数虽然在平滑性上有差异,但是如果从宏观视角看,可以发现它们
具有相似的形状。实际上,两者的结构均是“输入小时,输出接近0(为0);
随着输入增大,输出向1靠近(变成1)”。还有一个共同点是,不管输入信号有多小,或者有多 大,输出信号的值都在0到1之间。
一般而言,神经网络只把输出值最大的神经元所对应的类别作为识别结果。
并且,即便使用softmax函数,输出值最大的神经元的位置也不会变。因此, 神经网络在进行分类时,输出层的softmax函数可以省略。
对于分类问题,输出层的神经元数量一般设定为类别的数量。
二元分类问题可以使用 sigmoid函数,
多元分类问题可以使用 softmax函数。
# coding=utf-8
import numpy as np
"""
def softmax(a):
exp_a = np.exp(a)
sum_exp_a =np.sum(exp_a)
y = exp_a /sum_exp_a
return y
"""
# 计算机处理数的时候,数值必须在4字节或者8字节的有限带宽内,否则会出现超大值无法表示的问题,这被称为溢出
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
# softmax函数的输出总和是1
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def relu(x):
return np.maximum(0, x)
x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)
plt.plot(x, y)
plt.ylim(-1.0, 5.5)
plt.show()
# coding=utf-8
import numpy as np
A = np.array([1, 2, 3, 4])
print(A) # [1 2 3 4]
print(np.ndim(A)) # 输出A的维数
print(A.shape) # 输出A的形状
print(A.shape[0])
print("-----------------测试数组--------------------------")
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A.shape)
B = np.array([[1, 2], [3, 4], [5, 6]])
print(B.shape)
C = np.dot(A, B) # A,B进行点积运算,可以一次性计算出,而不是用多重for
print(C)
[1 2 3 4]
1
(4,)
4
-----------------测试数组--------------------------
(2, 3)
(3, 2)
[[22 28]
[49 64]]
# 这个函数写入identity_fuction 文件中
def identity_fuction(x):
return x
# coding=utf-8
import numpy as np
from sigmoid import sigmoid
from identity_fuction import identity_fuction
def init_network():
network = {}
network["w1"] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
# 输入层为第0层,有2个神经元;第一层有3个神经元
network["b1"] = np.array([0.1, 0.2, 0.3])
# 第一层三个神经元的阈值
network["w2"] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
# 第一层有三个神经元,第二层有两个神经元
network["b2"] = np.array([0.1, 0.2])
# 第2层的2个神经元的阈值
network["w3"] = np.array([[0.1, 0.3], [0.2, 0.4]])
# 第二层有2个神经元,输出层有2个神经元
network["b3"] = np.array([0.1,0.2])
return network
def forward(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 = identity_fuction(a3)
return y
if __name__ == '__main__':
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)
[0.31682708 0.69627909]
我们使用学习到的参 数,实现神经网络的“推理处理”。这个推理处理也称为神经网络的向前传播(forward propagation)。
和求解机器学习问题的步骤(分成学习和推理两个阶段进行)一样,使用神经网络解决问题时,也需要首先使用训练数据(学习数据)进行权重参数的学习;进行推理时,使用刚才学习到的参数,对输入数据进行分类。
MNIST数据集经常作为实 验用的数据出现。
MNIST数据集是由0到9的数字图像构成的。训练图像有6万张, 测试图像有1万张,这些图像可以用于学习和推理。MNIST数据集的一般 使用方法是,先用训练图像进行学习,再用学习到的模型度量能在多大程度 上对测试图像进行正确的分类。
这个神经网络 的输入层有784个神经元,输出层有10个神经元。输入层的784这个数字来 源于图像大小的28 × 28 = 784,输出层的10这个数字来源于10类别分类(数 字0到9,共10类别)。此外,这个神经网络有2个隐藏层,第1个隐藏层有 50个神经元,第2个隐藏层有100个神经元。
像这样把数据限定到某 个范围内的处理称为正规化(normalization)。此外,对神经网络的输入数据
进行某种既定的转换称为预处理(pre-processing)。预处理在神经网络(深度学习)中非常实用,其有效性已在提高识别
性能和学习的效率等众多实验中得到证明。
很多预处理都会考虑到数据的整体分布。比如,利用数据
整体的均值或标准差,移动数据,使数据整体以 0为中心分布,或
者进行正规化,把数据的延展控制在一定范围内。除此之外,还有 将数据整体的分布形状均匀化的方法,即数据白化(whitening)等
# coding: utf-8
"""显示 mnist图像"""
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))
# 实现从数组到图片的转换 np.unit8()对数据进行转换(0,255)
pil_img.show()
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)
# load_mnist函数以(训练图像,训练标签,测试函数,测试标签)的形式返回读入的mnist数据
# normalize设置是否将输入的图片正规化为0.0~1.0的值;为false的话,保持原来的(0~255)
# flatten函数设置是否展开为1维数组
img = x_train[0] #x_train的形状是(6000,784),即6000行728列的矩阵,所以x_train[0]表示第一列的784个数据
label = t_train[0] #t_train的形状是(6000,),即一行或者一列数据6000个,所以t_train[0]是第一个数据,这里它的值是5
print(label) # 5
print(img.shape) # (784,)
img = img.reshape(28, 28) # 把图像的形状变为原来的尺寸
print(img.shape) # (28, 28)
img_show(img)
# 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
"""
init_network()会读入保存在pickle文件sample_weight.pkl中的学习到的
权重参数A。这个文件中以字典变量的形式保存了权重和偏置参数。
"""
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)))
# 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)))
同上 均为0.935
神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。
以“性能的恶劣程度”
# coding=utf-8
import numpy as np
def mean_squared_error(y, t):
return 0.5 * np.sum((y - t) ** 2)
if __name__ == "__main__":
# 正解为2
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# 2的概率最高的情况(0.6)
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
a1 = mean_squared_error(np.array(y1), np.array(t))
print(a1)
# 7的概率最高情况(0.6)
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
a2 = mean_squared_error(np.array(y2), np.array(t))
print(a2)
这里,参数y和t是NumPy数组。函数内部在计算np.log时,加上了一个微小值delta。这是因为,当出现np.log(0)时,np.log(0)会变为负无限大的-inf,这样一来就会导致后续计算无法进行。作为保护性对策,添加一个微小值可以防止负无限大的发生。
# coding =utf-8
import numpy as np
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
a1 = cross_entropy_error(np.array(y), np.array(t))
print(a1)
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
a2 = cross_entropy_error(np.array(y), np.array(t))
print(a2)
mini——batch的交叉熵误差的实现
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
# coding= utf-8
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)
"""读入上面的MNIST数据后,训练数据有60000个,输入数据是784维
(28 × 28)的图像数据,监督数据是10维的数据。因此,上面的x_train、t_
train的形状分别是(60000, 784)和(60000, 10)。"""
在进行神经网络的学习时,不能将识别精度作为指标。因为如果以识别精度为指标,则参数的导数在绝大多数地方都会变为0。