全连接层 时间复杂度_神经网络全连接层(3)

0da2ea17e935291e5ace541818959a87.gifa6905e0ca19ee3ebaedf223a48db8e9d.png

CNN网络基础结构

36fbabd135914d22402b88f366c186ae.png

神经网络-全连接层(3)

上一回我们聊完了算法,这回我们正式开始写代码。上回在做公式推导的时候,我们实际上只是针对一个数据样本进行推导,而实际中,计算和训练都是一批一批完成的。大多数机器学习训练都有batch的概念,而训练中batch的计算不是一个一个地算,而是一批数据集中算,那么就需要用上矩阵了。

首先给出Loss的代码,这里y和t都是按列存储的,每一列都是一个样本:

class SquareLoss:
   def forward(self, y, t):
       self.loss = y - t
       return np.sum(self.loss * self.loss) /  self.loss.shape[1] / 2
   def backward(self):
       return self.loss

为了代码的简洁,我们在前向运算的时候就把一些后向计算的信息都保存起来,这样在后向计算的时候就能简单点。这样这个类就不能具备多线程的特性了,不过想支持多线程的功能还有别的办法。后面的全连接层也会采用同样的思路——前向为后向准备运算数据。

上一节我们讲了1个例子,输入有2个元素,第一层有4个输出,第2层有1个输出。我们假设训练数据有N个,我们对所有相关的训练数据和参数做以下的约定:

  • 所有的训练数据按列存储,也就是说如果把N个数据组成一个矩阵,那个矩阵的行等于数据特征的数目,矩阵的列等于N

  • 线性部分的权值w由一个矩阵构成,它的行数为该层的输入个数,列数为该层的输出个数。如果该层的输入为2,输出为4,那么这个权值w的矩阵就是一个2*4的矩阵。

  • 线性部分的权值b是一个行数等于输出个数,列数为1的矩阵。

基于上面的规则,我们把上一节的例子以批量数据的形式画成了下面一张图:

bd9e5635b6b66d1dee94bd63c1803cba.png

这张图从左往右有三个部分:

  1. 最左边是神经网络的结构图,可以看出里面的数据x,z和参数w,b都符合我们刚才对数据组织的定义。

  2. 中间是神经网络前向的过程。一共分为5步,其中最后一步用来计算Loss。

  3. 最右边是神经网络反向的过程。这里需要仔细看一下。为了表达上的简洁,我们用残差符号表达Loss对指定变量的偏导数。同时为了更加简洁地表达梯度计算的过程,在这个过程中我们对其中一个矩阵做了矩阵转置,这样可以确保最终输出维度的正确。

对于上图右边的部分,需要认真地看几遍,最好能仔细地推导一遍,才能更好地掌握这个推导的过程,尤其是为了维度对矩阵做转置这部分。

看懂了上面的图,接下来要做的就是对上面的内容进行总结,写出最终的矩阵版后向传播算法:

class FC:
   def __init__(self, in_num, out_num, lr = 0.1):
       self._in_num = in_num
       self._out_num = out_num
       self.w = np.random.randn(in_num, out_num)
       self.b = np.zeros((out_num, 1))
       self.lr = lr
   def _sigmoid(self, in_data):
       return 1 / (1 + np.exp(-in_data))
   def forward(self, in_data):
       self.topVal = self._sigmoid(np.dot(self.w.T, in_data) + self.b)
       self.bottomVal = in_data
       return self.topVal
   def backward(self, loss):
       residual_z = loss * self.topVal * (1 - self.topVal)
       grad_w = np.dot(self.bottomVal, residual_z.T)
       grad_b = np.sum(residual_z)
       self.w -= self.lr * grad_w
       self.b -= self.lr * grad_b
       residual_x = np.dot(self.w, residual_z)
       return residual_x

好了,现在我们有了Loss类和全连接类,我们还需要一个类把上面两个类串联起来,这里为了后面的内容我们定义了许多默认变量:

