TensorFlow中的两种conv2d方法和kernel_initializer

Easter79
• 阅读 773

####tf.nn.conv2d 在使用TF搭建CNN的过程中,卷积的操作如下

convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], padding="SAME") 

这个函数中各个参数的含义是什么呢?

  • X:输入数据的mini-batch,为一个4D tensor;分别表示的含义为[n_batch,height,width,channel]
  • filters:为卷积核,为一个4D tensor,分别表示的含义为 [filter_height, filter_width, in_channels, out_channels]
  • stride:为步长,使用方法为[1,stride,stride,1] 该方法先将filter展开为一个2D的矩阵,形状为[filter_height_filter_width_ in_channels, out_channels],再在图片上面选择一块大小进行卷积计算的到一个大小为[batch, out_height, out_width, filter_height * filter_width * in_channels]的虚拟张量。 再将上面两部相乘(右乘filter矩阵)
  • padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式。下面使用图表示两种的计算形式 TensorFlow中的两种conv2d方法和kernel_initializer

当使用VALID的时候,如果卷积计算过程中,剩下的不够一步,则剩下的像素会被抛弃,SAME则会补0.

filter_primes = np.array([2., 3., 5., 7., 11., 13.], dtype=np.float32)
x = tf.constant(np.arange(1, 13+1, dtype=np.float32).reshape([1, 1, 13, 1]))
filters = tf.constant(filter_primes.reshape(1, 6, 1, 1))

valid_conv = tf.nn.conv2d(x, filters, strides=[1, 1, 5, 1], padding='VALID')
same_conv = tf.nn.conv2d(x, filters, strides=[1, 1, 5, 1], padding='SAME')

with tf.Session() as sess:
    print("VALID:\n", valid_conv.eval())
    print("SAME:\n", same_conv.eval())

输出内容为

VALID:
 [[[[ 184.]
   [ 389.]]]]
SAME:
 [[[[ 143.]
   [ 348.]
   [ 204.]]]]

实际计算向量如下所示:

print("VALID:")
print(np.array([1,2,3,4,5,6]).T.dot(filter_primes))
print(np.array([6,7,8,9,10,11]).T.dot(filter_primes))
print("SAME:")
print(np.array([0,1,2,3,4,5]).T.dot(filter_primes))
print(np.array([5,6,7,8,9,10]).T.dot(filter_primes))
print(np.array([10,11,12,13,0,0]).T.dot(filter_primes))
>>

VALID:
184.0
389.0
SAME:
143.0
348.0
204.0

再来做一个小实验,使用VALID的时候:

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,1]))
op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='VALID')
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    print(op)
# print(sess.run(op))  
>>Tensor("Conv2D:0", shape=(1, 2, 2, 1), dtype=float32)

使用SAME的时候

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,1]))
op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')
init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    print(op)
# print(sess.run(op))  
>>Tensor("Conv2D:0", shape=(1, 3, 3, 1), dtype=float32)

**note:**在做卷积的过程中filter的shape为[hight,width,channel],也就是说如果为如果输入只有一个channel的时候,filter为一个矩阵,如果channel为3的时候,这个时候的filter就有了厚度为3。

####tf.layer.conv2d 同时TF也提供了tf.layer.conv2d的方法

def conv2d(inputs,
           filters,
           kernel_size,
           strides=(1, 1),
           padding='valid',
           data_format='channels_last',
           dilation_rate=(1, 1),
           activation=None,
           use_bias=True,
           kernel_initializer=None,
           bias_initializer=init_ops.zeros_initializer(),
           kernel_regularizer=None,
           bias_regularizer=None,
           activity_regularizer=None,
           trainable=True,
           name=None,
           reuse=None):

这个方法和tf.nn.conv2d有着相同的作用,相当于对其的更高层的api。两个方法的调用过程如下:

tf.layers.conv2d-> tf.nn.convolution . 
tf.layers.conv2d->Conv2D->Conv2D.apply()->_Conv->_Conv.apply()->_Layer.apply()->_Layer.\__call__()->_Conv.call()->nn.convolution()...

我用这两个方法搭建了相同的神经网络,可是得到的准确率相差很大,其他部分代码一张样。代码和准确率如下。为何差别这么的大?

    def conv2d(self,input,ksize,stride,name):
        with tf.name_scope(name):
            with tf.variable_scope(name):
                w = tf.get_variable("%s-w" %name,shape= ksize,initializer=tf.truncated_normal_initializer())
                b = tf.get_variable("%s-b" %name,shape = [ksize[-1]],initializer = tf.constant_initializer())
                out = tf.nn.conv2d(input,w,strides=[1,stride,stride,1],padding="SAME",name="%s-conv"%name)
                out = tf.nn.bias_add(out,b,name='%s-bias_add' %name)
                out = tf.nn.relu(out,name="%s-relu"%name)
        return out

TensorFlow中的两种conv2d方法和kernel_initializer

conv1 = tf.layers.conv2d(X,filters=conv1_fmaps, \
                         kernel_size = conv1_ksize,strides=conv1_stride,\
                         padding=conv1_pad,activation=tf.nn.relu,name='conv1')

TensorFlow中的两种conv2d方法和kernel_initializer

为何差异这么大呢?我现在还没弄查出结果,如果知道答案请指出,先谢过。

####tf.layers.conv2d中默认的kernel_initializer tf.layer.conv2d这里面默认的kernel_initializer为None,经查阅源码

    self.kernel = vs.get_variable('kernel',
                                  shape=kernel_shape,
                                  initializer=self.kernel_initializer,
                                  regularizer=self.kernel_regularizer,
                                  trainable=True,
                                  dtype=self.dtype)

这里面有一段说明

   If initializer is `None` (the default), the default initializer passed in
    the constructor is used. If that one is `None` too, we use a new
    `glorot_uniform_initializer`. If initializer is a Tensor, we use
    it as a value and derive the shape from the initializer.

也就是说使用的是 glorot_uniform_initializer来进行初始化的。这种方法又被称为Xavier uniform initializer,相关的文献在这里 。另外TF中tf.layers.dense也是使用的这个初始化方法。我把初始化方法都改成了使用tf.truncated_normal_initializer,上面模型的结果没有什么改善。看来初始化方法不是主要原因。求解。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k