0

0

在TensorFlow 2中实现完全卷积网络(FCN)

看不見的法師

看不見的法師

发布时间:2025-09-18 08:23:09

|

907人浏览过

|

来源于php中文网

原创

在TensorFlow 2中实现完全卷积网络(FCN)

作者 | himanshu rawlani

来源 | Medium

编辑 | 代码医生团队

卷积神经网络(CNN)非常适合计算机视觉任务。使用对大型图像集(如ImageNet,COCO等)进行训练的预训练模型,可以快速使这些体系结构专业化,以适合独特数据集。此过程称为迁移学习。但是有一个陷阱!用于图像分类和对象检测任务的预训练模型通常在固定的输入图像尺寸上训练。这些通常从224x224x3到某个范围变化,512x512x3并且大多数具有1的长宽比,即图像的宽度和高度相等。如果它们不相等,则将图像调整为相等的高度和宽度。

较新的体系结构确实能够处理可变的输入图像大小,但是与图像分类任务相比,它在对象检测和分割任务中更为常见。最近遇到了一个有趣的用例,其中有5个不同类别的图像,每个类别都有微小的差异。此外图像的纵横比也比平常高。图像的平均高度约为30像素,宽度约为300像素。这是一个有趣的原因,其原因如下:

调整图像大小容易使重要功能失真预训练的架构非常庞大,并且总是过度拟合数据集任务要求低延迟

需要具有可变输入尺寸的CNN

尝试了MobileNet和EfficientNet的基本模型,但没有任何效果。需要一种对输入图像大小没有任何限制并且可以执行手边的图像分类任务的网络。震惊的第一件事是完全卷积网络(FCN)。FCN是一个不包含任何“密集”层的网络(如在传统的CNN中一样),而是包含1x1卷积,用于执行完全连接的层(密集层)的任务。尽管没有密集层可以输入可变的输入,但是有两种技术可以在保留可变输入尺寸的同时使用密集层。本教程描述了其中一些技术。在本教程中,将执行以下步骤:

使用Keras在TensorFlow中构建完全卷积网络(FCN)下载并拆分样本数据集在Keras中创建生成器以加载和处理内存中的一批数据训练具有可变批次尺寸的网络使用TensorFlow Serving部署模型

获取代码

本文中的代码片段仅突出实际脚本的一部分,有关完整代码,请参阅GitHub存储库。

https://github.com/himanshurawlani/fully_convolutional_network.git

1.设计引擎(model.py)

通过堆叠由2D卷积层(Conv2D)和所需的正则化(Dropout和BatchNormalization)组成的卷积块来构建FCN模型。正则化可防止过度拟合并有助于快速收敛。还添加了一个激活层来合并非线性。在Keras中,输入批次尺寸是自动添加的,不需要在输入层中指定它。由于输入图像的高度和宽度是可变的,因此将输入形状指定为(None, None, 3)。3表示图像中的通道数,该数量对于彩色图像(RGB)是固定的。

代码语言:javascript代码运行次数:0运行复制
import tensorflow as tf def FCN_model(len_classes=5, dropout_rate=0.2):        # Input layer    input = tf.keras.layers.Input(shape=(None, None, 3))     # A convolution block    x = tf.keras.layers.Conv2D(filters=32, kernel_size=3, strides=1)(input)    x = tf.keras.layers.Dropout(dropout_rate)(x)    x = tf.keras.layers.BatchNormalization()(x)    x = tf.keras.layers.Activation('relu')(x)        # Stack of convolution blocks    .    .    .

最小图像尺寸要求

在输入施加卷积块之后,输入的高度和宽度将降低基于所述值kernel_size和strides。如果输入图像的尺寸太小,那么可能无法达到下一个卷积块所需的最小高度和宽度(应大于或等于内核尺寸)。确定最小输入尺寸的尝试和错误方法如下:

确定要堆叠的卷积块数选择任何输入形状以说出(32, 32, 3)并堆叠数量越来越多的通道的卷积块尝试构建模型并打印model.summary()以查看每个图层的输出形状。确保(1, 1, num_of_filters)从最后一个卷积块获得输出尺寸(这将被输入到完全连接的层)。尝试减小/增大输入形状,内核大小或步幅,以满足步骤4中的条件。满足条件的输入形状以及其他配置是网络所需的最小输入尺寸。

