政安晨:【Keras机器学习示例演绎】(三十七)—— 在计算机视觉中学习调整大小

政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏: TensorFlow与Keras机器学习实战

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!

本文目标:在计算机视觉中学习调整大小。

人们普遍认为,如果我们限制视觉模型像人类一样感知事物,它们的性能就能得到提高。例如,在这项工作中,Geirhos 等人发现,在 ImageNet-1k 数据集上预先训练的视觉模型偏重于纹理,而人类大多使用形状描述符来形成共同的感知。但这种观点是否总是适用,尤其是在提高视觉模型的性能时?

事实证明,情况并非总是如此。在训练视觉模型时,通常会将图像调整到较低的维度((224 x 224)、(299 x 299)等),以便进行小批量学习,同时也能减少计算量的限制。

在这一步骤中,我们通常使用双线性插值等调整图像大小的方法,调整后的图像对人眼来说不会失去太多感知特征。在《学习为计算机视觉任务调整图像大小》一书中,Talebi 等人指出,如果我们尝试为视觉模型而不是人眼优化图像的感知质量,其性能就能得到进一步提高。他们研究了以下问题:

对于给定的图像分辨率和模型,如何最好地调整给定图像的大小?

正如论文所示,这一想法有助于持续提高常见视觉模型(在 ImageNet-1k 上预先训练)的性能,如 DenseNet-121、ResNet-50、MobileNetV2 和 EfficientNets。在本示例中,我们将实现论文中提出的可学习图像大小调整模块,并使用 DenseNet-121 架构在猫狗数据集上进行演示。

设置

import os

os.environ["KERAS_BACKEND"] = "tensorflow"
import keras
from keras import ops
from keras import layers
import tensorflow as tf

import tensorflow_datasets as tfds

tfds.disable_progress_bar()

import matplotlib.pyplot as plt
import numpy as np

定义超参数


为了方便迷你批次学习,我们需要为给定批次中的图像设定一个固定的形状。这就是需要进行初始大小调整的原因。我们首先将所有图像的大小调整为(300 x 300),然后学习它们在(150 x 150)分辨率下的最佳表现形式。

INP_SIZE = (300, 300)
TARGET_SIZE = (150, 150)
INTERPOLATION = "bilinear"

AUTO = tf.data.AUTOTUNE
BATCH_SIZE = 64
EPOCHS = 5

在本例中,我们将使用双线性插值,但可学习图像调整模块并不依赖于任何特定的插值方法。我们也可以使用其他方法,例如双三次插值。

加载并准备数据集


在本例中,我们将只使用总训练数据集的 40%。

train_ds, validation_ds = tfds.load(
    "cats_vs_dogs",
    # Reserve 10% for validation
    split=["train[:40%]", "train[40%:50%]"],
    as_supervised=True,
)


def preprocess_dataset(image, label):
    image = ops.image.resize(image, (INP_SIZE[0], INP_SIZE[1]))
    label = ops.one_hot(label, num_classes=2)
    return (image, label)


train_ds = (
    train_ds.shuffle(BATCH_SIZE * 100)
    .map(preprocess_dataset, num_parallel_calls=AUTO)
    .batch(BATCH_SIZE)
    .prefetch(AUTO)
)
validation_ds = (
    validation_ds.map(preprocess_dataset, num_parallel_calls=AUTO)
    .batch(BATCH_SIZE)
    .prefetch(AUTO)
)

定义可学习的调整器实用程序


下图(提供:学习调整图像大小以完成计算机视觉任务)展示了可学习调整大小模块的结构:

def conv_block(x, filters, kernel_size, strides, activation=layers.LeakyReLU(0.2)):
    x = layers.Conv2D(filters, kernel_size, strides, padding="same", use_bias=False)(x)
    x = layers.BatchNormalization()(x)
    if activation:
        x = activation(x)
    return x


def res_block(x):
    inputs = x
    x = conv_block(x, 16, 3, 1)
    x = conv_block(x, 16, 3, 1, activation=None)
    return layers.Add()([inputs, x])

    # Note: user can change num_res_blocks to >1 also if needed


