fcn网络结构代码_经典网络复现系列(一):FCN

本文详细介绍了FCN(全卷积网络)的网络结构,包括其与VGG19的相似部分,以及FCN-32s、FCN-16s和FCN-8s的差异。重点讲解了反卷积的原理和在FCN-8s中的应用。此外,还分享了复现FCN-8s源码时的一些技巧,如参数设置、数据集处理、损失函数选择、优化器选取等,并提供了代码链接。
摘要由CSDN通过智能技术生成

1、FCN网络架构

FCN的前半段与VGG19架构相同,直接使用了VGG19预训练好的权重。

前半段的具体架构如下:

layers = (

'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1',

'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',

'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3',

'relu3_3', 'conv3_4', 'relu3_4', 'pool3',

'conv4_1', 'relu4_1', 'conv4_2', 'relu4_2', 'conv4_3',

'relu4_3', 'conv4_4', 'relu4_4', 'pool4',

'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2', 'conv5_3',

'relu5_3', 'conv5_4', 'relu5_4'

)

输入层(理论上对图像大小无限制,复现时resize统一到了224*224,且经过了批归一化的预处理) -------------共16个卷积层(卷积+偏置),对应16个relu层,5个pool层。 其中卷积层卷积步长为1,padding=‘SAME’。所以经过卷积层后图像的大小不变。pool层采用平均池化,核大小为2*2,步长[1,2,2,1],padding='SAME',因此每经过一个pool层,图像的长和款就变为原本的二分之一。经过5个池化层后,map变为原来的1/32。

架构中段:

conv6 (卷积核[7,7,512,4096])+relu----drop_out层----conv7 (卷积核[1,1,4096,4096])+relu----dropout

卷积层卷积步长为1,padding=‘SAME’ 权重使用截断正态分布初始化。就是说产生正太分布的值如果与均值的差值大于两倍的标准差,那就重新生成。

架构后半段:

根据搭建方式的不同,FCN分为3种:FCN-32s,FCN-16s,FCN-8s

经过前、中段以后,conv8输出的map变为原来的1/32,后续不特指的话,缩小都是指长和宽。要实现端到端的像素分类,需要对其做反卷积,将map变为原本的大小。关于反卷积的原理,下文有讲述。所使用的函数是tf.nn.conv2d_transpose() 长宽扩大多少倍由参数stride决定。与stride=2 可以理解为将map反卷积成为原本的两倍。需要注意的是,与conv时的kernel [size,size,in,out]不同,tf.nn.conv2d_transpose()使用的kernel是[size,size,out,in]

FCN-8s: ((conv7*2+pool4)*2+pool3)*8    2*2*8=2^5 恢复到了原本的大小

FCN-16s:(conv7*2+pool4)*16

FCN-32s: conv7*32

我复现了FCN-8s的源码,这种skip layer可以将浅层的和深层的特征组合在一起。

三个反卷积核的大小依次是:[4,4,pool4.shape[-1].value,4096],[4,4,pool3.shape[-1].value,pool4.shape[-1].value],[16,16,NUM_OF_CLASSESS,pool3.shape[3].value]

stride依次是2,2,8。

最后一个反卷积层的输出是[batchsize,224,224,NUM_CLASSES]  通过softmax(在损失函数优化器中自带)计算出像素点属于各类别的置信度,选择置信度最高的作为预测值,得到pre

由pre和gt计算损失函数。

2、复现过程中的小trick

1)命令行参数

FCN.py

FLAGS=tf.flags.FLAGS

tf.flags.DEFINE_integer('batchsize','8','trainning batchsize') #参数 默认值 说明

tf.flags.DEFINE_float('learning_rate','1e-4','learning_rate')

tf.flags.DEFINE_bool('train', "True", "Debug mode: True/ False")

python FCN.py会直接使用默认的参数

python FCN.py --batchsize 32  --learning_rate 0.05  --train False   参数可以根据需求进行修改

后续代码调用参数的话:

FLAGS.batchsize

FLAGS.learning_rate

FLAGS.train

2)np.squeeze()

去除array中为1的维度

3)tf.variable_scope和tf.name_scope的区别:

tf.variable_scope可以让变量有相同的命名,包括tf.get_variable得到的变量,还有tf.Variable的变量

tf.name_scope可以让变量有相同的命名,只是限于tf.Variable的变量

所以如果

with tf.namescope('V1'):

with tf.namescope('V2'):

中都使用tf.get_variable得到了name为 'kernel' 的variable 会报错

但如果都使用tf.Variable得到了name为 'kernel' 的variable 不会报错

4)tf.variable与tf.get_variable

tf.Variable() 每次都在创建新对象,所有reuse=True 和它并没有什么关系。对于get_variable(),来说,如果已经创建的变量对象,就把那个对象返回,如果没有创建变量对象的话,就创建一个新的。

具体参数说明参考:https://blog.csdn.net/u012436149/article/details/53696970

5)tf.nn.conv2d_transpose

反卷积

tf.nn.conv2d_transpose(input_tensor,kernel,out_shape,[1,strider,strider,1],padding='SAME')

