在学习神经网络之前,我认为弄懂逻辑回归是很有必要的(对于逻辑回归比较陌生的可以看看该作者分类那篇文章(●'◡'●)),因为逻辑回归就相当于神经网络的一个“神经元”,而整个神经网络就是由这些“神经元”构成的。我们知道每个"神经元"的作用是完成一个二分类的任务,那么将这些“神经元”链接起来自然而然是为了完成一个多分类的任务,这也就是神经网络的作用了。为了方便后面分享内容的理解,我们会先从一个神经元模型讲起,再到二层前馈神经网络,再和大家分享误差反向传播内容,最后与大家分享keras实现神经网络模型。希望能对大家有所帮助,如有错误,还望大家不吝指出。

目录

一、神经元模型

二、二层前馈神经网络

三、误差反向传播

四、使用Keras实现神经网络模型

五、文章代码合集


一、神经元模型

在神经元模型中有输入值x1,x2......xd(可以是正或负的实数值),也有权重w1,w2.......wd(这里也可以叫它们为神经元的突触传递强度),也有偏置值b,之后我们就会得到输入总和(我们也管输入总和为膜电位),最后我们通过激活函数sigmoid函数得到整个神经元的输出值a,a是0和1之间的连续值。正如我上述一样,一个逻辑回归模型就相当于一个神经元。并且与逻辑回归模型一样,神经元模型也是用平均交叉熵误差作为损失函数:

接下来我们将神经元拼接组合就得到了我们的神经网络。

二、二层前馈神经网络

如上图所示的是一个二层前馈神经网络。有人把输入层也包含在内,认为它是三层的。考虑到权重参数只有W和V这两层,把它当作二层的做法似乎更为妥当。

这个神经网络接受二维的输入,然后用三个神经元进行输出。我们要对网络进行训练,使得每个输出神经元的输出值能够代表数据属于每个类别的概率。b、a是输入总和,是输入总和应用sigmoid函数后,得到中间层神经元的输出,但有一点需要注意,今后我们用的不一定是sigmoid函数,又可能使用别的函数,我们称这类函数为激活函数。这个中间层的输出决定了输出层的神经元的活动。输出层中的是输入总和运用softmax函数后得到的输出。

使用了Softmax函数易知,输出的和等于1,因此就可以把这些值解释为概率了。这样我们就完成了网络功能的定义。上面的是永远为1的虚拟神经元,这样做是为了让求和表达式中包含偏置项。

接下来,我们用代码来实现上面的神经网络。

我们先生成一些需要用到的数据。

import numpy as np
import matplotlib.pyplot as pltnp.random.seed(seed=1)  #固定随机数
N = 200   #数据个数
K = 3     #分类个数
T = np.zeros((N,3),dtype=np.uint8)#dtype=np.uint8有利于加快运算速度
X = np.zeros((N,2))#生成二维数据X_range0 = [-3,3]
X_range1 = [-3,3]
#有利于后面的画图Mu = np.array([[-.5,-.5],[.5,1.0],[1,-.5]]) #分类的中心
Sig = np.array([[.7,.7],[.8,.3],[.3,.8]])   #分类的离散值
Pi = np.array([0.4,0.8,1])  #各分布所占的比例for n in range(N):wk = np.random.rand()for k in range(K):if wk < Pi[k]:T[n, k] = 1breakfor k in range(2):X[n,k] = np.random.randn() * Sig[T[n,:] == 1,k] + Mu[T[n,:] == 1,k]

将数据分为训练数据X_train,T_train和测试数据X_test,T_test。为了验证是否发生过拟合。

TrainingRatio = 0.5
X_n_training = int(N * TrainingRatio)
X_train = X[:X_n_training,:]
X_test = X[X_n_training:,:]
T_train = T[:X_n_training,:]
T_test = T[X_n_training:,:]

然后我们将训练集和测试集可视化

