一、前向计算和反向传播数学过程讲解

这里讲解的是平均池化层,最大池化层见本文第三小节

二、测试代码

数据和上面完全一致,自行打印验证即可。

1、前向传播

import tensorflow as tf
import numpy as np# 输入张量为3×3的二维矩阵
M = np.array([[[1], [-1], [0]],[[-1], [2], [1]],[[0], [2], [-2]]
])
# 定义卷积核权重和偏置项。由权重可知我们只定义了一个2×2×1的卷积核
filter_weight = tf.get_variable('weights', [2, 2, 1, 1], initializer=tf.constant_initializer([[1, -1],[0, 2]]))
biases = tf.get_variable('biases', [1], initializer=tf.constant_initializer(1))# 调整输入格式符合TensorFlow要求
M = np.asarray(M, dtype='float32')
M = M.reshape(1, 3, 3, 1)# 计算输入张量通过卷积核和池化滤波器计算后的结果
x = tf.placeholder('float32', [1, None, None, 1])# 我们使用了带Padding,步幅为2的卷积操作,因为filter_weight的深度确定了卷积核的数量
conv = tf.nn.conv2d(x, filter_weight, strides=[1, 2, 2, 1], padding='SAME')
bias = tf.nn.bias_add(conv, biases)# 使用带Padding,步幅为2的平均池化操作
pool = tf.nn.avg_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')# 执行计算图
with tf.Session() as sess:tf.global_variables_initializer().run()convoluted_M = sess.run(bias, feed_dict={x: M})pooled_M = sess.run(pool, feed_dict={x: M})print("convoluted_M: \n", convoluted_M)print("pooled_M: \n", pooled_M)

2、反向传播

import tensorflow as tf
import numpy as np# 输入张量为3×3的二维矩阵
M = np.array([[[1], [-1], [0]],[[-1], [2], [1]],[[0], [2], [-2]]
])
# 定义卷积核权重和偏置项。由权重可知我们只定义了一个2×2×1的卷积核
filter_weight = tf.get_variable('weights', [2, 2, 1, 1], initializer=tf.constant_initializer([[1, -1],[0, 2]]))
biases = tf.get_variable('biases', [1], initializer=tf.constant_initializer(1))# 调整输入格式符合TensorFlow要求
M = np.asarray(M, dtype='float32')
M = M.reshape(1, 3, 3, 1)# 计算输入张量通过卷积核和池化滤波器计算后的结果
x = tf.placeholder('float32', [1, None, None, 1])# 我们使用了带Padding,步幅为2的卷积操作,因为filter_weight的深度确定了卷积核的数量
conv = tf.nn.conv2d(x, filter_weight, strides=[1, 2, 2, 1], padding='SAME')
bias = tf.nn.bias_add(conv, biases)d_filter = tf.gradients(bias,filter_weight)
d_biases = tf.gradients(bias,biases)
d_conv = tf.gradients(bias,conv)
d_conv_x = tf.gradients(conv,x)
d_conv_w = tf.gradients(conv,filter_weight)
# d_bias_x = tf.gradients(bias,x)# 使用带Padding,步幅为2的平均池化操作
pool = tf.nn.avg_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')d_pool = tf.gradients(pool,x)# 执行计算图
with tf.Session() as sess:tf.global_variables_initializer().run()# convoluted_M = sess.run(bias, feed_dict={x: M})# pooled_M = sess.run(pool, feed_dict={x: M})## print("convoluted_M: \n", convoluted_M)# print("pooled_M: \n", pooled_M)print("d_filter:\n", sess.run(d_filter, feed_dict={x: M}))print("d_biases:\n", sess.run(d_biases, feed_dict={x: M}))print("d_conv:\n", sess.run(d_conv, feed_dict={x: M}))print("d_conv_x:\n", sess.run(d_conv_x, feed_dict={x: M}))print("d_conv_w:\n", sess.run(d_conv_w, feed_dict={x: M}))

四、CS31n上实现的卷积层池化层API

1、卷积层

卷积层向前传播示意图:

def conv_forward_naive(x, w, b, conv_param):"""A naive implementation of the forward pass for a convolutional layer.The input consists of N data points, each with C channels, height H and widthW. We convolve each input with F different filters, where each filter spansall C channels and has height HH and width HH.Input:- x: Input data of shape (N, C, H, W)- w: Filter weights of shape (F, C, HH, WW)- b: Biases, of shape (F,)- conv_param: A dictionary with the following keys:- 'stride': The number of pixels between adjacent receptive fields in thehorizontal and vertical directions.- 'pad': The number of pixels that will be used to zero-pad the input.Returns a tuple of:- out: Output data, of shape (N, F, H', W') where H' and W' are given byH' = 1 + (H + 2 * pad - HH) / strideW' = 1 + (W + 2 * pad - WW) / stride- cache: (x, w, b, conv_param)"""out = None############################################################################## TODO: Implement the convolutional forward pass.                           ## Hint: you can use the function np.pad for padding.                        #############################################################################pad = conv_param['pad']  stride = conv_param['stride']N, C, H, W = x.shapeF, _, HH, WW = w.shapeH0 = 1 + (H + 2 * pad - HH) / strideW0 = 1 + (W + 2 * pad - WW) / stridex_pad = np.pad(x, ((0,0),(0,0),(pad,pad),(pad,pad)),'constant')    # 填充后的输入out = np.zeros((N,F,H0,W0))                                        # 初始化的输出# 以输出的每一个像素点为单位写出其前传表达式for n in range(N):for f in range(F):for h0 in range(H0):for w0 in range(W0):out[n,f,h0,w0] = np.sum(x_pad[n,:,h0*stride:HH+h0*stride,w0*stride:WW+w0*stride] * w[f]) + b[f]##############################################################################                             END OF YOUR CODE                              ##############################################################################cache = (x, w, b, conv_param)return out, cache

