卷积神经网络

代码:https://github.com/TimVerion/cat

卷积层

卷积层:通过在原始图像上平移来提取特征,每一个特征就是一个特征映射

原理:基于人脑的图片识别过程,我们可以认为图像的空间联系也是局部的像素联系比较紧密,而较远的像素相关性比较弱,所以每个神经元没有必要对全局图像进行感知,只要对局部进行感知,而在更高层次对局部的信息进行综合操作得出全局信息;即局部感知。

卷积分的知识

 

过程:

作用:

局部感知:在进行计算的时候,将图片划分为一个个的区域进行计算/考虑; 参数共享机制:假设每个神经元连接数据窗的权重是固定的 滑动窗口重叠:降低窗口与窗口之间的边缘不平滑的特性。

不同的过滤器产生不同的效果:

真实做了什么?

一步有一步的浓缩,产生更加靠谱更加准确的特征

一张图片卷积后高和宽如何变化?

# 卷积函数
def conv_fun(cache):
   x, w, b = cache["a"], cache["w"], cache["b"]
   pad, stride = cache["pad"], cache["stride"]
   N, C, H, W = x.shape
   F, C, HH, WW = w.shape
   # numpy提供的可以填充0的api,constant代表用一样的值填充前两维不填,后两维各自填充pad行
   x_padded = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), mode='constant')
   H_new = int((H + 2 * pad - HH) / stride) + 1
   W_new = int((W + 2 * pad - WW) / stride) + 1
   s = stride
   out = np.zeros((N, F, H_new, W_new))
   for i in range(N):  # ith image
       for f in range(F):  # fth filter
           for j in range(H_new):
               for k in range(W_new):
                   out[i, f, j, k] = np.sum
                  (x_padded[i, :, j * s:(HH + j * s), k * s:(WW + k * s)] * w[f]) +b[f]
   return out

池化层

池化层:通过特征后稀疏参数来减少学习的参数,降低网络的复杂度,(最大池化和平均池化)

# 前向池化
def max_pool_forward(cache):
  x, HH, WW, s = cache["net"], cache["HH"], cache["WW"], cache["s"]
  N, C, H, W = x.shape
  H_new = 1 + int((H - HH) / s)
  W_new = 1 + int((W - WW) / s)
  out = np.zeros((N, C, H_new, W_new))
  for i in range(N):
      for j in range(C):
          for k in range(H_new):
              for l in range(W_new):
                  # 定位到某个窗口
                  window = x[i, j, k * s:HH + k * s, l * s:WW + l * s]
                  # 找到该窗口的最大值,然后赋值
                  out[i, j, k, l] = np.max(window)
  return out

ReLU层

http://playground.tensorflow.org/

作用:增加网络非线性的分割能力

# Relu函数
def Relu(x):
   return np.maximum(0, x)

全连接层

# 全连接
def fc(net, w, b):
   N = net.shape[0]
   # 把每个像素提取出来
   x_row = net.reshape(N, -1)
   out = np.dot(x_row, w) + b
   return out

CNN反向传播的不同之处

首先要注意的是,一般神经网络中每一层输入输出a,z都只是一个向量,而CNN中的a,z是一个三维张量,即由若干个输入的子矩阵组成。其次:

  1. 池化层没有激活函数。这个问题倒比较好解决,我们可以令池化层的激活函数为σ(z)=z,即激活后就是自己本身。这样池化层激活函数的导数为1。

  2. 池化层在前向传播的时候,对输入进行了压缩,那么我们向前反向推导上一层的误差时,需要做upsample处理

  3. 卷积层是通过张量卷积,或者说若干个矩阵卷积求和而得到当前层的输出,这和一般的网络直接进行矩阵乘法得到当前层的输出不同。这样在卷积层反向传播的时候,上一层误差的递推计算方法肯定有所不同。

  4. 对于卷积层,由于W使用的运算是卷积,那么由该层误差推导出该层的所有卷积核的W,b的方式也不同。

池化层的反向传播

这时候假如前向的时候是最大化池化:

这时候要用到前向传播的时候最大值位置进行还原:

