深度学习进阶,多个输出和多个损失实现多标签分类,程序员去大公司面试

  • red_dress(384张图片)

  • red_shirt(332张图片)

  • red_shoe(486张图片)

  • white_bag(747张图片)

  • white_shoe(840张图片)

我们的卷积神经网络的目标是同时预测颜色和服饰类别。代码使用Tensorflow2.0以上版本编写。下面对我实现算法的代码作讲解:

项目结构

===============================================================

$ tree --filelimit 10 --dirsfirst

.

├── dataset

│ ├── black_jeans [344 entries]

│ ├── black_shoes [358 entries]

│ ├── blue_dress [386 entries]

│ ├── blue_jeans [356 entries]

│ ├── blue_shirt [369 entries]

│ ├── red_dress [380 entries]

│ └── red_shirt [332 entries]

├── examples

│ ├── black_dress.jpg

│ ├── black_jeans.jpg

│ ├── blue_shoes.jpg

│ ├── red_shirt.jpg

│ └── red_shoes.jpg

├── output

│ ├── fashion.model

│ ├── category_lb.pickle

│ ├── color_lb.pickle

│ ├── output_accs.png

│ └── output_losses.png

├── model

│ ├── init.py

│ └── fashionnet.py

├── train.py

└── classify.py

在上面你可以找到我们的项目结构,但在我们继续之前,让我们先回顾一下内容。 有 3 个值得注意的 Python 文件:

  • model/fashionnet.py :我们的多输出分类网络文件包含由三种方法组成的 FashionNet 架构类: build_category_branch 、 build_color_branch 和 build 。我们将在下一节详细回顾这些方法。

  • train.py :此脚本将训练 FashionNet 模型并在此过程中生成输出文件夹中的所有文件。

  • category.py :此脚本加载我们训练好的网络并使用多输出分类对示例图像进行分类。