def Show_data(x,t):wk,n = t.shapefor i in range(n):plt.plot(x[t[:,i] == 1,0],x[t[:,i] == 1,1],marker='o',linestyle='none',alpha=0.8)plt.grid(True)plt.subplot(1,2,1)
Show_data(X_train,T_train)
plt.xlim(X_range0)
plt.ylim(X_range1)
plt.title('Training Data')plt.subplot(1,2,2)
Show_data(X_test,T_test)
plt.xlim(X_range0)
plt.ylim(X_range1)
plt.title('Test Data')
plt.show()

我们把二层前馈神经网络的函数命名为FNN。FNN接收传给网络的输入x,输出y。输入x是D维向量,输出y是K维向量,目前我们探讨的是D=2,K=3的情况。我们希望网络的函数FNN能够一次处理N(这里的N=100)个数据,因此将x作为数据量N*D维的矩阵,将y作为数据量N*K维的矩阵。向量y[n,0]、y[n,1]、y[n,2]表示x[n,:]属于类别0、1、2的概率。这里要注意的是,必须保证概率的和为1,好在我们有softmax函数,做到这点还是没有难度。另外,为了使中间层的数量和输出的维度能够自由修改,我们把二者分别命名为M、K,并将其作为网络的参数(通过输入数据x就能知道N和D的值,所以N和D不在参数里)。

影响网络行为的重要参数——中间层的权重W和输出层的权重V也要传给网络。W是M*(D+1)矩阵(由于还有偏置输入的权重,所以为D+1),V是K*(M+1)矩阵(这里也需要考虑中间层的偏置神经元,所以为M+1).。

W和V的信息通过汇总了W和V信息的向量wv传递。比如,中间层的神经元数据M=2,输出维度K=3,那么向网络传递的权重为:

W=[[0,1,2],[3,4,5]]  M*(D+1)=2*3

V=[[6,7,8],[9,10,11],[12,13,14]]   K*(M+1)=3*3

这时的wv为:

wv = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14])

wv的长度是M*(D+1)+K*(M+1)。将这些参数汇为一个,后面进行最优化的程序就会更容易。

FNN的输出是与N个数据想应的输出y(N*K)矩阵,中间层的输出z,输出层和中间层的输入总和为a,b。

def Sigmoid(x):y = 1 / (1 + np.exp(-x))return ydef FNN(wv,M,K,x):N,D = x.shape   #输入维度w = wv[:M * (D + 1)]  #传递到中间层神经元时用到的权重w = w.reshape(M,(D + 1)) v = wv[M * (D + 1):]  #传递到输出层神经元时用到的权重v = v.reshape((K,M+1))b = np.zeros((N,M + 1)) #中间层神经元的输入总和z = np.zeros((N,M+1))  #中间层神经元的输出a = np.zeros((N,K)) #输出层神经元的输入总和y = np.zeros((N,K)) #输出层神经元的输出for n in range(N):#中间层的计算for m in range(M):b[n,m] = np.dot(w[m,:],np.r_[x[n,:],1])  #np.r_[x[n,:],1]将1的虚拟输入作为x的第三个元素加在后面,np.r_[A,B]是横向链接矩阵的命令z[n,m] = Sigmoid(b[n,m])#输出层的计算z[n,M] = 1 #虚拟神经元,求偏置wkz = 0for k in range(K):a[n,k] = np.dot(v[k,:],z[n,:])wkz = wkz + np.exp(a[n,k]) #softmax函数for k in range(K):y[n,k] = np.exp(a[n,k]) / wkzreturn y,a,z,b

最后测试程序的效果,设M=2,K=3,WV的长度为2*3+3*3=15的权重向量。WV的元素全部为1,输入只使用X_traind两个数据,显示的输出从上到下依次是y,a,z,b的值。