如果是平均:

卷积层的反向传播

吴恩达笔记中的推导:

卷积神经网络中的反向传播(可选/非梯度)

在现代深度学习框架中,你只需要执行正向传递,这个框架负责向后传递,所以大多数深度学习工程师不会这样做

需要麻烦的细节向后传递。卷积的向后传递网络是复杂的。但是,如果您愿意,您可以完成这个可选部分

来了解卷积网络中的backprop是什么样子的。

在之前的课程中,你实现了一个简单的(完全连接的)神经网络,使用反向传播来计算关于更新成本的导数

参数。类似地,在卷积神经网络中你可以计算为了更新参数对代价求导。backprop方程不是平常那样的,我们在课堂上没有推导出来,但是我们简单地介绍了一下:

Convolutional layer backward pass

让我们从实现CONV层的向后传递开始。

 
  1. 计算dA:

这是计算dA对于一定的过滤器Wc的代价的公式以及一个给定的训练例子:

 

其中Wc是一个过滤器,dZhw是上一层传递过来的梯度,每次我们都将相同的过滤器Wc乘以不同的dZ更新的。我们这样做主要是因为当计算正向传播时,每个过滤器都是由不同的a_slice点乘求和。因此,当计算dA的反向传播的时候,我们也是把所有a_slice的梯度相加。

在代码中,在合适的for循环中,这个公式可以转化为:

da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] 
+=,W[:,:,:,c] * dZ[i, h, w, c]
  1. 计算dW: 这是计算dWc (dWc是一个过滤器的导数)关于损失的公式:

     

    其中aslice是原样本的一个窗口。因此,这就得到了W关于这个窗口的梯度。这是相同的W,我们将所有这些梯度相加得到dW。

    在代码中,在合适的for循环中,这个公式可以转化为:

    dW[:,:,:,c] += a_slice * dZ[i, h, w, c]
  2. 计算db: 这是计算db对于一个过滤器Wc的代价的公式:

     

    正如您之前在基本神经网络中看到的,db是通过求和dZ来计算的。在本例中只需对conv输出(Z)的所有梯度求和。

    在代码中,在合适的for循环中,这个公式可以转化为:

    db[:,:,:,c] += dZ[i, h, w, c]

真实代码:

def conv_backward(dout, cache):
x, w, b = cache["a"], cache["w"], cache["b"]
pad, stride = cache["pad"], cache["stride"]
F, C, HH, WW = w.shape
N, C, H, W = x.shape
H_new = 1 + int((H + 2 * pad - HH) / stride)
W_new = 1 + int((W + 2 * pad - WW) / stride)

dx = np.zeros_like(x)
dw = np.zeros_like(w)
db = np.zeros_like(b)

s = stride
x_padded = np.pad(x, ((0, 0), (0, 0), (pad, pad), (pad, pad)), 'constant')
dx_padded = np.pad(dx, ((0, 0), (0, 0), (pad, pad), (pad, pad)), 'constant')

for i in range(N): # ith image
for f in range(F): # fth filter
for j in range(H_new):
for k in range(W_new):
window = x_padded[i, :, j * s:HH + j * s, k * s:WW + k * s]
# db = dout // dw=dout*x // dx = dout*w
db[f] += dout[i, f, j, k]
dw[f] += window * dout[i, f, j, k]
dx_padded[i, :, j * s:HH + j * s, k * s:WW + k * s]
+= w[f] * dout[i, f, j, k]

