全连接层 时间复杂度_神经网络全连接层(3)
CNN网络基础结构
神经网络-全连接层(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的矩阵。
基于上面的规则,我们把上一节的例子以批量数据的形式画成了下面一张图:
这张图从左往右有三个部分:
最左边是神经网络的结构图,可以看出里面的数据x,z和参数w,b都符合我们刚才对数据组织的定义。
中间是神经网络前向的过程。一共分为5步,其中最后一步用来计算Loss。
最右边是神经网络反向的过程。这里需要仔细看一下。为了表达上的简洁,我们用残差符号表达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。其实上面的代码本来也不多,可能犯错的地方也不多。
一些具体的例子
一个经典的例子就是用神经网络做逻辑运算。我们可以用一个两层神经网络来模拟模拟与运算。下面就是具体的代码:
# 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]]
记得初始化
初始化是神经网络一个十分重要的事情,我就不说三遍了,来个实验,如果我们把所有的参数初始化成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]]
虽然每层的参数依然相同,但是训练得到了收敛。这又说明了什么呢?关于这个问题有机会再说。
全连接层就这样聊了三期,下回可以换个口味了。
雷课:
让教育更有质量,
让教育更有想象!
全连接层 时间复杂度_神经网络全连接层(3)相关推荐
- mysql自然连接和等值连接_数据库自然连接与等值连接
mysql-数据查询语句-多表 连接查询 连接查询,是关系数据库中最主要的查询,包括等值查询.自然连接查询.非等值查询.自身连接查询.外连接查询和复合条件连接查询等. 1.等值与非等值连接查询 连接查 ...
- 易语言连接mysql学习_[易语言]连接MYSQL数据库学习
1.工具-支持库配置-MYSQL数据库3.0版 2.定义全局变量名 CTRL+G 数据库连接|整数型 3.连接MYSQL数据库 定义的全局变量名("数据库地址","用户名 ...
- 三十二楼层选几层最好_【高层住宅几层最好】33、32层高层住宅几层最好,26、18高层住宅几层最好-吉屋网知识专区...
输入您的找房需求,10秒找到理想房源 期望城市: 期望区域: 期望户型: 购房目的:不限 期望预算:不限 手机号码: 立即找房 30层高层住宅几层最好呢? 一.楼房的选择需要结合很多情况,不同的楼 ...
- mysql内连接和外连接的区别_数据库左连接、右连接、内连接、全连接区别
基本定义: left join (左连接):返回包括左表中的所有记录和右表中连接字段相等的记录. right join (右连接):返回包括右表中的所有记录和左表中连接字段相等的记录. inner j ...
- mysql和windows连接不上_问题-jdbc连接不上mysql,windows下开启两个mysql服务
1.问题: 前两天安装了个php 环境- wamp,由于我自己电脑上本身带有 mysql的数据库,在安装完后,没有注意到,mysql已经指向了 刚安装好的wamp里的mysql .导致 之前的 mys ...
- 虚拟机上装的centos7使用xshell连接不上_使用Xshell连接虚拟机Ubuntu
首先查看ubuntu中是否安装了open-server: 使用命令ps -e | grep ssh; 如果安装了,则显示ssh-agent sshd; 2. 如果没有安装,首先执行以下步骤: 执行su ...
- java连接access2013数据库_滴水穿石–Java连接Access数据库及其操作
1.配置数据源 [控制面板]->[管理工具]->[数据源ODBC] 点击添加选择Microsoft Access Driver 填写数据源名(自定义,如test),并选择数据库(指定你的A ...
- 连接mysql数据库_解决Navicat连接MySQL数据库报错问题
今天在用Navicat连接另外一台主机上的MySQL时报错: Host is not allowed to connect to this MySQL server 默认安装的mysql无法远程连接是 ...
- django连接mysql步骤_使用Django连接Mysql数据库步骤
链接mysql步骤 第一步:在终端下载pymysql文件–pip install pymysql 第二步:在gjango项目的__init__文件中添加代码 import pymysql pymysq ...
最新文章
- mysql declare与set的区别_浅谈MySQL存储过程中declare和set定义变量的区别
- c3p0数据源配置抛出Could not load driverClass com.mysql.jdbc.Driver的解决方案
- zblog php 指定分类,zblogPHP 为某些分类指定分类模板,后台版方法
- 大众汽车和鸿蒙,鸿蒙系统下个月即将与大众见面,首发平台并非手机
- Chapter12(动态内存)--C++Prime笔记
- A 附录、ResolvableType
- java中特殊流程控制语句,深入分析JAVA流程控制语句
- cfe刷机教程 斐讯k3_斐讯K3刷机教程官改V2.1D或者其它版本教程
- TIA博途中如何将CPU导出为GSD文件与其他PLC进行PROFINET通信?
- COJ 0359 xjr考考你数据结构(根号2)线段树区间增加
- 金桔蓝牙LoRa主被动一体定位系统原理
- Linux系统:安装QQ教程
- UCOSIII实时操作系统------软件定时器
- 关于Scaner和BufferReader
- 面试刷题LeetCode经典100道
- 工具学习——有哪些好用的学术翻译工具
- Bootstrap全部知识点总结
- asp.net动态设置CSS等
- 上海最牛逼的75家互联网公司
- 2017年度全国出差地图!