WV=np.ones(15)
M=2
K=3
FNN(WV,M,K,X_train[:2,:]

这就是我们神经网络的前向传播,得出来的结果肯定不是我们想要的,参数肯定不是理想的,而要得到理想的参数,就要用到神经网络里面非常重要的误差反向传播

三、误差反向传播

误差反向传播使用网络输出中的误差(输出与监督信号的差)信息,从输出层权重V到中间层权重W,即与输入反方向地更新权重,这也是这个方法名称的由来。

首先,我们知道每一个输出层的输出后的误差函数是平均交叉熵,那么我们根据平均交叉熵使用梯度法,自然而然就更新了权重。

平均交叉熵:

N是样本数量,K是样本的类别个数。

那要用到梯度法,那我们肯定就离不开平均交叉熵的导数了。

我们先来求离输出层最近的参数V的导数。

我们知道,所以有:

由于过程复杂,我们直接给出结果(对过程有兴趣的可以私信我)。

所以由梯度法就有:

同理离输出层次远的参数W更新如下:

其中

接下来就是代码实现部分了。

首先我们肯定得将平均交叉熵误差函数写出来da

def CE_FNN(wv,M,K,x,t):N,D = x.shapey,a,z,b = FNN(wv,M,K,x)ce = -np.dot(t.reshape(-1),np.log(y.reshape(-1))) / Nreturn ce

接着我们将导数写出来

def dCE_FNN(wv,M,K,x,t):N,D = x.shape#把wv恢复为w和vw = wv[:M * (D + 1)]w = w.reshape(M,(D + 1))v = wv[M * (D + 1):]v = v.reshape((K,M + 1))#输入x,得到yy,a,z,b = FNN(wv,M,K,x)dwv = np.zeros_like(wv)dw = np.zeros((M,D + 1))dv = np.zeros((K,M + 1))delta1 = np.zeros(M)   #第一层的误差delta2 = np.zeros(K)   #第二层的误差for n in range(N):#求输出层的误差for k in range(K):delta2[k] = (y[n,k] - t[n,k])#求中间层的误差for j in range(M):delta1[j] = z[n,j] * (1 - z[n,j]) * np.dot(v[:,j],delta2)#求v的梯度dvfor k in range(K):dv[k,:] = dv[k,:] + delta2[k] * z[n,:] / N#求w的梯度dwfor j in range(M):dw[j,:] = dw[j,:] + delta1[j] * np.r_[x[n,:],1] / N#汇总dw和dv的信息,形成dwvdwv = np.c_[dw.reshape((1,M * (D + 1))),dv.reshape((1,K * (M + 1)))]dwv = dwv.reshape(-1)return dwv

下一步,我们用梯度法更新参数

def Fit_FNN(wv_init,M,K,x_train,t_train,x_test,t_test,n,alpha):wv = wv_init.copy()err_train = np.zeros(n)err_test = np.zeros(n)wv_hist = np.zeros((n,len(wv_init)))for i in range(n):wv = wv - alpha * dCE_FNN(wv,M,K,x_train,t_train)err_train[i] = CE_FNN(wv,M,K,x_train,t_train)err_test[i] = CE_FNN(wv,M,K,x_test,t_test)wv_hist[i,:] = wvreturn wv,wv_hist,err_train,err_test

接下来,让我们通过作图来看看效果。

M = 2
K = 3
np.random.seed(1)
WV_init = np.random.normal(0,0.01,M*3+K*(M+1))
N_step = 1000
alpha = 0.5
WV,WV_hist,Err_train,Err_test = Fit_FNN(WV_init,M,K,X_train,T_train,X_test,T_test,N_step,alpha)#显示权重随时间的变化
plt.subplot(1,2,1)
plt.plot(WV_hist[:,:M*3],'r')
plt.plot(WV_hist[:,M*3:],'b')
#显示决策边界
plt.subplot(1,2,2)
Show_data(X_test,T_test)
xb = np.linspace(-2,2,50)
x11 = -(WV[0]*xb + WV[2])/ WV[1]
x12 = -(WV[3]*xb + WV[5])/ WV[4]
x13 = -(WV[6]*xb + WV[8])/ WV[7]
plt.plot(xb,x11,'g')
plt.plot(xb,x12,'r')
plt.plot(xb,x13,'b')
plt.show()

神经网络(从手撕到工具包)相关推荐

  1. 手撕图机器学习,图神经网络

    手撕图机器学习,图神经网络 写在前面 & 配套链接(访者必读) 图的基本表示 图的基本参数 图的类别 节点连接数(Node degree) 图的矩阵表示(邻接矩阵) 连接列表和邻接列表 其他图 ...

  2. 手撕Resnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑。跑的代码有问题的可以在评论区指出,看到了会回复。训练代码和预测代码均有。

    Alexnet网络详解代码:手撕Alexnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑.跑的代码有问题的可以在评论区指出,看到了会回复.训练代 ...

  3. 手撕神经网络(2)—— 将基本组件搭建成躯干

    前言 之前写了篇文章<手撕神经网络(1)--神经网络的基本组件>介绍了手撕神经网络的各个层.但是疫情和学习原因,导致其后续一直没有机会写,这两天难得空闲,终于有机会继续分享. 概要 在文章 ...

  4. 手撕Alexnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑。跑的代码有问题的可以在评论区指出,看到了会回复。训练代码和预测代码均有。

    Alexnet网络详解代码:手撕Alexnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑.跑的代码有问题的可以在评论区指出,看到了会回复.训练代 ...

  5. 从零构建神经网络-不使用框架(纯纯手撕)

    一.从零构建神经网络-不使用框架(纯手撕) 神经网络从0开始 动手从零开始实现一个神经网络,不使用框架,一步一步推理应该可以加深一下对神经网络的理解. 网络结构为三层全连接网络,节点个数依次为784. ...

  6. 深度学习之手撕深度神经网络DNN代码(基于numpy)

    声明 1)本文仅供学术交流,非商用.所以每一部分具体的参考资料并没有详细对应.如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除. 2)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢 ...

  7. 手撕VGG卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑。跑的代码有问题的可以在评论区指出,看到了会回复。训练代码和预测代码均有。

    Alexnet网络详解代码:手撕Alexnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑.跑的代码有问题的可以在评论区指出,看到了会回复.训练代 ...

  8. Interview:算法岗位面试—11.06早上上海某智能驾驶科技公司(创业)笔试+面试之手撕代码、项目考察、比赛考察、图像算法的考察等

    Interview:算法岗位面试-11.06早上上海某智能驾驶科技公司(创业)笔试+面试之手撕代码.项目考察.比赛考察.图像算法的考察等 导读:该公司是在同济某次大型招聘会上投的,当时和HR聊了半个多 ...

  9. 手撕 CNN 经典网络之 VGGNet(理论篇)

    2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet.VGGNet是比AlexNet更深的 ...