def get_learnable_resizer(filters=16, num_res_blocks=1, interpolation=INTERPOLATION):
    inputs = layers.Input(shape=[None, None, 3])

    # First, perform naive resizing.
    naive_resize = layers.Resizing(*TARGET_SIZE, interpolation=interpolation)(inputs)

    # First convolution block without batch normalization.
    x = layers.Conv2D(filters=filters, kernel_size=7, strides=1, padding="same")(inputs)
    x = layers.LeakyReLU(0.2)(x)

    # Second convolution block with batch normalization.
    x = layers.Conv2D(filters=filters, kernel_size=1, strides=1, padding="same")(x)
    x = layers.LeakyReLU(0.2)(x)
    x = layers.BatchNormalization()(x)

    # Intermediate resizing as a bottleneck.
    bottleneck = layers.Resizing(*TARGET_SIZE, interpolation=interpolation)(x)

    # Residual passes.
    # First res_block will get bottleneck output as input
    x = res_block(bottleneck)
    # Remaining res_blocks will get previous res_block output as input
    for _ in range(num_res_blocks - 1):
        x = res_block(x)

    # Projection.
    x = layers.Conv2D(
        filters=filters, kernel_size=3, strides=1, padding="same", use_bias=False
    )(x)
    x = layers.BatchNormalization()(x)

    # Skip connection.
    x = layers.Add()([bottleneck, x])

    # Final resized image.
    x = layers.Conv2D(filters=3, kernel_size=7, strides=1, padding="same")(x)
    final_resize = layers.Add()([naive_resize, x])

    return keras.Model(inputs, final_resize, name="learnable_resizer")


learnable_resizer = get_learnable_resizer()

可视化可学习大小调整模块的输出结果


在这里,我们可以直观地看到经过调整器随机权重调整后的图像效果。

sample_images, _ = next(iter(train_ds))


plt.figure(figsize=(16, 10))
for i, image in enumerate(sample_images[:6]):
    image = image / 255

    ax = plt.subplot(3, 4, 2 * i + 1)
    plt.title("Input Image")
    plt.imshow(image.numpy().squeeze())
    plt.axis("off")

    ax = plt.subplot(3, 4, 2 * i + 2)
    resized_image = learnable_resizer(image[None, ...])
    plt.title("Resized Image")
    plt.imshow(resized_image.numpy().squeeze())
    plt.axis("off")
Corrupt JPEG data: 65 extraneous bytes before marker 0xd9
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

模型制作实用程序

def get_model():
    backbone = keras.applications.DenseNet121(
        weights=None,
        include_top=True,
        classes=2,
        input_shape=((TARGET_SIZE[0], TARGET_SIZE[1], 3)),
    )
    backbone.trainable = True

    inputs = layers.Input((INP_SIZE[0], INP_SIZE[1], 3))
    x = layers.Rescaling(scale=1.0 / 255)(inputs)
    x = learnable_resizer(x)
    outputs = backbone(x)

    return keras.Model(inputs, outputs)

可学习图像调整器模块的结构允许与不同的视觉模型灵活集成。

使用可学习的调整器编译和训练我们的模型

model = get_model()
model.compile(
    loss=keras.losses.CategoricalCrossentropy(label_smoothing=0.1),
    optimizer="sgd",
    metrics=["accuracy"],
)
model.fit(train_ds, validation_data=validation_ds, epochs=EPOCHS)
Epoch 1/5

 146/146 ━━━━━━━━━━━━━━━━━━━━ 1790s 12s/step - accuracy: 0.5783 - loss: 0.6877 - val_accuracy: 0.4953 - val_loss: 0.7173

Epoch 2/5

 146/146 ━━━━━━━━━━━━━━━━━━━━ 1738s 12s/step - accuracy: 0.6516 - loss: 0.6436 - val_accuracy: 0.6148 - val_loss: 0.6605

Epoch 3/5

 146/146 ━━━━━━━━━━━━━━━━━━━━ 1730s 12s/step - accuracy: 0.6881 - loss: 0.6185 - val_accuracy: 0.5529 - val_loss: 0.8655

Epoch 4/5

 146/146 ━━━━━━━━━━━━━━━━━━━━ 1725s 12s/step - accuracy: 0.6985 - loss: 0.5980 - val_accuracy: 0.6862 - val_loss: 0.6070

Epoch 5/5

 146/146 ━━━━━━━━━━━━━━━━━━━━ 1722s 12s/step - accuracy: 0.7499 - loss: 0.5595 - val_accuracy: 0.6737 - val_loss: 0.6321

<keras.src.callbacks.history.History at 0x7f126c5440a0>

可视化训练有素的可视化器的输出结果

plt.figure(figsize=(16, 10))
for i, image in enumerate(sample_images[:6]):
    image = image / 255

    ax = plt.subplot(3, 4, 2 * i + 1)
    plt.title("Input Image")
    plt.imshow(image.numpy().squeeze())
    plt.axis("off")

    ax = plt.subplot(3, 4, 2 * i + 2)
    resized_image = learnable_resizer(image[None, ...])
    plt.title("Resized Image")
    plt.imshow(resized_image.numpy().squeeze() / 10)
    plt.axis("off")
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
WARNING:matplotlib.image:Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