class Net:
   def __init__(self, input_num=2, hidden_num=4, out_num=1, lr=0.1):
       self.fc1 = FC(input_num, hidden_num, lr)
       self.fc2 = FC(hidden_num, out_num, lr)
       self.loss = SquareLoss()
   def train(self, X, y): # X are arranged by col
       for i in range(10000):
           # forward step
           layer1out = self.fc1.forward(X)
           layer2out = self.fc2.forward(layer1out)
           loss = self.loss.forward(layer2out, y)
           # backward step
           layer2loss = self.loss.backward()
           layer1loss = self.fc2.backward(layer2loss)
           saliency = self.fc1.backward(layer1loss)
       layer1out = self.fc1.forward(X)
       layer2out = self.fc2.forward(layer1out)
       print 'X={0}'.format(X)
       print 't={0}'.format(y)
       print 'y={0}'.format(layer2out)

代码是写完了,可是我们还需要验证一下自己的代码是不是正确的。一般来说我们会采用一些近似方法计算验证梯度是否正确,而现在,有一个博客为我们做了这件事情:

A Step by Step Backpropagation Example

http://link.zhihu.com/?target=https%3A//mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/

把我们的代码用博客上数据和结果做一下验证,就可以帮助我们修正代码做好debug。其实上面的代码本来也不多,可能犯错的地方也不多。

bd196c8f98e7a82471a2b5032c92f620.png

一些具体的例子

一个经典的例子就是用神经网络做逻辑运算。我们可以用一个两层神经网络来模拟模拟与运算。下面就是具体的代码:

# and operation

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]).T

y = np.array([[0],[0],[0],[1]]).T

net = Net(2,4,1,0.1)

net.train(X,y)

以下是调用代码给出的结果,可以看出最终的结果效果还不错,经过10000轮的迭代,最终模型给出的结果和我们的期望结果十分相近,实际上如果我们继续进行迭代,这个算法的精度还可以进一步地提高,Loss可以进一步地减少:

iter = 0, loss =0.105256639066

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.40930536  0.4617139   0.36923076  0.4299025 ]]

iter = 1000, loss =0.0229368486589

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.04445123  0.22684496  0.17747671  0.68605373]]

iter = 2000, loss =0.00657594469044

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.01057127  0.11332809  0.11016211  0.83411794]]

iter = 3000, loss =0.00322081318498

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00517544  0.07831654  0.07871461  0.88419737]]

iter = 4000, loss =0.00201059297485

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00336374  0.06171018  0.0624756   0.90855558]]

iter = 5000, loss =0.00142205310651

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00249895  0.05189239  0.05257126  0.92309992]]

iter = 6000, loss =0.00108341055769

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00200067  0.04532728  0.04585262  0.93287134]]

iter = 7000, loss =0.000866734887908

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00167856  0.04058314  0.04096262  0.9399489 ]]

iter = 8000, loss =0.000717647908313

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00145369  0.03696819  0.0372232   0.94534786]]

iter = 9000, loss =0.000609513241467

=== Label vs Prediction ===

t=[[0 0 0 1]]

y=[[ 0.00128784  0.03410575  0.03425751  0.94962473]]

=== Final ===

X=[[0 0 1 1]

[0 1 0 1]]

t=[[0 0 0 1]]

y=[[ 0.00116042  0.03177232  0.03183889  0.95311123]]

5ff75b23bc6ec27258b9a547f309211f.png

记得初始化

初始化是神经网络一个十分重要的事情,我就不说三遍了,来个实验,如果我们把所有的参数初始化成0,会发生一个可怕的事情:

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]).T

y = np.array([[0],[0],[0],[1]]).T

net = Net(2,4,1,0.1)

net.fc1.w.fill(0)

net.fc2.w.fill(0)

net.train(X,y)

print "=== w1 ==="

print net.fc1.w

print "=== w2 ==="

print net.fc2.w

直接看结果:

=== Final ===X=[[0 0 1 1][0 1 0 1]]t=[[0 0 0 1]]y=[[ 3.22480024e-04 2.22335711e-02 2.22335711e-02 9.57711099e-01]]=== w1 ===[[-2.49072772 -2.49072772 -2.49072772 -2.49072772][-2.49072772 -2.49072772 -2.49072772 -2.49072772]]=== w2 ===[[-3.373125][-3.373125][-3.373125][-3.373125]]