长宽扩大多少倍由参数stride决定。与stride=2 可以理解为将map反卷积成为原本的两倍。需要注意的是,与conv时的kernel [size,size,in,out]不同,tf.nn.conv2d_transpose()使用的kernel是[size,size,out,in]

需要指定output_shape

反卷积原理可见:https://blog.csdn.net/mao_xiao_feng/article/details/71713358

6)tfrecord数据集的制作和读取

参考另一篇博客 tensorflow高效读取数据(tfrecord)

7) label_batch=tf.expand_dims(label_batch,-1)

增加维度,增加的是哪一维,可以通过dims= 制定

8)损失函数的选择:

参考另一篇博客:关于tensorflow交叉熵损失函数的一些理解

9)优化器的选择:

参考博客:https://blog.csdn.net/aliceyangxi1987/article/details/73210204

10)权重的保存和恢复

with tf.Session() as sess:

saver=tf.train.Saver(max_to_keep=5)# 只保存最近的5个

if FLAGS.train==True:

sess.run(init) #如果是训练的话 初始化 不载入

else:

ckpt = tf.train.get_checkpoint_state('log')

saver.restore(sess,ckpt.model_checkpoint_path) #恢复最新的权重到sess中

saver.save(sess,'log/model.ckpt',step) #保存第step步的权重

11)训练一段时间后报错:

OutOfRangeError (see above for traceback): RandomShuffleQueue '_2_shuffle_batch/random_shuffle_queue' is closed and has insufficient elements (requested 8, current size 0)

[[Node: shuffle_batch = QueueDequeueManyV2[component_types=[DT_UINT8, DT_UINT8], timeout_ms=-1, _device="/job:localhost/replica:0/task:0/device:CPU:0"](shuffle_batch/random_shuffle_queue, shuffle_batch/n)]]

可能原因:tfrecord存储和读取时候的数据类型不一致。

1、数据编码前是float  解码时指定为uint8。

2、编码方式与解码方式不配对。

3、数据集有图片是损坏的。

检查后发现是第三个原因。

12)ubuntu下移动数据集,当数据集比较大,尽量使用终端命令,会比较快。

mv ./training/ADE_train_000202*.png ./train_back/

13)tensorflow的可视化

tf.summary.histogram  直方图

tf.summary.scalar     变量

最后

merged =tf.summary.merge_all() 将所有需要可视化的合并

定义writer

train_writer = tf.summary.FileWriter(FLAGS.log + '/train')

训练时每隔几步并写入一次

summary=sess.run(merged)

train_writer.add_summary(summary,step)

训练结束后查看:

在终端输入 tensorboard --logdir=dir

其中dir是summary日志存储的目录。

13)采用

if __name__=='__main__':

tf.app.run()

时 也就是python文件有预设参数时,调用main函数的定义:

def main(argv=None):

14)对于大数据集 制作numpy非常麻烦,因此数据格式为tfrecord会比较好,但是数据集比较小的话,制作成numpy会比较快。

15)

print('\r%d',step,end='') #'\r'使得下一次的输出把上一次的覆盖掉。end=''确保不换行。

sys.stdout.flush() #刷新

这两行代码是一个 在原位置不断刷新输出的简单例子

16)logging日志

使用方法参考

https://blog.csdn.net/hallo_ween/article/details/64906838

17)滑动平均的使用

以损失函数为例,滑动平均可以防止损失随着epoch的变化不太剧烈,而是相对平稳的下降,如果loss没有急剧的上涨,可以不考虑使用滑动平均,如果不稳定的话,可以使用。

使用方法:

v1 = tf.Variable(0, dtype=tf.float32)

step = tf.Variable(tf.constant(0))

ema = tf.train.ExponentialMovingAverage(0.99, step)

maintain_average = ema.apply([v1])

with tf.Session() as sess:

init = tf.initialize_all_variables()

sess.run(init)

print sess.run([v1, ema.average(v1)]) #初始的值都为0

sess.run(tf.assign(v1, 5)) #把v1变为5

sess.run(maintain_average)

print sess.run([v1, ema.average(v1)]) # decay=min(0.99, 1/10)=0.1, v1=0.1*0+0.9*5=4.5

sess.run(tf.assign(step, 10000)) # steps=10000

sess.run(tf.assign(v1, 10)) # v1=10

sess.run(maintain_average)

print sess.run([v1, ema.average(v1)]) # decay=min(0.99,(1+10000)/(10+10000))=0.99, v1=0.99*4.5+0.01*10=4.555

18)assert 断言的用法

格式 : assert+空格+要判断语句+双引号“报错语句”

例子:

出错时候

assert 1>5, "chucuo"

输出值为:

---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

in ()

----> 1 assert 2>5, "chucuo"

AssertionError: chucuo

19)tf.identity()和tf.group()均可将语句变为操作

3、相关代码

1)代码架构:

准备数据(读入事先制作好的tfrecord)-------定义网络结构-------可视化------计算损失---定义优化器----初始化-----开启Session----训练(每训练20个batch进行一次验证)------测试

2)代码地址:

https://github.com/zlrai5895/FCN-writed

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值