从图中可以看出,经过训练后,图像的视觉效果得到了改善。下表显示了使用大小调整模块与使用双线性插值相比的优势:

ModelNumber of parameters (Million)Top-1 accuracy
With the learnable resizer7.05171767.67%
Without the learnable resizer7.03955460.19%

欲了解更多详情,请查看此存储库。请注意,上述报告中的模型是在 90% 的《猫和狗》训练集上训练了 10 个历元,与本例不同。此外,请注意由于调整模块的大小而增加的参数数量是可以忽略不计的。为了确保性能的提高不是由于随机性造成的,我们使用相同的初始随机权重对模型进行了训练。

现在,一个值得一问的问题是--与基线相比,精度的提高难道不是因为在模型中增加了更多层次(毕竟调整器是一个微型网络)的结果吗?

为了证明事实并非如此,作者进行了以下实验:

—— 取一个预先训练好的模型,训练出一定的大小,比如(224 x 224)。
—— 现在,首先用它对调整为较低分辨率的图像进行预测。记录性能。
—— 在第二个实验中,在预训练模型的顶部插入调整器模块,并热启动训练。记录性能。

现在,作者认为使用第二种方案更好,因为它有助于模型学习如何根据给定的分辨率更好地调整表征。由于这些结果纯粹是经验性的,如果能再多做一些实验,比如分析跨渠道互动,效果会更好。值得注意的是,挤压和激励(SE)区块、全局上下文(GC)区块等元素也会给现有网络增加一些参数,但众所周知,它们有助于网络以系统的方式处理信息,从而提高整体性能。

注释:

—— 为了在视觉模型中加入形状偏差,Geirhos 等人结合自然图像和风格化图像对视觉模型进行了训练。由于输出结果似乎摒弃了纹理信息,因此研究这个可学习的大小调整模块是否能实现类似效果可能会很有趣。
—— 调整器模块可以处理任意分辨率和长宽比,这对于物体检测和分割等任务非常重要。
—— 还有一个与自适应图像大小调整密切相关的课题,即尝试在训练过程中自适应地调整图像/特征图的大小。EfficientV2 就采用了这一理念。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/594265.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(十一)----图的应用

目录 一.最小生成树 1.Prim算法&#xff08;普里姆&#xff09; 2.Kruskal算法(克鲁斯卡尔): 二.最短路径&#xff08;BFS算法&#xff09; 1.单源最短路径 &#xff08;1&#xff09;BFS算法&#xff08;无权图&#xff09; &#xff08;2&#xff09;Dijkstra算法&…

QT+网络调试助手+TCP客户端

一、网络调试助手UI界面 编程主要思路&#xff1a; 首先将水平的控件 水平布局 &#xff0c;然后相对垂直的控件 垂直布局 &#xff0c;哪怕是底下的groupBox也需要和里面的内容 水平布局&#xff0c;然后最后框选全部 栅格布局。如果需要界面自适应窗口大小&#xff0c…

JavaScript js写九九乘法表(两种方法)

方法一&#xff1a; 观察规律&#xff1a; 第一个数每行都是自增1。 我们发下第二个数都是从1开始&#xff0c;依次递增1&#xff0c;永远不大于前面的数。 前面数字每自增一次&#xff0c;后面数字自增一轮。 我们可以用双重for循环&#xff0c;外层初始值设为i&#xff0…

【C++】对文章分词,并对词频用不同排序方法排序,比较各排序算法效率

文章分词 1&#xff0e;问题描述2&#xff0e;需求分析3&#xff0e;概要设计3.1 主程序流程3.2 函数调用关系 4&#xff0e;主函数实现4.1 main.h4.2 main.cpp 5. 函数实现5.1 processDic函数5.2 forwardMax函数5.3 countWordFreq函数5.4 quickResult函数5.5 其它排序算法效率…

【链表】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

十二、泛型

这里写自定义目录标题 一、什么是泛型二、为什么需要泛型&#xff1f;三、自定义泛型结构1、泛型类2、泛型方法 四、泛型在继承上的体现五、通配符的使用1、注意点2、有限制的通配符 一、什么是泛型 泛型就是定义类、接口时通过一个标识表示类中某个属性的类型 、方法的返回值…

C#实现简单音乐文件解析播放——Windows程序设计作业2

