从感知机到神经网络:Python实现与测试
来源:互联网 发布:含数据库的网页作品 编辑:程序博客网 时间:2024/05/17 07:25
本文为吴恩达神经网络课程打的学习笔记,包含了本人自己的完整推导过程,并且为便于理解,将代码进行了部分重构。
简介
神经网络算法可以算是一种仿生学,其基本数据处理单元——感知机——模仿的是生物神经系统内的神经元,它能够接受来自多个源的信号输入,然后将信号转化为便于传播的信号在进行输出(在生物体内表现为电信号)。
感知机
感知机结构:
其中z为神经元将接收到的信号进行整合,step()函数将整合后的信号进行转化并输出。
早期常用到的step函数有:
多层感知机(Multi-Layer Perceptron)
多层感知机由输入层、输出层和隐含层组成:
实际上在机器学习发展的早期,感知机模型只能用来解决一些鸡毛蒜皮的问题,主要原因就是受step()函数的限制,因为早期的step()函数只能产生离散的输出,并且掩盖了原信号(即无法从感知机的输出来推断原信号)。下图为感知机模型解决异或问题的方案:
反向传播算法的出现
在很长一段时间里人们都没有找到训练MLP的方法,直到1986年D. E. Rumelhart等人发明了反向传播算法,MLP才具有学习能力。
反向传播算法具体过程是这样的:
- 对于一个训练用例,网络将其作为输出并计算输出,即预测值
- 测量网络的输出误差
- 计算在隐含层的最后一层中哪些单元对误差产生了贡献
- 再从那些产生误差的单元往回追溯,找出隐含层中所有导致误差的单元,直到回溯到输入层为止
- 调节那些单元的权重分布
为了使这个算法正常工作,作者还对MLP架构做出了一个至关重要的改进:将step函数替换为逻辑函数
目前常用的激活函数有三种:
下面是它们的图象与导数:
单感知机模型的实现
外部库
import numpy as npimport matplotlib.pyplot as pltimport h5pyimport scipyfrom PIL import Imagefrom scipy import ndimage%matplotlib inlinenp.random.seed(1)
引入数据
所用数据为h5格式的关于猫的图片数据,每张图片像素为64*64,RGB通道。其中猫的图片标记为y=1,不是猫的图片标记为y=0。
def load_dataset(): train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r") train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r") test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels classes = np.array(test_dataset["list_classes"][:]) # the list of classes train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0])) test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0])) return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()print("X_train shape:\t{}\nY_train shape:\t{}\nX_test shape:\t{}\nY_test shape:\t{}\n".format (train_set_x_orig.shape,train_set_y.shape,test_set_x_orig.shape,test_set_y.shape))
输出为:
X_train shape: (209, 64, 64, 3)
Y_train shape: (1, 209)
X_test shape: (50, 64, 64, 3)
Y_test shape: (1, 50)
index = 30 #更改index值以查看不同样本plt.imshow(train_set_x_orig[index])print ("y = " + str(train_set_y[0,index]))
输出为:
m_train=train_set_x_orig.shape[0]m_test=test_set_x_orig.shape[0]num_px=train_set_x_orig.shape[1]print("m_train:{}\tm_test:{}\tnum_px:{}".format(m_train,m_test,num_px))
输出为:m_train:209 m_test:50 num_px:64
数据的矩阵化
在多样本输入条件下,对于每一个样本
由于每个样本的计算之间没有依赖关系,可以将数据矩阵化实现并行计算:
,其中每个样本
感知机的最终输出
train_set_x_flatten = train_set_x_orig.reshape(m_train,num_px*num_px*3).Ttest_set_x_flatten = test_set_x_orig.reshape(m_test,num_px*num_px*3).Ttrain_set_x = train_set_x_flatten/255test_set_x = test_set_x_flatten/255print("X_train_flatten shape:\t{}\nX_test_flatten shape:\t{}\n".format(train_set_x.shape,test_set_x.shape))
输出为:
X_train_flatten shape: (12288, 209)
X_test_flatten shape: (12288, 50)
实现激活函数
def sigmoid(z): s = 1/(1+np.exp(-z)) return s
参数矩阵初始化
随即初始化权重矩阵w,而偏置常量b设为1。
#参数:输入层的节点数dim,同样本特征数#返回:随机初始化的参数字典parametersdef initialize_parameters(dim): parameters={ "w":np.random.randn(dim,1)*0.01, "b":1 } return parameters
前向传播
前向传播就是针对输入给出相应的输出并计算误差的过程,此处使用交叉熵
#参数:包含W,b的参数字典parameters,样本数据X,样本标签Y#返回:损失值cost,包含A的缓存cachedef forward_propagation(parameters, X, Y): w=parameters['w'] b=parameters['b'] m = X.shape[1] Z=np.dot(w.T,X)+b A = sigmoid(Z) cache=A cost = ((-1/m)*(Y*np.log(A)+(1-Y)*np.log(1-A))).sum(axis=1) cost = np.squeeze(cost) assert(cost.shape == ()) return cost,cache
反向传播
反向传播算法实际上是一个优化问题,它需要找到一组能最小化Loss的解(W,b)。最简单的方法就是求导,直接计算满足一阶导为零且二阶导大于或小于零的参数即可,实际上在线性模型中就有这么一种方法称为正规方程。
另外一种逼近解的方法叫梯度下降法,对于某参数
其中
具体对于参数w跟b的计算为:
我们只需要
#参数:样本数据X,样本标签Y,包含A的缓存cache#返回:包含dw,db的梯度字典gradsdef backward_propagation(X,Y,cache): m=X.shape[1] A=cache grads = {"dw": np.dot(X,(A-Y).T)/m, "db": ((A-Y)/m).sum(axis=1)} return grads
参数的迭代优化
对于给定的学习率与迭代次数,对参数W,b进行优化。optimize函数返回优化好的参数与记录下的损失值cost以供可视化。
def optimize(parameters, X, Y, num_iterations, learning_rate): costs = [] w=parameters['w'] b=parameters['b'] for i in range(num_iterations): cost,cache=forward_propagation(parameters,X,Y) grads=backward_propagation(X,Y,cache) dw = grads["dw"] db = grads["db"] w = w-learning_rate*dw b = b-learning_rate*db parameters={ 'w':w, 'b':b } #每一百次迭代记录一次cost if i % 100 == 0: costs.append(cost) params = {"w": w, "b": b} return params, costs
预测函数
预测函数以给定的参数(W,b)与样本X为参数,会返回给定参数下的模型对样本X的预测值。
def predict(parameters, X): w = parameters["w"] b = parameters["b"] m = X.shape[1] Y_prediction = np.zeros((1,m)) Z=np.dot(w.T,X)+b A = sigmoid(Z) for i in range(A.shape[1]): Y_prediction[0, i] = 1 if A[0,i]>0.5 else 0 #注意取矩阵元素与取数组元素的区别 return Y_prediction
评估模型
可视化模型在训练过程中的学习曲线。
def show_info(parameters,X_train,Y_train,X_test,Y_test,costs,learning_rate): Y_prediction_test = predict(parameters, X_test) Y_prediction_train = predict(parameters, X_train) print("train accuracy: " + str(np.sum((Y_prediction_train == Y_train)/X_train.shape[1]))) print("test accuracy: " + str(np.sum((Y_prediction_test == Y_test)/X_test.shape[1]))) plt.plot(np.squeeze(costs)) plt.ylabel('cost') plt.xlabel('iterations (per tens)') plt.title("Learning rate =" + str(learning_rate)) plt.show()
整合模型
def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.005): #1.参数初始化 parameters = initialize_parameters(X_train.shape[0]) #2.迭代优化参数 parameters, costs = optimize(parameters, X_train, Y_train, num_iterations, learning_rate) show_info(parameters,X_train,Y_train,X_test,Y_test,costs,learning_rate) return parameters
训练模型
parameters = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005)
输出为:
多层网络实现
网络模型
此处实现一个L层的神经网络,最后一层的激活函数使用
参数矩阵维度分析
对于L层的网络模型,易得每一层(第i层)都有这么几个参数(i>0):
- 神经元数,
n[i] - 权重参数,
W[i] - 偏置参数,
b - 线性输出,
Z[i]=W[i]∗A[i−1]+b (注意,此处不再使用WT∗X ) - 激活函数,
g[i](x)={σ(x)ReLU(x)i=Li<L - 输出,
A[i]=g(Z[i])
下面简单推导一下每一层的参数矩阵的维度。
令每个样本均为列向量,则易得
其中m为样本数量。
然后从输入层开始,输入层的矩阵维度为
所以
参数矩阵初始化
#三层模型layers_dims = [12288, 7,1] #输入层,隐含层,输出层
def initialize_parameters(layer_dims): parameters = {} L = len(layer_dims) # number of layers in the network for i in range(1, L): parameters['W' + str(i)] = np.random.randn(layer_dims[i],layer_dims[i-1])*0.01 parameters['b' + str(i)] = np.ones((layer_dims[i],1)) assert(parameters['W' + str(i)].shape == (layer_dims[i], layer_dims[i-1])) assert(parameters['b' + str(i)].shape == (layer_dims[i], 1)) return parameters
激活函数
def sigmoid(Z): A = 1/(1+np.exp(-Z)) return Adef relu(Z): A = np.maximum(0,Z) assert(A.shape == Z.shape) return A
每一层神经元的运算
完成每一层所有神经元的运算,支持两种激活函数。
#参数:上一层的输出A_prev,当前层的参数W,b,激活方式activation#返回:当前层的输出A,缓存A_prev,W,Zdef perceptron_forward(A_prev, W, b, activation): Z=np.dot(W,A_prev) if activation == "sigmoid": A = sigmoid(Z) elif activation == "relu": A = relu(Z) assert (A.shape == (W.shape[0], A_prev.shape[1])) cache=(A_prev,W,Z) return A, cache
前向传播(L层的神经元运算)
def forward_propagation(X,Y, parameters): caches = [] A = X #第零层的输出就为X L = len(parameters)//2 # number of layers in the neural network for l in range(1, L): A_prev = A A, cache = perceptron_forward(A_prev,parameters["W"+str(l)],parameters["b"+str(l)],"relu") caches.append(cache) AL, cache = perceptron_forward(A,parameters["W"+str(L)],parameters["b"+str(L)],"sigmoid") caches.append(cache) assert(AL.shape == (1,X.shape[1])) m = Y.shape[1] cost = -np.sum(np.multiply(Y,np.log(AL))+np.multiply(1-Y,np.log(1-AL)))/m return AL, caches,cost
反向传播推导
首先从最后一层开始,
于是对于使用\sigma(x)的最后一层,得到了
可得对于使用ReLU(x)的L-1层,每层的梯度为
以上结论可变换为:
在多层神经网络的反向传播过程中,为快速求出第i层的
每一层神经元的运算
#参数:当前层的dA,包含A_prev,W,Z的cache,激活方式activation#返回:上一层的梯度dA_prev,当前层的梯度dW,dbdef perceptron_backward(dA, cache, activation): A_prev,W,Z=cache if activation == "relu": dZ = np.array(dA, copy=True) dZ[Z <= 0] = 0 elif activation == "sigmoid": s = 1/(1+np.exp(-Z)) dZ = dA * s * (1-s) assert (dZ.shape == Z.shape) m = A_prev.shape[1] dW = np.dot(dZ,A_prev.T) db = np.sum(dZ,axis=1,keepdims=True)/m dA_prev = np.dot(W.T,dZ) return dA_prev, dW, db
反向传播
def backward_propagation(AL, Y, caches): grads = {} L = len(caches) # the number of layers m = AL.shape[1] dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))/m current_cache = caches[L-1] #取L层的缓存数据 grads["dA" + str(L-1)], grads["dW" + str(L)], grads["db" + str(L)] = perceptron_backward(dAL,current_cache,"sigmoid") for l in reversed(range(L - 1)): current_cache = caches[l] dA_prev, dW, db = perceptron_backward(grads["dA"+str(l+1)],current_cache,"relu") grads["dA" + str(l)] = dA_prev grads["dW" + str(l + 1)] = dW grads["db" + str(l + 1)] = db return grads
迭代优化
def update_parameters(parameters, grads, learning_rate): L = len(parameters) // 2 # number of layers in the neural network for l in range(L): parameters["W" + str(l+1)] = parameters["W"+str(l+1)]-learning_rate*grads["dW"+str(l+1)] parameters["b" + str(l+1)] = parameters["b"+str(l+1)]-learning_rate*grads["db"+str(l+1)] return parameters
预测函数
若\sigma(x)的输出>0.5则判为正例,否则判为反例。
def predict(X, y, parameters): m = X.shape[1] n = len(parameters) // 2 # number of layers in the neural network p = np.zeros((1,m)) probas, _ , _ = forward_propagation(X,y, parameters) for i in range(0, probas.shape[1]): if probas[0,i] > 0.5: p[0,i]=1 if probas[0,i]>0.5 else 0 print("Accuracy: " + str(np.sum((p == y)/m))) return p
整合模型
def L_layer_model(X, Y, layers_dims, learning_rate = 0.005, num_iterations = 2000, print_cost=False): costs = [] parameters = initialize_parameters(layers_dims) for i in range(0, num_iterations): AL, caches,cost = forward_propagation(X,Y, parameters) grads = backward_propagation(AL, Y, caches) parameters = update_parameters(parameters, grads, learning_rate) if i % 100 == 0: costs.append(cost) # plot the cost plt.plot(np.squeeze(costs)) plt.ylabel('cost') plt.xlabel('iterations (per tens)') plt.title("Learning rate =" + str(learning_rate)) plt.show() return parameters
训练模型
parameters = L_layer_model(train_set_x, train_set_y, layers_dims, learning_rate=0.005,num_iterations = 2000, print_cost = True)
输出为:
评估模型
predict(train_set_x,train_set_y,parameters)predict(test_set_x,test_set_y,parameters)
输出为:
Accuracy: 0.99043062201
Accuracy: 0.76
具有隐含层的神经网络比单感知机要提高了六个百分点的准确率,不过两个模型都存在明显的过拟合现象。
- 从感知机到神经网络:Python实现与测试
- 从感知机到人工神经网络
- 从感知机到BP神经网络,简单BP神经网络的实现
- 从感知器到神经网络
- 从双层感知机到BP神经网络的Delta规则
- 神经网络和深度学习简史1-从感知机到BP神经网络
- 【神经网络】:如何实现感知机
- 神经网络-感知器算法python代码实现
- 人工神经网络的设计与实现(二) 感知机
- 深度|神经网络和深度学习简史(第一部分):从感知机到BP算法
- 神经网络和深度学习简史(第一部分):从感知机到BP算法
- 机器学习与神经网络(二):感知器的介绍和Python代码实现
- 感知机Python实现
- 感知机实现Python
- python感知机实现
- 神经网络从原理到实现
- 神经网络:感知机与梯度下降
- 神经网络(上):神经元与感知机
- 关于“socket:<10106> 无法加载或初始化请求的服务提供程序”问题的解决方法
- Debugging a Stack Overflow with Windbg
- POJ 1741 Tree (点分治)
- Linux
- 音频文件的上传和剪辑
- 从感知机到神经网络:Python实现与测试
- PHP一键安装扩展的程序
- PLSQL Developer常用配置
- java 二进制 权限管理
- mac 下 android studio 的离线gradle极速配置方法
- XML简介(学习笔记)
- dlib 11 dlib自带demo ResNet
- linux进阶之旅(一)& varnish
- python3.5+selenium3.4自动化测试6_selenium的Webdriver-API整理(上)