最新文章

  1. 编译-链接-运行-环境配置各种error汇总
  2. 软件破解系列之OD中断方法
  3. 驱动操作硬件的根本操作
  4. 好物推荐 | 轻薄神器,妈妈再也不用担心我的颈椎了
  5. [CQOI 2006]线段树之简单题
  6. 详解Oracle DELETE和TRUNCATE 的区别
  7. vue中引入外部文件js、css、img的方法
  8. [Java] 蓝桥杯ADV-182 算法提高 前10名
  9. 计算机主机结构讲解,电脑内部结构图和讲解
  10. WIN10虚拟机安装教程
  11. KY RD9700_USB网卡驱动
  12. Liunx使用apt安装本地deb软件包
  13. php后缀加swp,当编辑文件出现swp的时候如何处理
  14. 一分钟让你知道Hadoop是什么
  15. 机器学习-新闻分类案例
  16. 爱思助手 for Mac(苹果手机助手)中文版
  17. 白平衡(Color Constancy,无监督AWB):CVPR2019论文解析
  18. linux iscsi软件,Redhat Linux 配置 iSCSI 连接存储
  19. 没有处理程序要使用以下任何注释:javax.persistence.PersistenceContext
  20. 基于PHP的租赁商城系统(包括数据库和后台)

热门文章

  1. #比赛# 互联网+比赛后感
  2. Text to SQL 论文汇总(NL2SQL/TableQA)
  3. 第十九讲:爱情:如何让爱情天长地久 第二十讲:幽默 第二十一讲:爱情自尊
  4. 手机话费充值接口开发指南(含API文档,充值移动、联通、电信话费)
  5. 【加精】手机话费充值API接口(PHP版)
  6. python 获取视频时长
  7. 概率题 宝剑升级需要多少宝石
  8. MySQL手动注入步骤
  9. 网络找不到自己计算机,电脑搜不到自己家的wifi怎么办?
  10. C++对象(懒得传图版)