当前位置: 首页 > 编程日记 > 正文

『TensorFlow』卷积层、池化层详解

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

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

二、测试代码

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

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

相关文章:

个人计算机用户隐私保护全接触(2)

在第一部分中,我们已经详细讨论了有关如何加固系统和应用数据加密来保护用户隐私的方式,现在,就跟雪源梅香一起了解其它保护用户隐私的方法。1、清除计算机当中的用户操作痕迹我们应当在使用完计算机后,对操作所产的痕迹进行全面清…

java日期相关的类正则表达式

常用的API Date、Math、DateFormat、Calendar、正则表达式 Data类 public class DateDeom {public static void main(String[] args) {//创建日期类的对象Date datenew Date();// 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。long timedate.getTim…

M_Map画南海水深地形图

数据来自Etopo1全球地形和水深数据。 其分为两个版本,Ice Surface和Bedrock,两个版本基本一致。不同之处在于在处理南极洲和Greenland地形时,前者给出的是加上冰盖层之后的高程,后者给出的是岩床的高程。 在每个子版本下又有多种数…

blackberry Jvm error 104 错误(Device Simulator)

把模拟器目录下的这个文件 **-fs.dmp 删掉或者搬个家就成啦,然后重启模拟器 每次启动它都会生成这个文件,具体原因还待研究 8300 GSM GPRS EDGE8310 8300 GPS8320 8300 Wi-Fi8330 8310 CDMA Ev-DO Video Recording (!)转载于:https://www.c…

关于Map的key值的问题

HashMap<StringBuffer,String> strmap new HashMap<>();StringBuffer snew StringBuffer("1");strmap.put(s,"1");s.append("2");System.out.println(strmap.get("1")); null 与之前研究的value值的问题一样&#xff0c;…

田志刚:要你共享,但不告诉你共享什么

案例所述的问题很典型&#xff0c;是国内各类机构做知识管理的一个典型&#xff1a;我需要你共享&#xff0c;但不告诉你共享什么。问题是&#xff0c;我也不知道你该共享什么。这样的结果就是共享出来的东西都没用也都有用&#xff0c;因为你根本没有标准&#xff0c;所以我说…

Oracle Data Guard 理论知识

RAC&#xff0c; Data Gurad&#xff0c; Stream 是Oracle 高可用性体系中的三种工具&#xff0c;每个工具即可以独立应用&#xff0c;也可以相互配合。 他们各自的侧重点不同&#xff0c;适用场景也不同。 RAC 它的强项在于解决单点故障和负载均衡&#xff0c;因此RAC 方案常用…

JavaScript脚本文件学习总结

javaScript 学习总结 什么是JavaScript和javaScript的特点 是一种解释型脚本语言&#xff08;代码不进行预编译&#xff09;&#xff0c;不需要进行编译&#xff0c;直接嵌套在HTML页面&#xff0c;将静态的页面转变成支持用户交互的动态页面。 文件类型是.js 特点 解释性&…

Git note

feat&#xff1a;新功能&#xff08;feature&#xff09; fix&#xff1a;修补bug docs&#xff1a;文档&#xff08;documentation&#xff09; style&#xff1a; 格式&#xff08;不影响代码运行的变动&#xff09;注意不是 css 修改 refactor&#xff1a;重构&#xff08;即…

说客是一种俗文化

说客是一种俗文化阿祥中国移动旗下的139.com社区改版&#xff0c;没有张扬&#xff0c;也没有滥发广告&#xff0c;还是引起了业内人士的广泛减少。为什么&#xff1f;以笔者之见&#xff0c;这个改版后的社区打出“说客”这张牌&#xff0c;是互联网文化的一个全新的创意&…

leetcode 203 Remove Linked List Elements

&#xfeff;&#xfeff;Remove all elements from a linked list of integers that have valueval. ExampleGiven: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val 6Return: 1 --> 2 --> 3 --> 4 --> 5 我的解法&#xff1a; // Linklist.cpp …

eclipse实用快捷键

eclipse的快捷键非常的多&#xff0c;全部记录一遍也不利于查看&#xff0c;记录一些比较实用的更加方便。 ctrl / 注释单行/取消注释 ctrl Z 回退一步 ctrl Y &#xff08;回退后&#xff09;前一步 ctrl S 保存 ctrl D 删除行 alt / 补全提示 ctrl …

集合 泛型 迭代器

什么是集合 集合与数组的区别 数组的长度是固定的&#xff0c;集合的长度是可变的数组中可以存储任何类型的元素&#xff08;基本类型和引用类型&#xff09;&#xff0c;集合只能存储引用类型的。 集合 在java中提供了很多的集合&#xff0c;因为用户要求存储不同接口的数据…

《监控》再起风云,连同创作中的《监控2》成功牵手影视公司

“监控”&#xff0c;辞海上的解释为&#xff1a;监测并进行控制。 “监控”&#xff0c;百度百科解释为&#xff1a;监控&#xff0c;职场谍战小说。 从2个月内超过230万人阅读的天涯热帖&#xff0c;到上市两月即获重印的畅销图书&#xff0c;神秘作者搏击带着他的《监控》在…

跟我学交换机配置(四)

以下内容摘自笔者最新图书《Cisco/H3C交换机配置与管理完全手册》。本书在51CTO上的样章试读地址为&#xff1a;http://book.51cto.com/art/200908/142118.htm 8.5.4 创建PVLAN 在IOS和CatOS系统交换机中都可以配置PVLAN&#xff0c;所以下面也分别予以介绍。 1. IOS系统交换机…

使用nc传输文件和目录【转】

方法1&#xff0c;传输文件演示&#xff08;先启动接收命令&#xff09; 使用nc传输文件还是比较方便的&#xff0c;因为不用scp和rsync那种输入密码的操作了把A机器上的一个rpm文件发送到B机器上需注意操作次序&#xff0c;receiver先侦听端口&#xff0c;sender向receiver所在…

假如有Thread1、Thread2、ThreaD3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?...

有两种方法&#xff1a; 第一种方法&#xff1a; 一般情况&#xff0c;我们实现多线程都是Thread或者Runnable(后者比较多)&#xff0c;但是&#xff0c;这两种都是没返回值的&#xff0c;所以我们需要使用callable(有返回值的多线程)和future(获得线程的返回值)来实现了。 /**…

ORA-00907:缺少右括号

在创建以下表的时候出现ORA-00907&#xff1a;缺少右括号的错误&#xff0c;最后发现是字符串类型写错了&#xff0c;VARCHAR2写成了VARCAHR2&#xff0c; /**//* DBMS name: ORACLE Version 9i2 *//* Created on: 2010-4-23 12:28:27 …

Java Web项目第二次总结

学生管理系统 问题 jQuery 不熟悉El需要复习servlet的内置对象 新认识的知识 利用servlet的 Session对象实现权限的验证。它的作用是:只能通过登录后才能进入主界面&#xff0c;否则不能进入。没有加权限验证前是可以根据页面的完整路径进入主界面&#xff0c;可以不输入密…

软件项目中的需求分析具体方法探讨之一

这家单位&#xff0c;我进去没多久&#xff0c;满打满算也就刚两月多一周而已。我也不是开发部的人&#xff0c;但是&#xff0c;看到了一些事情&#xff0c;纯为有感而发。领导想做个CRM&#xff0c;于是&#xff0c;开发部的人写了&#xff0c;当然&#xff0c;正式的需求分析…

portscaner 多线程、多协程并发端口扫描

import socket,time,re,sys,os,threading import gevent from gevent import monkey monkey.patch_all()socket.setdefaulttimeout(2)#该方法用来处理用户数据的port范围&#xff0c;并计算范围内的port&#xff0c;将其添加到列表中&#xff0c;将列表返回 def handle_port(in…

POJ 2828 Buy Tickets | 线段树的喵用

题意: 给你n次插队操作,每次两个数,pos,w,意为在pos后插入一个权值为w的数; 最后输出1~n的权值 题解: 首先可以发现,最后一次插入的位置是准确的位置 所以这个就变成了若干个子问题, 所以用线段树维护一下每个区间剩余多少位置可选 对于一个pos 如果左儿子的剩余超过当前位置,就…

Ext结合DWR的关键代码(运行成功的DWRProxy)

关键代码如下&#xff1a;Store为&#xff1a;var ds new Ext.data.Store({ proxy: new Ext.data.DWRProxy({ callback: Folder.getMessageList, params: { start: 0, limit: PAGE_SIZE } }), // proxy: new…

serlvet 九大内置对象

隐式对象 说明 request 转译后对应HttpServletRequest/ServletRequest对象 response 转译后对应HttpServletRespons/ServletResponse对象 session 转译后对应HttpSession对象 application 转译后对应ServletContext对象 out 转译后对应JspWriter对象&#xff0c;其…

网路游侠:某软件版WEB应用防火墙试用

去年的这个时候&#xff0c;游侠(www.youxia.org)认为WAF都是硬件的&#xff0c;后来在网上看到这个在国内做的不错的牌子。居然是软件的WAF&#xff0c;这样的话&#xff0c;一些服务器在机房托管的用户就特别需要这样的产品&#xff0c;因为1U的设备在电信机房的托管费用都有…

P2172 [国家集训队]部落战争 二分图最小不相交路径覆盖

二分图最小不相交路径覆盖 #include<bits/stdc.h> using namespace std; const int MAXN 5550; const int MAXM 1000005; const int INF 1000000050; int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], f[MAXM << 1], ed 1, …

IO流 字符流 字节流 缓冲流 文件的复制

IO流 IO概述 IO流就是一个管道&#xff0c;是用来在设备之间传输数据 input&#xff1a;相对于内存/程序 往进走输入流 output&#xff1a;相对于内存/程序 往硬盘写入 分类 根据数据进出方式 1、输出流&#xff1a; FileWriter 字符输出流BufferedWriter 字符缓冲输出…

强烈推荐:240多个jQuery插件

http://www.cnblogs.com/Terrylee/archive/2007/12/09/the-ultimate-jquery-plugin-list.html转载于:https://www.cnblogs.com/HughTan/archive/2010/05/14/1735376.html

FreeBSD Ports加速的方法

使用代理。 在/etc/make.conf中设置&#xff1a;FETCH_ENV "HTTP_PROXYIP[:端口]"如果需要&#xff0c;在FETCH_ENV值后面加入空格&#xff0c;HTTP_PROXY_AUTHbasic:*:user:password利用其他机器下载的文件... 首先&#xff0c;请确保2台机器cvsup的一致&#xff0…

AngularJS ng-if使用

示例中&#xff0c;根据ng-if指令显示不同任务状态&#xff0c;以及判断任务是否可以操作 <div ng-app"NgifDemoApp" ng-controller"NgifDemoContrl as vm"><h1>任务列表</h1><table class"table"><thead><tr&…