Keras-FCN 源码精读:全连接层如何转换为卷积层实现像素级分类

发布时间:2026/8/20 17:06:33
Keras-FCN 源码精读:全连接层如何转换为卷积层实现像素级分类 Keras-FCN 源码精读全连接层如何转换为卷积层实现像素级分类【免费下载链接】Keras-FCNKeras-tensorflow implementation of Fully Convolutional Networks for Semantic SegmentationUnfinished项目地址: https://gitcode.com/gh_mirrors/ker/Keras-FCNKeras-FCN 是一个基于 Keras 与 TensorFlow 的开源语义分割项目它把 VGG16、ResNet50 这类图像分类网络改造成全卷积网络FCN从而实现像素级分类。而实现这一跨越的核心技巧正是全连接层转换为卷积层。本篇文章将带你精读 Keras-FCN 源码彻底搞懂这个转换的原理与实现让你对语义分割的理解再上一个台阶。什么是像素级分类先认识语义分割语义分割Semantic Segmentation是计算机视觉的重要任务它不满足于告诉模型这张图里有一只猫而是让模型把图像中的每一个像素都打上类别标签比如人、自行车、道路、天空……这种逐像素打标签的过程就叫像素级分类。传统图像分类网络如 VGG16、ResNet50输出的是一个一维向量代表整张图属于某个类别的概率而语义分割需要输出一张与输入同尺寸的标签图。想直接复用训练好的分类网络就必须对它的结构动手术——这正是 Keras-FCN 的核心工作。为什么必须把全连接层转换为卷积层分类网络尾部通常用全连接层Fully Connected Layer收尾直接拿来做分割会遇到三个问题而把它们改写成卷积层可以一次性全部解决1. 保留空间位置信息实现像素级分类全连接层会把特征图压扁成一维向量空间位置信息全部丢失而卷积层用滑动窗口扫描天然保留哪个位置有什么的空间结构。像素级分类恰恰最依赖位置信息这一步是质的改变。2. 摆脱固定输入尺寸的限制全连接层的参数量与输入尺寸绑定训练完成后只能接受固定尺寸的图片卷积层是参数共享的可以处理任意尺寸输入。改成全卷积网络后图片想多大就多大实用性强得多。3. 完整复用预训练权重免去从头训练最关键的一点全连接层与卷积层在数学上可以互相转换ImageNet 预训练权重只需做一次 reshape 就能原封不动搬进新网络稍作微调即可投入分割任务大幅降低训练成本和时间。对比项全连接层卷积层输出形式一维向量二维特征图空间信息丢失保留输入尺寸固定任意参数量与输入尺寸绑定与输入尺寸无关能否像素级分类不能可以全连接层转卷积层的原理一次优雅的数学等价为什么全连接层能转成卷积层因为它们在数学上是等价的全连接层本质是矩阵乘法y Wx b卷积层本质也是加权求和只是按空间位置滑动窗口当一个卷积核的大小恰好等于输入特征图的尺寸时卷积就退化成了一次矩阵乘法——此时两者完全等价以 VGG16 为例fc1 层输入是 7×7×512 25088 维向量把它改造成 7×7 卷积核、输出 4096 通道功能完全相同fc2 层4096 → 4096对应特征图已是 1×1用 1×1 卷积即可替代分类层4096 → 1000同样用 1×1 卷积替代Keras-FCN 源码精读权重转换的魔法理论说完了来看看 Keras-FCN 到底怎么实现。核心代码集中在 transfer_FCN.py它做的事情可以概括为三步用卷积层复刻一遍原网络结构把 fc 全部换成 conv加载 ImageNet 预训练权重把全连接层的权重 reshape 成卷积核形状另存为新权重文件VGG16一个 7×7 卷积 两个 1×1 卷积transfer_FCN.py 中的transfer_FCN_Vgg16()先搭建了一个结构相同的全卷积 VGG16替换关系一目了然fc1→Conv2D(4096, (7, 7))fc2→Conv2D(4096, (1, 1))分类层 →Conv2D(1000, (1, 1))随后从预训练 VGG16 中取出权重最核心的 reshape 其实只有三行weights[0] np.reshape(weights[0], (7, 7, 512, 4096)) # fc1 weights[0] np.reshape(weights[0], (1, 1, 4096, 4096)) # fc2 weights[0] np.reshape(weights[0], (1, 1, 4096, 1000)) # predictions(7, 7, 512, 4096)就是把原来 25088×4096 的权重矩阵重新排列成高 7、宽 7、输入通道 512、输出通道 4096的卷积核后面两个 1×1 卷积同理。转换完成后保存权重文件之后 models.py 里的 FCN 模型按层名加载这份新权重即可直接开始分割训练。ResNet50只需要改最后一层transfer_FCN.py 中的transfer_FCN_ResNet50()更简单ResNet50 经过全局平均池化后只有一个fc1000层2048 → 1000只需把它 reshape 成(1, 1, 2048, 1000)的卷积核即可完成转换堪称一行代码的魔法。组装像素级分类网络models.py 精读权重转换好之后models.py 负责把完整的 FCN 网络组装起来。以FCN_Vgg16_32s为例主干结构与转换脚本完全一致之后追加两个关键操作分类层1×1 卷积输出 21 个通道对应 Pascal VOC 的 21 个类别让每个像素都得到一个 21 维的类别分数向量上采样层接上 BilinearUpSampling2D 双线性上采样把低分辨率的分数图放大回原图尺寸这里 32s 的含义是输入图像经过 5 次池化缩小了 32 倍最后再上采样 32 倍还原。特征图缩得越小上采样丢失的细节就越多于是 Keras-FCN 又引入了更聪明的做法——空洞卷积。进阶空洞卷积与 16s 模型AtrousFCN_Resnet50_16s是项目里表现最好的模型。它用空洞卷积Atrous / Dilated Convolution替换了 stage5 的普通卷积在不额外池化、不增加参数量的情况下扩大感受野让特征图只缩小 16 倍而非 32 倍保留了更多细节最终只需 16 倍上采样分割边界明显更精细。在增强版 Pascal VOC2012 数据集上该模型平均交并比mIoU达到0.661像素精度约0.9是名副其实的性能担当。亲自上手从权重转换到训练推理想亲手跑一遍 Keras-FCN 也不难整体流程如下克隆仓库git clone https://gitcode.com/gh_mirrors/ker/Keras-FCN生成转换权重进入utils目录运行python transfer_FCN.py Vgg16或ResNet50训练模型运行 train.py所有参数都在 main 函数中配置评估效果运行 evaluate.py会保存分割结果图并计算 IoU 指标单张推理运行 inference.py 快速查看分割效果数据增强、学习率调度等细节都可以在 train.py 与 SegDataGenerator.py 中按需调整。需要注意的是项目仍处于持续开发中Unfinished部分功能可能还不够完善但这并不影响它作为 FCN 学习范本的巨大价值。总结Keras-FCN 用全连接层转换为卷积层这一招优雅地完成了从图像分类到像素级分类的跨越当卷积核大小等于输入特征图尺寸时全连接与卷积在数学上完全等价因此只需 reshape 权重即可完整复用预训练模型。理解了 transfer_FCN.py 中那几行 reshape 代码你就抓住了 FCN 的灵魂——再看语义分割领域的其他经典论文与实现都会觉得豁然开朗。【免费下载链接】Keras-FCNKeras-tensorflow implementation of Fully Convolutional Networks for Semantic SegmentationUnfinished项目地址: https://gitcode.com/gh_mirrors/ker/Keras-FCN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考