一、从感知机到神经网络
上一章关于感知机,既有好消息,也有坏消息。好消息是,即便对于复杂的函数,感知机也隐含着能够表示它的可能性。上一章已经介绍过,即便是计算机进行的复杂处理,感知机(理论上)也可以将其表示出来。坏消息是,设定权重的工作,即确定合适的、能符合预期的输入与输出的权重,现在还是由人工进行的。
神经网络的出现就是为了解决刚才的坏消息。具体地讲,神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。
我们把最左边的一列称为输入层(第0层),最右边的一列称为输出层,中间的一列称为中间层。中间层有时也称为“ 隐藏层 ”。
二、激活函数
1、阶跃函数
激活函数以阈值为界,一旦输入超过阈值,就切换输出,这样的函数称为“ 阶跃函数 ”。可以说感知机中使用了阶跃函数作为激活函数。
import numpy as np
import matplotlib.pyplot as plt
def step_functon(x):
y=x>0
# y:array([False, True, True], dtype=bool)
# 用astype()方法转换NumPy数组的类型
return y.astype(int)
x=np.arange(-5.0,5.0,0.1)
y=step_functon(x)
plt.plot(x,y)
plt.ylim(-0.1, 1.1) # 指定y轴的范围
plt.show()
阶跃函数以0 为界,输出从0 切换为1(或者从1 切换为0),值呈阶梯式变化,所以称为阶跃函数。
2、sigmoid 函数
如果将激活函数从阶跃函数换成其他函数,就可以进入神经网络的世界了。
import numpy as np
import matplotlib.pyplot as plt
def sigmod(x):
return 1 / (1 + np.exp(-x))
x=np.arange(-5.0,5.0,0.1)
y=sigmod(x)
plt.plot(x,y)
plt.ylim(-0.1, 1.1) # 指定y轴的范围
plt.show()
感知机中神经元之间流动的是0 或1 的二元信号,而神经网络中流动的是连续的实数值信号。
3、非线性函数
阶跃函数和sigmoid 函数还有其他共同点,就是两者均为非线性函数。
神经网络的激活函数必须使用非线性函数。因为使用线性函数的话,加深神经网络的层数就没有意义了。
4、ReLU函数(Rectified Linear Unit)
def relu(x):
return np.where(x>0,x,0)
三、多维数组的运算
1、矩阵乘法
矩阵乘积或点积(np.dot(A,B)):
2、神经网络的内积
Y=np.dot(X,W)+B
3、3层神经网络的实现
def init_network():
network = {}
network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
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])
network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
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_function(a3) # 输出层的激活函数
return y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x) # 神经网络的前向处理
print(y) # [ 0.31682708 0.69627909]
四、输出层的设计
神经网络可以用在分类问题和回归问题上,不过需要根据情况改变输出层的激活函数。一般地,回归问题可以使用恒等函数,二元分类问题可以使用sigmoid 函数,多元分类问题可以使用softmax 函数。
1、softmax函数
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函数的特征:softmax函数的输出是0.0 到1.0之间的实数。并且,softmax函数的输出值的总和是1,可以把softmax 函数的输出解释为“概率“。
一般而言,神经网络只把输出值最大的神经元所对应的类别作为识别结果。并且,即便使用softmax 函数,输出值最大的神经元的位置也不会变。因此,神经网络在进行分类时,输出层的softmax 函数可以省略。在实际的问题中,由于指数函数的运算需要一定的计算机运算量,因此输出层的softmax 函数一般会被省略。
求解机器学习问题的步骤可以分为“学习” 和“推理”两个阶段。首先,在学习阶段进行模型的学习B,然后,在推理阶段,用学到的模型对未知的数据进行推理(分类)。如前所述,推理阶段一般会省略输出层的softmax 函数。在输出层使用softmax 函数是因为它和神经网络的学习有关系。
五、手写数字识别
1、神经网络的推理处理
# 展示图片
import sys, os
sys.path.append(os.pardir)
sys.path.append('./')
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)
# 神经网络的推理处理
# 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
# x_test.shape=(10000, 784) t_test.shape=(10000,)
# x_train.shape=(60000, 784) t_train.shape=(60000,)
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)))
2、批处理
处理一张图片:
同时处理100张图片:这种打包式的输入数据称为批(batch)
# 批处理
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)))
# list( range(0, 10, 3) )----->[0, 3, 6, 9]