首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何利用EfficientNet实现多标签图像分类

如何利用EfficientNet实现多标签图像分类
EN

Data Science用户
提问于 2021-05-13 21:09:11
回答 2查看 1.4K关注 0票数 0

问题

我的目标是用EfficientNet进行多标签图像分类.它应该以一张图片作为输入,例如告诉用户它在图片上看到了一个人和一只狗,这意味着概率不会加到1 --每个类的概率从0到1。简而言之,我想把一个多类的解决方案转换成一个多标签的解决方案。

数据

我正在使用来自Kaggle的COCO数据集的一个小子集,您可以找到它的这里。它包含大约100 k的图像,精确地包含了80个类。labels.csv包含一个带有文件名的列和一个用于目标输出的热编码列。

我在子集label.csv中添加了标题,以了解哪些列引用哪个标签。我还将所有的图像文件复制到一个目录中(数据集/coco_subset/train),因为标签信息也在一个.csv文件中,并且无法让DataGenerators单独检索图像。但这不是我的主要问题!(不过,对于如何正确处理这件事,我还是很感激。)

精度与损耗

我得到了模型来编写并开始训练。首先我尝试了20次,然后是50次,最后是100次。在花费了大量时间( 6GB VRAM大约12小时)的100个历次之后,我仍然无法达到可接受的精度。实际上,在整个100个年代中,精度停滞在20%左右。同样的损失也发生在4-5左右,如下图所示:

在下一节中,您可以找到关联的代码。EfficientNet作为新的多标签分类方法的基本模型.对于EfficientNets预先训练的权重,我选择了imagenet权重。我用扁平、Dropout和密集层替换了原来的顶层,节点数=可能的输出数。

我不希望模型库是可训练的,因为我读到,通过这种方式,它使用预先训练过的imagenet权重来提取特征。同时,将这个属性设置为True意味着需要更多的时间进行培训。

我用乙状结肠代替了最终的激活功能。作为损失函数,我使用了二元交叉熵。我将EfficientNetB0用于性能目的。当我从训练变体B4获得好的结果时,我想切换到B5或B0。

代码语言:javascript
运行
复制
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Dense, Flatten
from keras.optimizers import Adam
import pandas as pd

# define input shape and batch size
input_shape = (224, 224, 3)
batch_size = 256

# paths
train_dir = "datasets/coco_subset/images/train"
# test_dir = "datasets/coco_subset/images/test" # didn't work with ImageDataGeneartor.flow_from_dataframe
csv_dir = "datasets/coco_subset/labels/labels_train.csv"
label_names_dir = "datasets/coco_subset/labels/categories.csv"

# read csv data for loading image label information
df = pd.read_csv(csv_dir)
df_labels = pd.read_csv(label_names_dir)

label_names = list(df_labels["Labels"])
x_col = df.columns[0]
y_cols = list(df.columns[1:len(label_names)+1])

# load input images and split into training, test and validation
datagen = ImageDataGenerator(rescale=1./255,validation_split=.25)

train_generator = datagen.flow_from_dataframe(
    df,
    directory=train_dir,
    x_col=x_col,
    y_col=y_cols,
    subset="training",
    target_size=input_shape[0:2],
    color_mode="rgb",
    class_mode="raw", # for multilabel output
    batch_size=batch_size,
    shuffle=True,
    seed=42,
    interpolation="bilinear",
    validate_filenames=False
)

test_generator = datagen.flow_from_dataframe(
    df,
    directory=train_dir,
    x_col=x_col,
    y_col=y_cols,
    subset="validation",
    target_size=input_shape[0:2],
    color_mode="rgb",
    class_mode="raw",
    batch_size=batch_size,
    shuffle=True,
    seed=42,
    interpolation="bilinear",
    validate_filenames=False
)

# build model
n_outputs = len(label_names)

model_base = EfficientNetB0(weights='imagenet', include_top=False, input_shape=input_shape)
model_base.trainable = False

model = Sequential([
    model_base,
    Dropout(0.25),
    Flatten(),
    Dense(n_outputs, activation="sigmoid")
])

model.summary()

# compile model
opt = Adam(learning_rate=0.01)
model.compile(optimizer=opt, loss="binary_crossentropy", metrics=["accuracy"])

# define training and validation steps
steps_per_epoch = train_generator.samples // train_generator.batch_size
validation_steps = test_generator.samples // test_generator.batch_size

# train model
hist = model.fit(
    train_generator,
    epochs=100, steps_per_epoch=steps_per_epoch,
    validation_data=test_generator,
    validation_steps=validation_steps).history

概述

总结一下我的问题:

  • 新的顶层甚至能够解决多标签问题吗?
  • 我是将基模型的可训练属性设置为真,还是将其保持为假?
  • 该模型是否存在过度或不足的问题?
EN

回答 2

Data Science用户

发布于 2022-07-02 02:51:39

你的代码看起来是正确的。特别是,使用sigmoid激活是正确的(因为您需要多个热输出,使用softmax没有意义)和binary_cross_entropy (考虑到问题不是二进制的,但每个决定都是这样)。

那它为什么不起作用?我怀疑问题出在你训练过的体重上。当您使用冻结的、预先训练过的权重时,您必须使用与导出权重时完全相同的预处理。作为一个健全检查,您可以获取原始ImageNet的一个子集,并验证您对这些图像的评估准确性与论文所得到的大致相同。

您还会询问是否应该将基本模型设置为可培训的。如果这样做,您将不那么依赖于规范化方案,并且您将得到更好地调整到特定问题的特性。另一方面,由于您的数据集比ImageNet更小,这些特性实际上可能不太好(而且需要更长的时间来训练)。

票数 0
EN

Data Science用户

发布于 2021-05-15 10:42:22

乙状结肠激活和binary_cross_entropy损失用于二值分类。

应用softmax激活和categorical_cross_entropy损失进行多类分类.

代码语言:javascript
运行
复制
...

model = Sequential([
    model_base,
    Dropout(0.25),
    Flatten(),
    Dense(n_outputs, activation="softmax")
])

...

model.compile(optimizer=opt, loss="categorical_cross_entropy", metrics=["accuracy"])


```
代码语言:javascript
运行
复制
票数 -1
EN
页面原文内容由Data Science提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://datascience.stackexchange.com/questions/94408

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档