神经网络之入门基础

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的广播功能,标量和数组各个元素进行了运算,运算结果以数组形式输出。

5、sigmoid和阶跃函数的比较
神经网络之入门基础_第1张图片

#函数图形
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个神经元。

  • 从输入层到第1层的信号传递:隐藏层的加权和(加权信号和偏置的总和)用a表示,被激活函数转换后的信号用z表示,h()表示激活函数。
    神经网络之入门基础_第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)
  • 从第1层到第2层的信号传递
    神经网络之入门基础_第3张图片
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)
  • 从第2层到输出层的信号传递:定义identity_function()函数,作为输出层的激活函数,这个恒等函数会将输入按照原样输出,主要为了和之前的流程保持一致,输出层的激活函数用σ()表示(一般根据求解问题的性质决定,回归函数可以使用恒等函数,二元分类问题可以使用sigmoid函数,多元分类问题可以使用softmax函数)。
    神经网络之入门基础_第4张图片
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函数,回归问题(根据某个输入预测一个连续数值)用恒等函数。

  • 恒等函数:将输入按照原样输出,对于输入信息,不加以改动地原样输出;
  • softmax函数:假设输出层共有n个神经元,计算第k个神经元的输出y(k),使用如下公式,分子是输入信号a(k)的指数函数,分母是所有输入信号的指数函数的和。
    在这里插入图片描述
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
  • softmax函数的改进:softmax函数在计算机运算中可能产生溢出问题,进行指数函数运算时,值容易变得非常大,在这些超大值之间进行除法运算可能使结果出现“不确定”情况。改进后的函数公式在分子和分母上同乘任意常数C,然后将C移入指数函数exp中,记为log C,再用C’进行替换,为了防止溢出,C’一般使用输入信号中的最大值。
    在这里插入图片描述

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)这样设置三个参数。

  • 第1个参数normalize设置是否将输入图像正规化为0.0-1.0的值(设置为False则原图像保持原像素);
  • 第2个参数flatten设置是否展开输入图像(),变成一维数组(设置为True输入图像保存为由784个元素构成的一维数组,设置为False输入图像为1x28x28的三维数组);
  • 第3个参数one_hot_label设置是否将标签保存为one-hot表示(仅正确解标签为1,其余皆为0的数组),设置为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、 数据处理行为

  • 正规化——把数据限定到某个范围内的处理;
  • 预处理——对神经网络的输入数据进行某种既定的转换,能够在提高识别性能和学习效率等实验中发挥作用;
  • 白化——将数据整体的分布形状均匀化;
  • 批处理——打包式的输入数据称为“批”,批处理可以大幅缩短每张图像的处理时间,一次性计算大型数组要比分开计算各个小型数组速度更快。range()函数若指定range(start,end),则会生成一个由start - end-1之间整数构成的列表;若指定range(start,end,step),则生成的列表中下一个元素会增加step指定的值。通过argmax()函数获取值最大元素的索引,给定参数axis=1表明在数组中沿着第一维方向查找该索引。
#批处理
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])

你可能感兴趣的:(#,深度学习)