卷积层反向传播示意图:

def conv_backward_naive(dout, cache):"""A naive implementation of the backward pass for a convolutional layer.Inputs:- dout: Upstream derivatives.- cache: A tuple of (x, w, b, conv_param) as in conv_forward_naiveReturns a tuple of:- dx: Gradient with respect to x- dw: Gradient with respect to w- db: Gradient with respect to b"""dx, dw, db = None, None, None############################################################################## TODO: Implement the convolutional backward pass.                          ##############################################################################x, w, b, conv_param = cachepad = conv_param['pad']  stride = conv_param['stride']N, C, H, W = x.shapeF, _, HH, WW = w.shape_, _, H0, W0 = out.shapex_pad = np.pad(x, [(0,0), (0,0), (pad,pad), (pad,pad)], 'constant')dx, dw = np.zeros_like(x), np.zeros_like(w)dx_pad = np.pad(dx, [(0,0), (0,0), (pad,pad), (pad,pad)], 'constant')   # 计算b的梯度(F,)db = np.sum(dout, axis=(0,2,3))    # dout:(N,F,H0,W0)# 以每一个dout点为基准计算其两个输入矩阵x(:,:,窗,窗)和w(f)的梯度,注意由于这两个矩阵都是多次参与运算,所以都是累加的关系for n in range(N):for f in range(F):for h0 in range(H0):for w0 in range(W0):x_win = x_pad[n,:,h0*stride:h0*stride+HH,w0*stride:w0*stride+WW]dw[f] += x_win * dout[n,f,h0,w0]dx_pad[n,:,h0*stride:h0*stride+HH,w0*stride:w0*stride+WW] += w[f] * dout[n,f,h0,w0]dx = dx_pad[:,:,pad:pad+H,pad:pad+W]##############################################################################                             END OF YOUR CODE                              ##############################################################################return dx, dw, db

2、最大池化层

池化层向前传播:

和卷积层类似,但是更简单一点,只要在对应feature map的原输入上取个窗口然后池化之即可,

def max_pool_forward_naive(x, pool_param):HH, WW = pool_param['pool_height'], pool_param['pool_width']s = pool_param['stride']N, C, H, W = x.shapeH_new = 1 + (H - HH) / sW_new = 1 + (W - WW) / sout = np.zeros((N, C, H_new, W_new))for i in xrange(N):    for j in xrange(C):        for k in xrange(H_new):            for l in xrange(W_new):                window = x[i, j, k*s:HH+k*s, l*s:WW+l*s] out[i, j, k, l] = np.max(window)cache = (x, pool_param)return out, cache

池化层反向传播:

反向传播的时候也是还原窗口,除最大值处继承上层梯度外(也就是说本层梯度为零),其他位置置零。

池化层没有过滤器,只有dx梯度,且x的窗口不像卷积层会重叠,所以不用累加,

def max_pool_backward_naive(dout, cache):x, pool_param = cacheHH, WW = pool_param['pool_height'], pool_param['pool_width']s = pool_param['stride']N, C, H, W = x.shapeH_new = 1 + (H - HH) / sW_new = 1 + (W - WW) / sdx = np.zeros_like(x)for i in xrange(N):    for j in xrange(C):        for k in xrange(H_new):            for l in xrange(W_new):                window = x[i, j, k*s:HH+k*s, l*s:WW+l*s]                m = np.max(window)               dx[i, j, k*s:HH+k*s, l*s:WW+l*s] = (window == m) * dout[i, j, k, l]return dx

五、实际框架实现方法

实际框架当然不会才用这种大循环的手段实现卷积操作,矩阵化运算才是正路。

1、Theano

常见的一种拆法是将二维 input 展开成一维向量([in_h * in_w] -> [out_h * out_w]),将卷积核展开为([in_h * in_w, out_h * out_w]),

上面仅讨论了2维输入,其实由于 input 的 channels 和 kernal 的 channels 数一致,所以情况延申起来原理并无改变。最后的运算如下:

y = C·xT

2、Caffe

caffe的卷积矩阵化如下,其直接把 input 的各个通道的值放在了一个矩阵种,将各个 kernals 的各个通道值放入同一个矩阵,一次解决所有运算,感觉比上面的做法高明了一点(不过都是很厉害的算法)。