还有,以计算输出体积的空间大小,其所示的输入体积的函数的数学方式这里。找到最小输入尺寸后,现在需要将最后一个卷积块的输出传递到完全连接的层。但是任何尺寸大于最小输入尺寸的输入都需要汇总以满足步骤4中的条件。了解如何使用我们的主要成分来做到这一点。

http://cs231n.github.io/convolutional-networks/#conv

主要成分

全连接层(FC层)将执行分类任务。可以通过两种方式构建FC层:

致密层1x1卷积

如果要使用密集层,则必须固定模型输入尺寸,因为必须预先定义作为密集层输入的参数数量才能创建密集层。具体来说,希望(height, width, num_of_filters)最后一个卷积块的输出中的高度和宽度为常数或1。滤波器的数量始终是固定的,因为这些值是在每个卷积块中定义的。

1x1卷积的输入尺寸可以是(1, 1, num_of_filters)或(height, width, num_of_filters)模仿它们沿num_of_filters尺寸方向FC层的功能。但是,在1x1卷积之后,最后一层(Softmax激活层)的输入必须具有固定的长度(类数)。

主要成分:GlobalMaxPooling2D() / GlobalAveragePooling2D()。Keras中的这些层将尺寸的输入转换(height, width, num_of_filters)为(1, 1, num_of_filters)实质上沿尺寸的每个值的最大值或平均值,用于沿尺寸的每个过滤器num_of_filters。

代码语言:javascript代码运行次数:0运行复制
# Uncomment the below line if you're using dense layers# x = tf.keras.layers.GlobalMaxPooling2D()(x) # Fully connected layer 1# x = tf.keras.layers.Dropout(dropout_rate)(x)# x = tf.keras.layers.BatchNormalization()(x)# x = tf.keras.layers.Dense(units=64)(x)# x = tf.keras.layers.Activation('relu')(x) # Fully connected layer 1x = tf.keras.layers.Conv2D(filters=64, kernel_size=1, strides=1)(x)x = tf.keras.layers.Dropout(dropout_rate)(x)x = tf.keras.layers.BatchNormalization()(x)x = tf.keras.layers.Activation('relu')(x) # Fully connected layer 2# x = tf.keras.layers.Dropout(dropout_rate)(x)# x = tf.keras.layers.BatchNormalization()(x)# x = tf.keras.layers.Dense(units=len_classes)(x)# predictions = tf.keras.layers.Activation('softmax')(x) # Fully connected layer 2x = tf.keras.layers.Conv2D(filters=len_classes, kernel_size=1, strides=1)(x)x = tf.keras.layers.Dropout(dropout_rate)(x)x = tf.keras.layers.BatchNormalization()(x)x = tf.keras.layers.GlobalMaxPooling2D()(x)predictions = tf.keras.layers.Activation('softmax')(x) model = tf.keras.Model(inputs=input, outputs=predictions)print(model.summary())

密集层与1x1卷积

该代码包括密集层(注释掉)和1x1卷积。在使用两种配置构建和训练模型之后,这里是一些观察结果:

两种模型都包含相同数量的可训练参数。类似的训练和推理时间。密集层比1x1卷积的泛化效果更好。

第三点不能一概而论,因为它取决于诸如数据集中的图像数量,使用的数据扩充,模型初始化等因素。但是这些是实验中的观察结果。可以通过执行命令来独立运行脚本,以测试是否已成功构建模型$python model.py。

2.下载fuel(data.py)

闪念贝壳
闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

下载

本教程中使用的flowers数据集主要旨在了解在训练具有可变输入维度的模型时面临的挑战。测试FCN模型的一些有趣的数据集可能来自医学成像领域,其中包含对图像分类至关重要的微观特征,而其他数据集包含的几何图案/形状在调整图像大小后可能会失真。

1.提供的脚本(data.py)需要独立运行($python data.py)。它将执行以下任务:

2.下载包含5类(“雏菊”,“蒲公英”,“玫瑰”,“向日葵”,“郁金香”)的花卉数据集。有关数据集的更多细节在这里。

https://www.tensorflow.org/datasets/catalog/tf_flowers

3.将数据集分为训练和验证集。可以设置要复制到训练和验证集中的图像数量。

提供有关数据集的统计信息,例如图像的最小,平均和最大高度和宽度。

