【653】FCN——全卷积网络详解
[1] 语义分割--全卷积网络FCN详解【解释详细】
[4] keras.applications【VGG16】
[5] keras—VGG16
一、总体说明
FCN = CNN(VGG16) + UpSampling
-
FCN-32s: conv7 直接上采样 32 倍到原来的尺寸
-
FCN-16s:
-
conv7 上采样 2 倍 (/16)
-
pool4 (/16)
-
两者 add 之后,上采样 16 倍到原来的尺寸
-
-
FCN-8s:
-
conv7 上采样 2 倍 (/16)
-
pool4 (/16)
-
两者 add 之后,上采样 2 倍 (/8)
-
pool3 (/8)
- 上面两者 add 之后,上采样 8 倍到原来的尺寸
-
二、结构图示
图示如下所示:
第1阶段
以经典的分类网络为初始化。最后两级是全连接(红色),参数弃去不用。
第2阶段
从特征小图(16*16*4096)预测分割小图(16*16*21),之后直接升采样为大图。
反卷积(橙色)的步长为32,这个网络称为FCN-32s。
这一阶段使用单GPU训练约需3天。
升采样分为两次完成(橙色×2)。
在第二次升采样前,把第4个pooling层(绿色)的预测结果(蓝色)融合进来。使用跳级结构提升精确性。
第二次反卷积步长为16,这个网络称为FCN-16s。
这一阶段使用单GPU训练约需1天。
升采样分为三次完成(橙色×3)。
进一步融合了第3个pooling层的预测结果。
第三次反卷积步长为8,记为FCN-8s。
三、代码实现
FCN-32s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | from keras.applications import vgg16 from keras.models import Model, Sequential from keras.layers import Conv2D, Conv2DTranspose, Input , Cropping2D, add, Dropout, Reshape, Activation from keras.utils.vis_utils import plot_model def FCN32(nClasses, input_height, input_width): assert input_height % 32 = = 0 assert input_width % 32 = = 0 img_input = Input (shape = (input_height, input_width, 3 )) # VGG16 structrue # 2conv + 1pool -> block1_pool # 2conv + 1pool -> block2_pool # 3conv + 1pool -> block3_pool # 3conv + 1pool -> block4_pool # 3conv + 1pool -> block5_pool model = vgg16.VGG16(include_top = False , weights = 'imagenet' , input_tensor = img_input) assert isinstance (model, Model) o = Conv2D( 4096 , 7 , padding = "same" , activation = "relu" , name = "fc6" )(model.output) o = Dropout(rate = 0.5 )(o) o = Conv2D( 4096 , 1 , padding = "same" , activation = "relu" , name = "fc7" )(o) o = Dropout(rate = 0.5 )(o) o = Conv2D(nClasses, 1 , padding = "same" , activation = "relu" , kernel_initializer = "he_normal" , name = "score_fr" )(o) o = Conv2DTranspose(nClasses, 32 , strides = ( 32 , 32 ), padding = "valid" , activation = None , name = "score2" )(o) #o = Reshape((-1, nClasses))(o) o = Activation( "softmax" )(o) fcn8 = Model(inputs = img_input, outputs = o) # mymodel.summary() return fcn8 if __name__ = = '__main__' : m = FCN32( 2 , 512 , 512 ) m.summary() plot_model(m, show_shapes = True , to_file = 'model_fcn32.png' ) print ( len (m.layers)) |
FCN-16s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | from keras.applications import vgg16 from keras.models import Model, Sequential from keras.layers import Conv2D, Conv2DTranspose, Input , Cropping2D, add, Dropout, Reshape, Activation def FCN16_helper(nClasses, input_height, input_width): assert input_height % 32 = = 0 assert input_width % 32 = = 0 img_input = Input (shape = (input_height, input_width, 3 )) model = vgg16.VGG16(include_top = False ,weights = 'imagenet' , input_tensor = img_input) assert isinstance (model, Model) o = Conv2D( 4096 , 7 ,padding = "same" ,activation = "relu" ,name = "fc6" )(model.output) o = Dropout(rate = 0.5 )(o) o = Conv2D( 4096 , 1 ,padding = "same" ,activation = "relu" ,name = "fc7" )(o) o = Dropout(rate = 0.5 )(o) # /32 o = Conv2D(nClasses, 1 , padding = "same" , activation = "relu" , kernel_initializer = "he_normal" ,name = "score_fr" )(o) # 用于与 block4_pool合并 # /32 * 2 = /16 o = Conv2DTranspose(nClasses, 2 , strides = ( 2 , 2 ), padding = "valid" , activation = None , name = "score2" )(o) fcn16 = Model(inputs = img_input, outputs = o) return fcn16 def FCN16(nClasses, input_height, input_width): fcn16 = FCN16_helper(nClasses, input_height, input_width) # Conv to be applied on Pool4 # 这些 layer 的名字也可以通过后面的 summary 显示查看 # /16 skip_con1 = Conv2D(nClasses, 1 , padding = "same" , activation = None , kernel_initializer = "he_normal" , name = "score_pool4" )(fcn16.get_layer( "block4_pool" ).output) Summed = add(inputs = [skip_con1, fcn16.output]) # /16 * 16 = /1 Up = Conv2DTranspose(nClasses, 16 , strides = ( 16 , 16 ), padding = "valid" , activation = None ,name = "upsample" )(Summed) #Up = Reshape((-1, nClasses))(Up) Up = Activation( "softmax" )(Up) mymodel = Model(inputs = fcn16. input , outputs = Up) return mymodel if __name__ = = '__main__' : m16 = FCN16( 2 , 512 , 512 ) #plot_model(m, show_shapes=True, to_file='model_fcn8.png') m16.summary() print ( len (m.layers)) |
FCN-8s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | from keras.applications import vgg16 from keras.models import Model, Sequential from keras.layers import Conv2D, Conv2DTranspose, Input , Cropping2D, add, Dropout, Reshape, Activation def FCN8_helper(nClasses, input_height, input_width): assert input_height % 32 = = 0 assert input_width % 32 = = 0 img_input = Input (shape = (input_height, input_width, 3 )) model = vgg16.VGG16(include_top = False ,weights = 'imagenet' , input_tensor = img_input) assert isinstance (model, Model) o = Conv2D( 4096 , 7 ,padding = "same" ,activation = "relu" ,name = "fc6" )(model.output) o = Dropout(rate = 0.5 )(o) o = Conv2D( 4096 , 1 ,padding = "same" ,activation = "relu" ,name = "fc7" )(o) o = Dropout(rate = 0.5 )(o) # /32 o = Conv2D(nClasses, 1 , padding = "same" , activation = "relu" , kernel_initializer = "he_normal" ,name = "score_fr" )(o) # 用于与 block4_pool合并 # /32 * 2 = /16 o = Conv2DTranspose(nClasses, 2 , strides = ( 2 , 2 ), padding = "valid" , activation = None , name = "score2" )(o) fcn8 = Model(inputs = img_input, outputs = o) return fcn8 def FCN8(nClasses, input_height, input_width): fcn8 = FCN8_helper(nClasses, input_height, input_width) # Conv to be applied on Pool4 # 这些 layer 的名字也可以通过后面的 summary 显示查看 # /16 skip_con1 = Conv2D(nClasses, 1 , padding = "same" , activation = None , kernel_initializer = "he_normal" , name = "score_pool4" )(fcn8.get_layer( "block4_pool" ).output) Summed = add(inputs = [skip_con1, fcn8.output]) # /16 * 2 = /8 x = Conv2DTranspose(nClasses, 2 , strides = ( 2 , 2 ), padding = "valid" , activation = None ,name = "score4" )(Summed) ### # /8 skip_con2 = Conv2D(nClasses, 1 , padding = "same" , activation = None , kernel_initializer = "he_normal" , name = "score_pool3" )(fcn8.get_layer( "block3_pool" ).output) Summed2 = add(inputs = [skip_con2, x]) ##### # /8 * 8 = /1 Up = Conv2DTranspose(nClasses, 8 , strides = ( 8 , 8 ),padding = "valid" , activation = None , name = "upsample" )(Summed2) #Up = Reshape((-1, nClasses))(Up) Up = Activation( "softmax" )(Up) mymodel = Model(inputs = fcn8. input , outputs = Up) return mymodel if __name__ = = '__main__' : m = FCN8( 2 , 512 , 512 ) #plot_model(m, show_shapes=True, to_file='model_fcn8.png') m.summary() print ( len (m.layers)) |
四、模型网络图
FCN-32s
FCN-16s
FCN-8s
posted on 2021-09-03 15:44 McDelfino 阅读(1272) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)