不但没有训练出合理的结果,而且每一层的参数还都是一样的。

但是如果把每层参数设为不同的固定值呢?

X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]).T

y = np.array([[0],[0],[0],[1]]).T

net = Net(2,4,1,0.1)

net.fc1.w.fill(1)

net.fc2.w.fill(0)

net.train(X,y)

print "=== w1 ==="

print net.fc1.w

print "=== w2 ==="

print net.fc2.w

结果竟然也不错:

=== Final ===

X=[[0 0 1 1]

[0 1 0 1]]

t=[[0 0 0 1]]

y=[[ 0.00399349  0.02830098  0.02830098  0.96924181]]

=== w1 ===

[[ 2.48265841  2.48265841  2.48265841  2.48265841]

[ 2.48265841  2.48265841  2.48265841  2.48265841]]

=== w2 ===

[[ 3.231811]

[ 3.231811]

[ 3.231811]

[ 3.231811]]

虽然每层的参数依然相同,但是训练得到了收敛。这又说明了什么呢?关于这个问题有机会再说。

全连接层就这样聊了三期,下回可以换个口味了。

f06e5ddc8a0abf251b79675d1774c01f.png

雷课:

       让教育更有质量,

       让教育更有想象!

946033c0b54458c57a6315840178f084.gif0728bcbed442cf8a715a7cce497326f0.png66f91295e3dec8a2583fd86673c1c853.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

line和spline_探索适用于Apache Spark的Spline Data Tracker和可视化工具(第1部分)

line和spline最近引起我注意的一个有趣且很有希望的开源项目是Spline ,它是由Absa维护的Apache Spark数据沿袭跟踪和可视化工具。 该项目由两部分组成:一个在驱动程序上工作的Scala库,该库通过分析Spark执行计划来捕获数据沿袭,以…

MacBook如何快速显示桌面

1.触控板中张开拇指和其它三指 2.通过触发角来快速显示桌面

怎么把word里面虚线变成实线_弱电不会制作cad图,花3分钟看完,只要会用WORD保证你能画出来...

今天我要给你介绍的就是Microsoft Office Visio是Microsoft Office 套件之一。安装Visio之后,可以类比Word的操作方法一样来使用,不过,就是比在Word里画图、修改更方便,功能更强大。特别是在做技术路线图、各种图表的绘图&#xf…

MacBook如何设置分屏浏览的快捷键

MacBook的系统自身无法设置,必须安装第三方软件才能设置,例如:BetterAndBetter、Magnet、BetterSnapTool 等。 BetterAndBetter 的设置,如下图所示:

api自动化测试_API测试和自动化101:基本指南

api自动化测试API代表A pplication P AGC软件我覆盖整个院落。 通常,API用于通过使用任何通信方式来促进两个不同应用程序之间的交互。 在网络上使用API​​时,我们将其称为“ Web服务”。 近年来,API已成为编程的Struts。 与在应用程序中一样…

web.config连接mysql_web.config中配置数据库连接的方式

在网站开发中,数据库操作是经常要用到的操作,ASP.NET中一般做法是在web.config中配置数据库连接代码,然后在程序中调用数据库连接代码,这样做的好处就是当数据库连接代码需要改变的时候,我们只要修改web.config中的数据…

BetterAndBetter(BAB)的使用详解

文章目录多指轻点时防止左键点击规则管理重置全部设置和规则多指轻点时防止左键点击 在正常情况下按下触控板的左键,使用鼠标选择好文本后,松开触控板的左键,就已经退出文本选择模式了,此时移动鼠标应该是不会影响到已经选择的文…

gradle使用maven_使用Gradle – 2019版从Travis可靠发布到Maven Central

gradle使用maven得益于在2018年和2019年末实现的显式登台存储库创建功能集,使您(自动)从Travis(不仅是)发布到Maven Central更加可靠。 背景 如果您仅想获取有关如何使工件从Travis发行的信息更可靠的信息&#xff0c…

mysql 事件 day hour_Mysql事件调度器(Event Scheduler)