此脚本使用来下载.tar文件并将其内容提取到当前目录中keras.utils.get_file()。如果想使用TensorFlow数据集(TFDS),可以查看本教程,该教程说明了TFDS以及数据扩充的用法。

3.特殊化carburetor(generator.py)

想在不同的输入维度上训练模型。给定批次和批次之间的每个图像都有不同的尺寸。所以有什么问题?退后一步,回顾一下如何训练传统的图像分类器。在传统的图像分类器中,将图像调整为给定尺寸,通过转换为numpy数组或张量将其打包成批,然后将这批数据通过模型进行正向传播。在整个批次中评估指标(损失,准确性等)。根据这些指标计算要反向传播的梯度。

无法调整图像大小(因为我们将失去微观特征)。现在由于无法调整图像的大小,因此无法将其转换为成批的numpy数组。这是因为如果有一个10张图像的列表,(height, width, 3)它们的height和值不同,width并且尝试将其传递给np.array(),则结果数组的形状将为(10,)and not (10, height, width, 3)!但是模型期望输入尺寸为后一种形状。一种解决方法是编写一个自定义训练循环,该循环执行以下操作:

通过将通过每个图像,在列表中(分批),通过模型(height, width, 3)来(1, height, width, 3)使用np.expand_dims(img, axis=0)。累积python列表(批处理)中每个图像的度量。使用累积的指标计算损耗和梯度。将渐变更新应用到模型。重置指标的值并创建新的图像列表(批次)。

尝试了上述步骤,但建议不要采用上述策略。它很费力,导致代码复杂且不可持续,并且运行速度非常慢!每个人都喜欢优雅的 model.fit()和model.fit_generator()。后者是将在这里使用的!但是首先是化油器。

化油器是一种以合适的空燃比混合用于内燃机的空气和燃料的装置。这就是所需要的,空气!找到批处理中图像的最大高度和宽度,并用零填充每个其他图像,以使批处理中的每个图像都具有相等的尺寸。现在可以轻松地将其转换为numpy数组或张量,并将其传递给fit_generator()。该模型会自动学习忽略零(基本上是黑色像素),并从填充图像的预期部分学习特征。这样就有了一个具有相等图像尺寸的批处理,但是每个批处理具有不同的形状(由于批处理中图像的最大高度和宽度不同)。可以generator.py使用独立运行文件$python generator.py并交叉检查输出。

代码语言:javascript代码运行次数:0运行复制
def construct_image_batch(image_group, BATCH_SIZE):    # get the max image shape    max_shape = tuple(max(image.shape[x] for image in image_group) for x in range(3))     # construct an image batch object    image_batch = np.zeros((BATCH_SIZE,) + max_shape, dtype='float32')     # copy all images to the upper left part of the image batch object    for image_index, image in enumerate(image_group):        image_batch[image_index, :image.shape[0], :image.shape[1], :image.shape[2]] = image     return image_batch

4.点燃认知(train.py)

训练脚本导入并实例化以下类:

生成器:需要指定到创建的路径train和val目录data.py。FCN_model:需要指定最终输出层中所需的类数。

将上述对象传递给train()使用Adam优化器和分类交叉熵损失函数编译模型的函数。创建一个检查点回调,以在训练期间保存最佳模型。最佳模型是根据每个时期结束时的验证集计算出的损失值确定的。fit_generator()函数在很大程度上简化了代码。

代码语言:javascript代码运行次数:0运行复制
def train(model, train_generator, val_generator, epochs = 50):    model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.0001),                    loss='categorical_crossentropy',                    metrics=['accuracy'])     checkpoint_path = './snapshots'    os.makedirs(checkpoint_path, exist_ok=True)    model_path = os.path.join(checkpoint_path, 'model_epoch_{epoch:02d}_loss_{loss:.2f}_acc_{acc:.2f}_val_loss_{val_loss:.2f}_val_acc_{val_acc:.2f}.h5')        history = model.fit_generator(generator=train_generator,                                    steps_per_epoch=len(train_generator),                                    epochs=epochs,                                    callbacks=[tf.keras.callbacks.ModelCheckpoint(model_path, monitor='val_loss', save_best_only=True, verbose=1)],                                    validation_data=val_generator,                                    validation_steps=len(val_generator))     return history