我们还有 4 个顶级目录:

  • dataset/ :我们的时尚数据集,是使用他们的 API 从 Bing Image Search 中抓取的。我们在上一节中介绍了数据集。要以与我相同的方式创建您自己的数据集,请参阅如何(快速)构建深度学习图像数据集。

  • examples/ :我们有一些示例图像,我们将在本博文的最后一节中将它们与我们的分类.py 脚本结合使用。

  • output/ :我们的 train.py 脚本生成了一些输出文件:

  • fashion.model :我们的序列化 Keras 模型。

  • category_lb.pickle :服装类别的序列化 LabelBinarizer 对象由 scikit-learn 生成。这个文件可以通过我们的classify.py 脚本加载(并调用标签

  • color_lb.pickle :颜色的 LabelBinarizer 对象。

  • output_accs.png :精度训练图图像。

  • output_losses.png :损失训练图图像。

  • model/ :这是一个包含 FashionNet 类的 Python 模块。

快速回顾我们的多输出 Keras 架构

==============================================================================

为了使用 Keras 执行多输出预测,我们将实现一个名为 FashionNet 的特殊网络架构(我为这篇博文而创建)。

FashionNet 架构包含两个特殊组件,包括:

  • 网络早期的一个分支,将网络分成两个“子网络”——一个负责服装类型分类,另一个负责颜色分类。

  • 网络末端的两个(不相交)全连接头,每个头负责各自的分类职责。

在我们开始实现 FashionNet 之前,让我们可视化这些组件中的每一个,第一个是分支:

在这里插入图片描述

在这个网络架构图中,您可以看到我们的网络接受 96 x 96 x 3 的输入图像。

然后我们立即创建两个分支:

  1. 左边的分支负责对服装类别进行分类。

  2. 右侧的分支处理颜色分类。

每个分支执行其各自的一组卷积、激活、批量归一化、池化和 dropout 操作,直到我们达到最终输出:

img

图 5:我们的深度学习 Keras 多输出分类网络可以学习不相交的标签组合。

请注意这些全连接 (FC) 头集如何与我们在本博客中研究过的其他架构中的 FC 层相似——但现在有两个,每个都负责其给定的分类任务。

网络右侧的分支明显比左侧分支浅(没有那么深)。 预测颜色比预测服装类别要容易得多,因此颜色分支相对较浅。

为了了解我们如何实现这样的架构,让我们继续下一节。

实施我们的“FashionNet”架构

==============================================================================

img

图 6:Keras 深度学习库具有执行多输出分类所需的所有功能。

新建fashionnet.py 在里面增加:

import the necessary packages

from tensorflow.keras.models import Model

from tensorflow.keras.layers import BatchNormalization

from tensorflow.keras.layers import Conv2D

from tensorflow.keras.layers import MaxPooling2D

from tensorflow.keras.layers import Activation

from tensorflow.keras.layers import Dropout

from tensorflow.keras.layers import Lambda

from tensorflow.keras.layers import Dense

from tensorflow.keras.layers import Flatten

from tensorflow.keras.layers import Input

import tensorflow as tf

我们首先从 Keras 库导入模块,然后导入 TensorFlow 本身。

由于我们的网络由两个子网络组成,我们将定义两个函数来负责构建各自的分支。

第一个, build_category_branch ,用于分类服装类型,定义如下:

class FashionNet:

@staticmethod

def build_category_branch(inputs, numCategories,

finalAct=“softmax”, chanDim=-1):

utilize a lambda layer to convert the 3 channel input to a

grayscale representation

x = Lambda(lambda c: tf.image.rgb_to_grayscale©)(inputs)

CONV => RELU => POOL

x = Conv2D(32, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(3, 3))(x)

x = Dropout(0.25)(x)

build_category_branch 具有三个值得注意的参数:

  1. 输入:我们类别分支子网络的输入量。

  2. numCategories :类别的数量,例如“连衣裙”、“鞋子”、“牛仔裤”、“衬衫”等。

  3. finalAct :最终激活层类型,默认为 softmax 分类器。如果您同时执行多输出和多标签分类,您可能希望将此激活更改为 sigmoid。

我们使用 Lambda 层将图像从 RGB 转换为灰度。

为什么要这样做? 嗯,不管是红色、蓝色、绿色、黑色还是紫色,裙子都是裙子,对吧? 因此,我们决定丢弃任何颜色信息,转而关注图像中的实际结构成分,确保我们的网络不会学习将特定颜色与服装类型联合关联。

然后我们继续构建我们的 CONV => RELU => POOL 块和 dropout。请注意,我们使用的是 TensorFlow/Keras 的函数式 API;我们需要功能性 API 来创建我们的分支网络结构。

我们的第一个 CONV 层有 32 个滤波器,带有 3 x 3 内核和 RELU 激活(整流线性单元)。我们应用批量归一化、最大池化和 25% dropout。 Dropout是将节点从当前层随机断开到下一层的过程。这种随机断开的过程自然有助于网络减少过度拟合,因为层中没有一个节点负责预测某个类、对象、边缘或角。

接下来是我们的两组 (CONV => RELU) * 2 => POOL 块:

(CONV => RELU) * 2 => POOL

x = Conv2D(64, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = Conv2D(64, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(2, 2))(x)

x = Dropout(0.25)(x)

(CONV => RELU) * 2 => POOL

x = Conv2D(128, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = Conv2D(128, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(2, 2))(x)

x = Dropout(0.25)(x)

此代码块中过滤器、内核和池大小的变化协同工作,以逐渐减小空间大小但增加深度。

让我们将它与 FC => RELU 层结合起来:

define a branch of output layers for the number of different

clothing categories (i.e., shirts, jeans, dresses, etc.)

x = Flatten()(x)

x = Dense(256)(x)

x = Activation(“relu”)(x)

x = BatchNormalization()(x)

x = Dropout(0.5)(x)

x = Dense(numCategories)(x)

x = Activation(finalAct, name=“category_output”)(x)

return the category prediction sub-network

return x

最后一个激活层是完全连接的,并且具有与我们的 numCategories 相同数量的神经元/输出。

请注意,我们将最终激活层命名为“category_output”。这很重要,因为我们稍后将在 train.py 中按名称引用该层。

让我们定义用于构建多输出分类网络的第二个函数。 这个名为 build_color_branch ,顾名思义,它负责对图像中的颜色进行分类:

@staticmethod

def build_color_branch(inputs, numColors, finalAct=“softmax”,

chanDim=-1):

CONV => RELU => POOL

x = Conv2D(16, (3, 3), padding=“same”)(inputs)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(3, 3))(x)

x = Dropout(0.25)(x)

CONV => RELU => POOL

x = Conv2D(32, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(2, 2))(x)

x = Dropout(0.25)(x)

CONV => RELU => POOL

x = Conv2D(32, (3, 3), padding=“same”)(x)

x = Activation(“relu”)(x)

x = BatchNormalization(axis=chanDim)(x)

x = MaxPooling2D(pool_size=(2, 2))(x)

x = Dropout(0.25)(x)

我们的 build_color_branch 参数与 build_category_branch 基本相同。

我们用 numColors (不同于 numCategories )来区分最后一层的激活次数。

这一次,我们不会应用 Lambda 灰度转换层,因为我们实际上关心的是网络这个区域的颜色。 如果我们转换为灰度,我们将丢失所有颜色信息!

网络的这个分支比服装类别分支浅得多,因为手头的任务要简单得多。 我们要求子网络完成的只是对颜色进行分类——子网络不必那么深。

就像我们的类别分支一样,我们有第二个完全连接的头部。 让我们构建 FC => RELU 块来完成:

define a branch of output layers for the number of different

colors (i.e., red, black, blue, etc.)

x = Flatten()(x)

x = Dense(128)(x)

x = Activation(“relu”)(x)

x = BatchNormalization()(x)

x = Dropout(0.5)(x)

x = Dense(numColors)(x)

x = Activation(finalAct, name=“color_output”)(x)

return the color prediction sub-network

return x

为了区分颜色分支的最终激活层,我提供了 name=“color_output” 关键字参数。我们将在训练脚本中引用名称。 我们构建 FashionNet 的最后一步是将我们的两个分支放在一起并构建最终架构:

@staticmethod

def build(width, height, numCategories, numColors,

finalAct=“softmax”):

initialize the input shape and channel dimension (this code

assumes you are using TensorFlow which utilizes channels

last ordering)

inputShape = (height, width, 3)

chanDim = -1

construct both the “category” and “color” sub-networks

inputs = Input(shape=inputShape)

categoryBranch = FashionNet.build_category_branch(inputs,

numCategories, finalAct=finalAct, chanDim=chanDim)

colorBranch = FashionNet.build_color_branch(inputs,

numColors, finalAct=finalAct, chanDim=chanDim)

create the model using our input (the batch of images) and

two separate outputs – one for the clothing category

branch and another for the color branch, respectively

model = Model(

inputs=inputs,

outputs=[categoryBranch, colorBranch],

name=“fashionnet”)

return the constructed network architecture

return model

定义build函数,有5个参数。 build 函数假设我们使用的是 TensorFlow 和最后一次排序的通道。

inputShape 元组是明确排序的 (height, width, 3) ,其中 3 代表 RGB 通道。 如果您想使用 TensorFlow 以外的后端,您需要修改代码以:(1) 正确地为您的后端设置正确的通道顺序,以及 (2) 实现一个自定义层来处理 RGB 到灰度的转换。 从那里,我们定义了网络的两个分支,然后将它们放在一个模型中。 关键是我们的分支有一个共同的输入,但有两个不同的输出(服装类型和颜色分类)。

实现多输出和多损失训练脚本

========================================================================

现在我们已经实现了我们的 FashionNet 架构,让我们训练它! 准备好后,打开 train.py 并深入研究:

set the matplotlib backend so figures can be saved in the background

import matplotlib

matplotlib.use(“Agg”)

import the necessary packages

from tensorflow.keras.optimizers import Adam

from tensorflow.keras.preprocessing.image import img_to_array

from sklearn.preprocessing import LabelBinarizer

from sklearn.model_selection import train_test_split

from model.fashionnet import FashionNet

from imutils import paths

import matplotlib.pyplot as plt

import numpy as np

import argparse

import random

import pickle

import cv2

import os

我们首先为脚本导入必要的包。

从那里我们解析我们的命令行参数:

construct the argument parser and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument(“-d”, “–dataset”, required=True,

help=“path to input dataset (i.e., directory of images)”)

ap.add_argument(“-m”, “–model”, required=True,

help=“path to output model”)

ap.add_argument(“-l”, “–categorybin”, required=True,

help=“path to output category label binarizer”)

ap.add_argument(“-c”, “–colorbin”, required=True,

help=“path to output color label binarizer”)

ap.add_argument(“-p”, “–plot”, type=str, default=“output”,

help=“base filename for generated plots”)

args = vars(ap.parse_args())

我们很快就会看到如何运行训练脚本。 现在,只知道 --dataset 是我们数据集的输入文件路径, --model 、 --categorybin 、 --colorbin 都是三个输出文件路径。

或者,您可以使用 --plot 参数为生成的精度/损失图指定基本文件名。

现在,让我们建立四个重要的训练变量:

initialize the number of epochs to train for, initial learning rate,

batch size, and image dimensions

EPOCHS = 50

INIT_LR = 1e-3

BS = 32

IMAGE_DIMS = (96, 96, 3)

我们设置以下变量:

  1. EPOCHS : epoch 数设置为 50 。通过实验,我发现 50 个 epoch 生成的模型具有低损失并且没有过拟合到训练集(或尽可能不过拟合)。

  2. INIT_LR :我们的初始学习率设置为 0.001 。学习率控制着我们沿着梯度所做的“步骤”。较小的值表示较小的步长,较大的值表示较大的步长。我们很快就会看到我们将使用 Adam 优化器,同时随着时间的推移逐渐降低学习率。

  3. BS:我们将以 32 的批量大小训练我们的网络。

  4. IMAGE_DIMS :所有输入图像都将调整为 96 x 96,具有 3 个通道 (RGB)。我们正在使用这些维度进行训练,我们的网络架构输入维度也反映了这些维度。当我们在后面的部分中使用示例图像测试我们的网络时,测试维度必须与训练维度匹配。

我们的下一步是抓取我们的图像路径并随机打乱它们。我们还将初始化列表以分别保存图像本身以及服装类别和颜色:

grab the image paths and randomly shuffle them

print(“[INFO] loading images…”)

imagePaths = sorted(list(paths.list_images(args[“dataset”])))

random.seed(42)

random.shuffle(imagePaths)

initialize the data, clothing category labels (i.e., shirts, jeans,

dresses, etc.) along with the color labels (i.e., red, blue, etc.)

data = []

categoryLabels = []

colorLabels = []

随后,我们将遍历 imagePaths 、预处理并填充 data 、 categoryLabels 和 colorLabels 列表:

loop over the input images

for imagePath in imagePaths:

load the image, pre-process it, and store it in the data list

image = cv2.imread(imagePath)

image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0]))

image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

image = img_to_array(image)

data.append(image)

extract the clothing color and category from the path and

update the respective lists

(color, cat) = imagePath.split(os.path.sep)[-2].split(“_”)

categoryLabels.append(cat)

colorLabels.append(color)

我们开始遍历我们的 imagePaths。

在循环内部,我们加载图像并将其调整为 IMAGE_DIMS 。 我们还将图像从 BGR 排序转换为 RGB。 我们为什么要进行这种转换? 回想一下我们在 build_category_branch 函数中的 FashionNet 类,我们在 Lambda 函数/层中使用了 TensorFlow 的 rgb_to_grayscale 转换。 因此,我们首先转换为 RGB,并最终将预处理后的图像附加到数据列表中。

接下来,仍然在循环内部,我们从当前图像所在的目录名称中提取颜色和类别标签。

要查看此操作,只需在终端中启动 Python,并提供一个示例 imagePath 进行实验,如下所示:

$ python

import os

imagePath = “dataset/red_dress/00000000.jpg”

(color, cat) = imagePath.split(os.path.sep)[-2].split(“_”)

color

‘red’

cat

‘dress’

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
img

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

70aad5355a2c5eeff0.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
[外链图片转存中…(img-CklJCm9w-1711879092229)]

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值