卷积神经网络cnn的实现的更多相关文章

  1. 卷积神经网络(CNN)前向传播算法

    在卷积神经网络(CNN)模型结构中,我们对CNN的模型结构做了总结,这里我们就在CNN的模型基础上,看看CNN的前向传播算法是什么样子的.重点会和传统的DNN比较讨论. 1. 回顾CNN的结构 在上一 ...

  2. 卷积神经网络(CNN)反向传播算法

    在卷积神经网络(CNN)前向传播算法中,我们对CNN的前向传播算法做了总结,基于CNN前向传播算法的基础,我们下面就对CNN的反向传播算法做一个总结.在阅读本文前,建议先研究DNN的反向传播算法:深度 ...

  3. 卷积神经网络CNN总结

    从神经网络到卷积神经网络(CNN)我们知道神经网络的结构是这样的: 那卷积神经网络跟它是什么关系呢?其实卷积神经网络依旧是层级网络,只是层的功能和形式做了变化,可以说是传统神经网络的一个改进.比如下图 ...

  4. 【深度学习系列】手写数字识别卷积神经--卷积神经网络CNN原理详解(一)

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  5. 深度学习之卷积神经网络(CNN)详解与代码实现(二)

    用Tensorflow实现卷积神经网络(CNN) 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10737065. ...

  6. 深度学习之卷积神经网络(CNN)详解与代码实现(一)

    卷积神经网络(CNN)详解与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10430073.html 目 ...

  7. 【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  8. 卷积神经网络(CNN)学习笔记1:基础入门

    卷积神经网络(CNN)学习笔记1:基础入门 Posted on 2016-03-01   |   In Machine Learning  |   9 Comments  |   14935  Vie ...

  9. 深度学习方法(五):卷积神经网络CNN经典模型整理Lenet,Alexnet,Googlenet,VGG,Deep Residual Learning

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 关于卷积神经网络CNN,网络和文献中 ...

  10. 深度学习之卷积神经网络CNN

    转自:https://blog.csdn.net/cxmscb/article/details/71023576 一.CNN的引入 在人工的全连接神经网络中,每相邻两层之间的每个神经元之间都是有边相连 ...

随机推荐

  1. py+selenium 老是定位不到文本内容【已解决】

    问题:定位不到文本内容,路径也正确,该加frame也有加,等待时间也够长 测试: 上图看不出差异,但是测试1就定位得到,测试2就定位不到,为什么? 看下图就知道了 区别就在于,测试2后面多了个空格!! ...

  2. [virtualenvwrapper] 命令小结

    创建环境 mkvirtualenv env1 mkvirtualenv env2 环境创建之后,会自动进入该目录,并激活该环境. 切换环境 workon env1 workon env2 列出已有环境 ...

  3. 关于Object.defineProperty 的基础知识

    Object.defineProperty 这个方法大家耳熟能详,可以对 对象的属性进行添加或修改的操作.即可以进行  数据劫持 .vue就是通过这个方法来劫持数据的. 平时我们创建对象的时候,一般通 ...

  4. WPF依赖属性的正确学习方法

    前言 我在学习WPF的早期,对依赖属性理解一直都非常的不到位,其恶果就是,我每次在写依赖属性的时候,需要翻过去的代码来复制黏贴. 相信很多朋友有着和我相同的经历,所以这篇文章希望能帮助到那些刚刚开始学 ...

  5. Golang高效实践之interface、reflection、json实践

    前言 反射是程序校验自己数据结构和类型的一种机制.文章尝试解释Golang的反射机制工作原理,每种编程语言的反射模型都是不同的,有很多语言甚至都不支持反射. Interface 在将反射之前需要先介绍 ...

  6. 第三章 JavaScript操作Dom对象

    常用的方法: 1.访问节点: 通过Document.getElementByXXX()获得一个指定节点-->再通过以下属性节点访问节点:第一部分:节点属性a:parentNode 返回节点的父节 ...

  7. IO流3

    public class Test1 { public static void main(String[] args) throws Exception { //第二个参数,表示是否向末尾追加,tru ...

  8. Reactv16.8.6生命周期函数

    组件生命周期函数 React 主动调用的方法,也可重写这些方法 生命周期图谱 当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下: constructor(props) 如果不需要初始化 s ...

  9. &= 的含义

    这是一个缩略式子,展开之后的结果是a = a & b;&是按位与的操作符. 按位与运算:参加运算的两个数据,按二进位进行“与”运算.如果两个相应的二进位都为1,则该位的结果值为1,否则 ...

  10. linux下pip的安装

    ---恢复内容开始--- 1 输入apt-cache search wxpython 如果有返回信息 则输入 sudo apt-get install python-tools 2 否则 1.添加软件 ...