1. 作业内容 编写一个C#程序&#xff0c;要求实现常见音乐文件的播放功能&#xff0c;具体要求如下&#xff1a;     1). 播放MP3文件&#xff1a; 程序应能够读取MP3文件&#xff0c;并播放其中的音频。     2). 播放OGG文件&#xff1a; 应能够播放ogg文件。     …

学习3:scrapy请求对象、模拟登录、POST请求、管道的使用、crawlspider爬虫类

请求对象 请求对象参数 scrapy.Request(url[],callback,method"GET",headers,body,cookies,meta,dont_filterFalse)callback 表示当前的url响应交给那个函数去处理method 指定请求方式headers 接受一个字典&#xff0c;其中不包括cookiesbody 接收json字符串&#…

OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69) 下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71) 目录 目标 理论 如何消除傅里叶域中的周期性噪声&#xff1f; 源代码 解释 结果 目…

IDEA--debug

1. 单点调试的三个级别 Step into&#xff1a;在单步执行时&#xff0c;遇到子函数就进入并且继续单步执行。Step over&#xff1a;在单步执行时&#xff0c;在函数内遇到子函数时不会进入子函数内单步执行&#xff0c;而是将子函数整个执行完再停止&#xff0c;也就是把子函数…

用树莓派2B当web服务器

树莓派2&#xff0c;卡片大小&#xff0c;arm 32位cpu&#xff0c;512G内存。我找了一下购买记录&#xff0c;2013年12月15日买的。带网线接头。属于树莓派2B。以前下载的操作系统还在。是2014年的操作系统&#xff0c;文件名是&#xff1a;2014-09-09-wheezy-raspbian_shumeip…

C语言之整形提升和算术转换

目录 前言 一、整形提升 二、算术转换 总结 前言 本文主要介绍C语言中的整形提升和算术转换的概念和意义&#xff0c;以及例题帮助理解&#xff0c;了解之后&#xff0c;我们就能知道在C语言中&#xff0c;字符型变量如何计算以及如果变量的类型、字节大小不一致的情况下&am…

前端工程化06-JavaScript模块化CommonJS规范ES Module

7、JavaScript模块化 在js开发中&#xff0c;他并没有拆分的概念&#xff0c;并不像java一样他可以拆分很多的包&#xff0c;很多的类&#xff0c;像搭积木一样完成一个大型项目的开发&#xff0c;所以js在前期的时候并不适合大型后端的项目开发&#xff0c;但是这些问题在后来…

Android 10.0 Launcher3 app页面调整workspace边距app行距变小功能实现

1.前言 在10.0的系统rom定制化开发中,在launcher3的一些开发定制功能中,在对于大分辨率比如1600*2560的设备进行开发的时候, 会在竖屏的时候,在默认7*4的布局的时候,显得行距有点宽,这样就需要调整整个CellLayout的上下左右边距,然后就 会显得行距会小一点,接下来具体…

ASP.NET网上书店

摘要 本设计尝试用ASP.NET在网络上架构一个电子书城&#xff0c;以使每一位顾客不用出门在家里就能够通过上网来轻松购书。本文从理论和实践两个角度出发&#xff0c;对一个具有数据挖掘功能电子书城进行设计与实现分析。论文首先较为详尽地介绍了面向对象分析与设计的有关概念…

基于Springboot的房屋租赁管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的房屋租赁管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

图中有几个三角形

让我们先把三角形进行分类&#xff1a;1块组成的三角形、2块组成的三角形、依此类推。 1块组成的三角形有4个&#xff1a; 2块组成的三角形有&#xff1a;12,13,14,23,24,34.其中&#xff0c;14&#xff0c;23构不成三角形. 3块组成的三角形有&#xff1a;123,124,134,234。但…

贪心算法(活动选择、分数背包问题)

一、贪心算法 贪心算法是指&#xff1a;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择&#xff0c;而不从整体最优考虑&#xff0c;做出的仅是在某种意义上的局部最优解。 …

流畅的Python阅读笔记

五一快乐的时光总是飞快了&#xff0c;不知多久没有拿起键盘写文章了&#xff0c;最近公司有Python的需求&#xff0c;想着复习下Python吧&#xff0c;然后就买了本Python的书籍 书名&#xff1a; 《流畅的Python》 下面是整理的一个阅读笔记&#xff0c;大家自行查阅&#xf…

Python 全栈系列241 GFGo Lite迭代

说明 随着整个算网开发逐渐深入&#xff0c;各个组件、微服务的数量、深度在不断增加。由于算网是个人项目&#xff0c;我一直按照MVP(Minimum Viable Product )的原则在推进。由于最初的时候对架构、算法和业务的理解并没有那么深刻&#xff0c;所以MVP的内容还是在不断变化&…