建议在Google Colab上进行训练,除非本地计算机上有GPU。GitHub存储库包含一个Colab笔记本,该笔记本将训练所需的所有内容组合在一起。可以在Colab本身中修改python脚本,并在选择的数据集上训练不同的模型配置。完成训练后,可以从Colab中的“文件”选项卡将最佳快照下载到本地计算机。

5.使用TensorFlow Serving(inference.py)部署模型

下载模型后,需要使用将其导出为SavedModel格式export_savedmodel.py。.h5在主要功能中指定下载模型(文件)的路径,然后使用命令执行脚本$python export_savedmodel.py。该脚本使用TensorFlow 2.0中的新功能,该功能从.h5文件中加载Keras模型并将其保存为TensorFlow SavedModel格式。SavedModel将导出到export_path脚本中指定的位置。TensorFlow服务docker映像需要此SavedModel。

代码语言:javascript代码运行次数:0运行复制
def export(input_h5_file, export_path):    # The export path contains the name and the version of the model    tf.keras.backend.set_learning_phase(0)  # Ignore dropout at inference    model = tf.keras.models.load_model(input_h5_file)    model.save(export_path, save_format='tf')    print(f"SavedModel created at {export_path}")

要启动TensorFlow Serving服务器,请转到导出SavedModel的目录(./flower_classifier在这种情况下)并运行以下命令(注意:计算机上必须安装了Docker):

代码语言:javascript代码运行次数:0运行复制
$ docker run --rm -t -p 8501:8501 -v "$(pwd):/models/flower_classifier" -e MODEL_NAME=flower_classifier --name flower_classifier tensorflow/serving

可以使用$ docker ps命令验证容器在后台运行。还可以使用查看容器日志$ docker logs your_container_id。该inference.py脚本包含用于构建具有统一图像尺寸的批次的代码,并将这些批次作为POST请求发送到TensorFlow服务服务器。从服务器接收的输出被解码并在终端中打印。

代码语言:javascript代码运行次数:0运行复制
def make_serving_request(image_batch):    data = json.dumps({"signature_name": "serving_default",                       "instances": image_batch.tolist()})     headers = {"content-type": "application/json"}     os.environ['NO_PROXY'] = 'localhost'    json_response = requests.post(        'http://localhost:8501/v1/models/flower_classifier:predict', data=data, headers=headers)     predictions = json.loads(json_response.text)['predictions']     return predictions

梦想的传达

本教程仅介绍机器学习工作流程中的单个组件。机器学习管道包括针对组织及其用例的大量训练,推断和监视周期。建立这些管道需要对驾驶员,乘客和车辆路线有更深入的了解。只有这样,才能实现理想的运输工具!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

447

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

606

2023.08.10

github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

4332

2026.01.21

k8s和docker区别
k8s和docker区别

k8s和docker区别有抽象层次不同、管理范围不同、功能不同、应用程序生命周期管理不同、缩放能力不同、高可用性等等区别。本专题为大家提供k8s和docker区别相关的各种文章、以及下载和课程。

280

2023.07.24

docker进入容器的方法有哪些
docker进入容器的方法有哪些

docker进入容器的方法:1. Docker exec;2. Docker attach;3. Docker run --interactive --tty;4. Docker ps -a;5. 使用 Docker Compose。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

516

2024.04.08

docker容器无法访问外部网络怎么办
docker容器无法访问外部网络怎么办

docker 容器无法访问外部网络的原因和解决方法:配置 nat 端口映射以将容器端口映射到主机端口。根据主机兼容性选择正确的网络驱动(如 host 或 overlay)。允许容器端口通过主机的防火墙。配置容器的正确 dns 服务器。选择正确的容器网络模式。排除主机网络问题,如防火墙或连接问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

417

2024.04.08

docker镜像有什么用
docker镜像有什么用

docker 镜像是预构建的软件组件,用途广泛,包括:应用程序部署:简化部署,提高移植性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

454

2024.04.08

Docker容器化部署与DevOps实践
Docker容器化部署与DevOps实践

本专题面向后端与运维开发者,系统讲解 Docker 容器化技术在实际项目中的应用。内容涵盖 Docker 镜像构建、容器运行机制、Docker Compose 多服务编排,以及在 DevOps 流程中的持续集成与持续部署实践。通过真实场景演示,帮助开发者实现应用的快速部署、环境一致性与运维自动化。

42

2026.02.11

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号