1、神经网络:一个重要性质是它可以自动从数据中学习到合适的权重参数,用图表示神经网络的话,最左边的一列称为输入层,最右边的一列称为输出层,中间的一列称为中间层(也称隐藏层)。一般而言,“朴素感知机”是指单层网络,指的是激活函数使用了阶跃函数(一旦输入超过阈值,就切换输出的函数)的模型;“多层感知机”指神经网络,即使用sigmoid函数等平滑的激活函数的多层网络。
2、激活函数:将输入信号的总和转换为输出信号,作用在于决定如何来激活输入信号的总和,通常可以分为两个阶段进行,首先通过a=b+w1x1+w2x2计算加权输入信号和偏置的总和,记为a;然后用h()函数将a转换为输出y。
3、阶跃函数的实现:
#简单实现(x只能接受浮点数)
def step_function(x):
if x>0:
return 1
else:
return 0
#支持NumPy数组的实现
def step_function(x):
y = x > 0 #数组y是布尔型数组
return y.astype(np.int) #使用astype()方法转换数组类型
对NumPy数组进行不等号运算时,数组的各个元素都会进行不等号运算,最后生成一个布尔型数组,其中>0的元素被转换为True,≤0的元素被转换为False,想要阶跃函数输出int型,需要使用astype()方法进行转换,通过参数指定期望类型。
4、sigmoid函数及其实现:神经网络使用该函数作为激活函数,进行信号的转换,转换后的信号被传送给下一个神经元。其中,exp(-x)表示e^(-t)。
def sigmoid(x):
return 1 / (1 + np.exp(-x))
sigmoid函数的实现能支持NumPy数组,主要是因为Numpy的广播功能,标量和数组各个元素进行了运算,运算结果以数组形式输出。
#函数图形
import numpy as np
import matplotlib.pylab as plt
def step_function(x): #阶跃函数
return np.array(x > 0,dtype = np.int)
def sigmoid(x): #sigmoid函数
return 1 / (1 + np.exp(-x))
x = np.arange(-5.0,5.0,0.1)
y1 = step_function(x)
y2 = sigmoid(x)
plt.plot(x,y)
plt.ylim(-0.1,1.1) #指定y轴范围
plt.show()
①两者的平滑性不同:sigmoid函数是一条平滑的曲线,输出随着输入发生连续性变化,而阶跃函数以0为界,输出发生急剧性变化;
②两者信号机制不同:相对于阶跃函数只能返回0或1,sigmoid函数可以返回一系列实数值,即感知机中神经元之间流动的是0或1的二元信号,而神经网络流动的是连续的实数值信号;
③共同点:当输入信号为重要信息时,都会输出较大的值(接近1),当输出信号为不重要信息时,都会输出小小的值(接近0),并且输出信号只在[0,1]区间。
6、非线性函数:sigmoid函数和阶跃函数都是非线性函数,sigmoid函数是一条曲线,阶跃函数是一条像阶梯一样的折线,函数本来是输入某个值后会返回一个值的转换器,向这个转换器输入某个值后,输出值是输入值常数倍的函数称为线性函数(h(x)=cx)。对于线性函数,不管如何加深层次,总是存在与之等效的“无隐藏层的神经网络”,这样无法发挥多层网络带来的优势;为了发挥叠加层所带来的优势,激活函数必须使用非线性函数。
7、ReLU函数:在输入大于0时,直接输出该值;在输入小于等于0时,输出0。
def relu(x):
return np.maximum(0,x) #从输入数值中,选择较大的值输出
8、多维数组:数字排成一列的集合、长方形的集合、三维状或者N维状的集合,A表示数组,则维数可以通过np.ndim(A)函数获得,数组形状可以通过实例变量A.shape获得,结果返回一个元组。二维数组也称为矩阵,数组的横向排列称为行,纵向排列称为列。
矩阵乘法——通过左边矩阵的行和右边矩阵的列以对应元素的方式相乘后再求和,计算时要保证左边矩阵的列维与右边矩阵的行维相同(例如,左矩阵为mn,右矩阵为nl,计算所得矩阵为m*l型),计算使用np.dot()函数,接收两个Numpy数组作为参数,并返回数组乘积。
9、3层神经网络的实现:输入层(第0层)有2个神经元,第1个隐藏层(第1层)有3个神经元,第2个隐藏层(第2层)有2个神经元,输出层(第3层)有2个神经元。
X = np.array([1.0,0.5])
W1 = np.array([[0.1,0.3.0.5],[0.2,0.4,0.6]])
B1 = np.array([0.1,0.2,0.3])
A1 = np.dot(X,W1) + B1
Z1 = sigmoid(A1)
W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
B2 = np.array([0.1,0.2])
A2 = np.dot(Z1,W2) + B2
Z2 = sigmoid(A2)
def identity_function(x):
return x
W3 = np.array([[0.1,0.3],[0.2,0.4]])
B3 = np.array([0.1,0.2])
A3 = np.dot(Z2,W3) + B3
Y = identity_function(A3)
10、输出层的设计:神经网络可以用在分类问题和回归问题上,需要根据情况改变输出层的激活函数,一般而言,分类问题(数据属于那一个类别)用softmax函数,回归问题(根据某个输入预测一个连续数值)用恒等函数。
def softmax(a):
exp_a = np.exp(a)
exp_newa = exp_a - np.max(a) #改进后的值
sum_exp_a = np.sum(exp_newa)
y = exp_newa/sum_exp_a
return y
11、softmax函数的特征:输出值总是介于0.0——1.0之间的实数,并且所有输出值的总和是1,这样使得softmax函数的输出可以解释为“概率”。又因为指数函数是单调递增函数,所以各个元素之间的大小关系不变,一般而言,神经网络只把输出值最大的神经元对应的类别作为识别结果,在使用softmax函数时,输出值最大的神经元的位置不会变化,所以神经网络进行分类时(输出层神经元的数量一般设定为类别的数量),输出层的softmax函数可以省略。
12、前向传播(forward propagation):使用学习到的参数,先实现神经网络的“推理处理”,这个推理处理称为神经网络的前向传播。
13、MNIST数据集:MNIST手写数字图像集是机器学习领域最有名的数据集之一,被应用于从简单的实验到发表论文研究等各种场合,在阅读图像识别或机器学习的论文时,MNIST数据集经常作为实验用的数据出现。
MNIST数据集由0到9的数字图像构成,图像数据是28像素x28像素的灰度图像(1通道),各个像素的取值在0-255之间,训练图像有6万张,测试图像有1万张,这些图像可以用于学习和推理,通常的使用方法是:先用训练图像进行学习,再用学习到的模型对测试图像正确分类的程度进行度量。
14、Python脚本mnist.py:该脚本支持从下载MNIST数据集到将这些数据转换成Numpy数组等处理,使用mnist.py中的load_mnist()函数可以轻松读入MNIST数据,但是不能跨目录导入mnist.py文件,sys.path.append(os.pardir)语句实际上把父目录deep-learning-from-scratch加入到sys.path(Python搜索模的路径集),从而可以导入deep-learning-from-scratch下任何目录中的任何文件。在显示MNIST图像时需要使用PIL(Python Image Library)模块,可以使用reshape()方法的参数指定期望的形状,更改NumPy数组的形状,并通过Image.fromarray()函数把保存为NumPy数组的图像数据转换为PIL用的数据对象。
import sys,os
sys.path.append(os.pardir) #为了导入父目录中的文件而设定
from dataset.mnist import load_mnist
(x_train,t_train),(x_test,t_test) =
load_mnist(flatten=True,normalize=False)
#输出各个数据的形状
print(x_train.shape) #(60000,784)
print(t_train.shape) #(60000,)
print(x_test.shape) #(10000,784)
print(t_test.shape) #(10000,)
load_mnist函数——以“(训练图像,训练标签),(测试图像,测试标签)”的形式返回读入的MNIST数据,此外还可以像load_mnist(normalize=True,flatten=True,one_hot_label=False)这样设置三个参数。
15、pickle功能:可以将程序运行中的对象保存为文件,加载保存过的pickle文件可以立刻复原之前程序运行中的对象。由于load_mnist()函数内部也使用了pickle功能,所以可以高效完成MNIST数据的准备工作。
16、手写数字识别神经网络的推理处理:神经网络的输入层有784个神经元(源于图像大小28x28=784),输出层有10个神经元(源于数字0-9类别分类),此外还有2个隐藏层,神经元个数设置随意,实验设置为第1个隐藏层有50个神经元,第2个隐藏层有100个神经元。init_network()函数会读入保存在文件sample_weight.pkl(文件中以变量形式保存了权重和偏置参数)中学习到的权重参数,然后使用该函数评价它的识别精度,即能在多大程度上正确分类,然后用for语句逐一取出保存在x中的图像数据,用predict()函数进行分类(以NumPy数组的形式输出各个标签对应的概率),接着用np.argmax(x)函数取出数组中最大值的索引,最后比较神经网络所预测的答案和正确解标签,将回答正确的概率作为识别精度。
def get_data():
(x_train,t_train),(x_test,t_test) =
load_mnist(normalize = True,flatten = False,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("准确度:" + str(float(accuracy_cnt) / len(x)))
17、 数据处理行为:
#批处理
batch_size = 100 #批数量
for i in range(0,len(x),batch_size):
x_batch = x[i:i+batch_size] #从头开始以100为单位抽取数据
y_batch = predict(network, x_batch)
p = np.argmax(y_batch,axis=1)
accuracy_cnt += np.sum(p==t[i:i+batch_size])