转载于:https://www.cnblogs.com/hellcat/p/7850048.html

『TensorFlow』卷积层、池化层详解相关推荐

  1. 【深度学习入门到精通系列】卷积和池化计算详解

    文章目录 1 卷积 2 填充 3 池化 4 注意 1 卷积 卷积层由一组滤波器组成,滤波器可以视为二维数字矩阵.这是一个示例3x3滤波器: 在图像的某个位置上覆盖滤波器:将滤波器中的值与图像中的对应像 ...

  2. 深度学习笔记(一):卷积层+池化层+激活函数+全连接层

    写在前面:大家好!我是[AI 菌],一枚爱弹吉他的程序员.我热爱AI.热爱分享.热爱开源! 这博客是我对学习的一点总结与记录.如果您也对 深度学习.机器视觉.算法.Python.C++ 感兴趣,可以关 ...

  3. 卷积神经网络——池化层学习——最大池化

    池化层(Pooling layers) 除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性,我们来看一下. 先举一个池化层的例子,然后我们再讨论池化层的必要 ...

  4. keras中的卷积层池化层

    文章目录 卷积层 创建卷积层 卷积层的格式及参数: 卷积层中的参数数量 卷积层的形状 池化层 keras中的最大池化层 参数 卷积层 创建卷积层 首先导入keras中的模块 from keras.la ...

  5. cs231n-(7)卷积神经网络:架构,卷积层/池化层

    架构总览 常用的层 卷积层 概述 池化层 归一化层 全连接层 全连接层转为卷积层 卷积网络架构 层模式 层大小设计模式 实例 计算资源考虑 额外资源 卷积神经网络和普通神经网络非常类似.卷积神经网络由 ...

  6. CNN模型中 卷积层 RELU层 池化层 作用及顺序

    卷积层  Convolutional layer 卷积运算的目的是提取输入的不同特征 类似于CV中的滤波,通过滑动窗口来得到特征图像 非线性激活层  Relu f(x)=max(0,x) 非线性激活层 ...

  7. TensorFlow实现卷积、池化操作

    1.调用tf.nn.conv2d()实现卷积 首先是调用卷积函数实现卷积操作: 这里说明一下conv2d的定义及参数含义: 参考 [定义:] tf.nn.conv2d (input, filter, ...

  8. 卷积神经网络 池化层上采样(upsampling、interpolating)、下采样(subsampled、downsampled)是什么?(上采样为放大图像或图像插值、下采样为缩小图像)

    缩小图像:或称为下采样(subsampled)或降采样(downsampled) 主要目的有两个:1.使得图像符合显示区域的大小:2.生成对应图像的缩略图. 放大图像:或称为上采样(upsamplin ...

  9. 『Linux』第九讲:Linux多线程详解(三)_ 线程互斥 | 线程同步

    「前言」文章是关于Linux多线程方面的知识,上一篇是 Linux多线程详解(二),今天这篇是 Linux多线程详解(三),内容大致是线程互斥与线程同步,讲解下面开始! 「归属专栏」Linux系统编程 ...

最新文章

  1. 安装lua及问题解决
  2. 又是一卦测感情,这卦很是霸气
  3. 《Fabric 云存储的电子健康病历系统》(2)病历结构体 Records
  4. 【竞赛相关】Kaggle知识点:入门到进阶的10个问题
  5. IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm
  6. fifa15服务器位置,《FIFA 15》全系统教程图文攻略
  7. 《设计模式其实很简单》
  8. ioc控制反转_深入理解依赖注入(DI)和控制反转(IOC)
  9. [webpack]手写一个mvp版本的webpack
  10. 以太坊系列之十四: solidity特殊函数
  11. 坦克大战游戏java代码_Java实现坦克大战游戏的源码示例
  12. 六款Linux常用远程连接工具介绍,看看哪一款最适合你
  13. 详解正向代理与反向代理
  14. 适合计算机中职生见到打拼音的软件,中职计算机基础教案设计(18页)-原创力文档...
  15. 合肥有哪些不错的 IT 公司?
  16. mysql error 1236_MySQL Got fatal error 1236原因和解决方法
  17. matlab示波器多个接口,simulink在一个图形中画出多个示波器曲线的方法
  18. linux安装android x86_64,在VirtualBox上安装Android-X86
  19. UE4-(光照)光照贴图
  20. 华为GAUSS数据库常用的单行操作函数介绍

热门文章

  1. linux 端口 流量统计,Linux下如何对端口流量进行统计
  2. 宝塔面板 mysql装不上_宝塔面板强制安装mysql8.0
  3. php文件夹列表,php获取文件夹下面的文件列表和文件夹列表
  4. 1069 The Black Hole of Numbers
  5. (C++)自定义链表并写入
  6. UI设计培训之UI设计系统知识
  7. 《从零开始学Swift》学习笔记(Day 47)——final关键字
  8. 2.最详细的WSDD配置文件注释
  9. 初级Java程序员所面临的4大挑战
  10. Spring中使用Schedule调度