Mysql中的事件调度器Event Scheduler类似于linux下的crontab计划任务的功能,它是由一个特殊的时间调度线程执行的一、查看当前是否开启了event scheduler三种方法:1) SHOW VARIABLES LIKE ‘event_scheduler’;2) SELECT event_scheduler;3) SHOW PROCESSLIST;(是否有State为&a…

2020年全国儿童青少年总体近视率为52.7%,比上年上升2.5%播

2021年7月13日,国家卫健委召开新闻发布会介绍儿童青少年近视防控和暑期学生健康有关情况。国家卫健委疾控局副局长再那吾东玉山介绍,2020年上半年全民居家抗疫减少了户外活动和放松眼睛的时间,对近视防控工作带来了挑战。为全面评估近视率的情…

精简jdk包_在JDK 12精简数字格式中使用最小分数数字

精简jdk包帖子“ 紧凑数字格式出现在JDK 12中 ”演示了对JDK 12中 NumberFormat的支持,以支持紧凑数字格式 。 该帖子中显示的示例仅使用NumberFormat的实例,这些实例是通过调用NumberFormat的新重载getCompactNumberInstance(-)方法返回的,因…

mysql insert limit_Mysql Limit 调优

建表与插入数据SQL对比基本数据创建表CREATE TABLE student(id int(10) NOT NULL AUTO_INCREMENT,name varchar(25) DEFAULT NULL,age tinyint(2) DEFAULT NULL,live varchar(255) DEFAULT NULL,PRIMARY KEY (id)) ;批量插入1百万条数据DROP PROCEDURE IF EXISTS insert_Stu;DE…

预防近视的方法

推荐的方法里面有角膜塑形镜,也就是OK镜,还有低浓度阿托品、补光仪、离焦软镜、离焦框架眼镜等,阿托品离焦眼镜

spoon java_如何以及为什么使用Spoon分析,生成和转换Java代码

spoon javaSpoon是分析,生成和转换Java代码的工具。 在本文中,我们将看到通过使用以编程方式处理代码的技术可以实现什么。 我认为这些技术不是很为人所知或使用,这很遗憾,因为它们可能非常有用。 谁知道,即使您不想使…

下列支持mysql中文字符_MySQL中文支持问题

0. 本文目的让MySQL支持中文1. 测试环境Windows XP sp2,MySQL Server 5.1,MySQL Administrator 1.2.172. 操作步骤1)修改数据库的默认字符集(开始菜单) - MySQL - MySQL Server 5.1 - MySQL Server Instance Config Wizard:- Reconfigure Ins…

异常(Exception)的学习

1.Throwsable 的两个子类 Exception 和 Error 2.Exception 这是编译期异常,可以捕获处理 3.RuntimeException 表示运行期间的异常,它是 Exception 的子类 4.Error 这是程序错误,不可捕获处理。例如,内存溢出 5.throws 关键字&…

recorder_将Java Flight Recorder与OpenJDK 11一起使用

recorderJava Flight Recorder(JFR)曾经是Oracle JDK的商业附加组件。 由于它最近与Java Mission Control一起开源,因此使用OpenJDK 11的每个人现在都可以免费使用此出色的工具对Java应用程序进行故障排除。 JFR以前是专有解决方案&#xff0…

mysql 酒店管理设计_酒店管理系统的设计与实现(Myeclipse,MySQL)

酒店管理系统的设计与实现(Myeclipse,MySQL)(任务书,开题报告,中期检查表,文献综述,外文翻译,毕业论文12000字,程序代码,MySQL数据库)本系统是一个酒店管理系统,以Java Web技术为基础,采用MVC设计模式,利用MyEclipse编程平台结合MySQL数据库&…

可以在循环体内声明局部变量吗?

循环体声明的局部变量,第一次创建后,后面每次循环就不会再创建了。因为 JVM 在执行创建局部变量代码时,会先查询是否存在同名的局部变量,若存在则不会创建。如果有赋值,则直接删除旧的数据,保存新的数据&am…

传一个实体一个string_没想到,一个小小的String还有这么多窍门

1. 看看源码大家都知道, String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)。我们先来看看 String 的源码。在 Java 8 中,String 内部使用 char 数组存储数据。在 Java 9 之后,String 类的实现…