PaddleHub 轻量级图像分类实战:ghostnet_x1_3_imagenet 模块的安装、推理、Fine-tune 与 Serving 部署全指南

PaddleHub 轻量级图像分类实战:ghostnet_x1_3_imagenet 模块的安装、推理、Fine-tune 与 Serving 部署全指南

【免费下载链接】PaddleFormers PaddleFormers is an easy-to-use library of pre-trained large language model zoo based on PaddlePaddle. 【免费下载链接】PaddleFormers 项目地址: https://gitcode.com/gh_mirrors/pa/PaddleFormers

本文以 PaddleFormers 仓库中的 ghostnet_x1_3_imagenet 图像分类模块为主线,系统讲解 GhostNet 轻量级网络的模块结构、环境安装、命令行与 Python API 预测、基于 Flowers 数据集的 Fine-tune 全流程,以及 PaddleHub Serving 在线服务化部署。读完本文,你将能够独立完成从模型安装、单张图片分类预测,到自定义数据集微调并部署为 HTTP 分类服务的完整链路。

一、模型基本信息与适用场景

ghostnet_x1_3_imagenet 是 PaddleHub 提供的一个图像分类模块,其核心信息如下:

模型名称ghostnet_x1_3_imagenet
类别图像-图像分类
网络GhostNet
数据集ImageNet-2012
是否支持 Fine-tuning是
模型大小43MB
指标-
最新更新日期2021-09-14

GhostNet 是华为在 2020 年提出的全新轻量级网络结构,其核心思想是引入 ghost 模块(Ghost Module):传统深度网络产生的特征图中存在大量冗余,Ghost 模块通过"先做少量固有卷积生成一部分特征图,再对这部分特征图施加廉价线性变换(cheap operation)生成其余特征图"的方式,显著缓解了特征的冗余计算问题,从而大幅减少网络参数和计算量。x1_3 表示通道数缩放系数(width multiplier)为 1.3,属于在标准 GhostNet 基础上加宽通道的变体,在轻量与精度之间取得平衡。

在 PaddleFormers 仓库中,该模块的完整源码位于 module.py,模块元信息通过 @moduleinfo 装饰器声明(name="ghostnet_x1_3_imagenet"、type="CV/classification"、version="1.0.0"),继承自 ImageClassifierModule(定义于 cv_module.py),因而天然具备 predict、training_step、serving_method、run_cmd 等分类模块的标准能力。

二、GhostNet 网络结构的源码级解析

结合 module.py 的实现,可以清晰看到该模块的组成单元与数据流。

2.1 GhostModule:核心"幽灵"模块

GhostModule 是网络的基本构建块(module.py 第 88-114 行):

class GhostModule(nn.Layer):
    def __init__(self, in_channels, output_channels, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True, name=None):
        super(GhostModule, self).__init__()
        init_channels = int(math.ceil(output_channels / ratio))
        new_channels = int(init_channels * (ratio - 1))
        self.primary_conv = ConvBNLayer(...)      # 主卷积:生成 init_channels 个特征图
        self.cheap_operation = ConvBNLayer(      # 廉价操作:深度可分离卷积生成其余特征图
            ..., groups=init_channels, ...)
    def forward(self, inputs):
        x = self.primary_conv(inputs)
        y = self.cheap_operation(x)
        out = paddle.concat([x, y], axis=1)      # 沿通道拼接
        return out

其原理可拆解为:

  • primary_conv:一个 1×1(或指定 kernel_size)普通卷积,输出通道数为 ceil(output_channels / ratio),ratio 默认为 2;
  • cheap_operation:一个 kernel_size 为 3(dw_size)、groups=init_channels 的深度可分离卷积,在每张主特征图上独立做廉价变换,生成剩余 init_channels * (ratio - 1) 个通道;
  • 最后将两部分在通道维拼接(paddle.concat),得到完整的 output_channels 通道输出。

由于廉价变换的计算成本远低于普通卷积,整体 FLOPs 和参数量被显著压缩,这正是 GhostNet 轻量的根本原因。

2.2 GhostBottleneck:倒残差瓶颈

GhostBottleneck(module.py 第 117-180 行)将两个 GhostModule 组合成一个类似 MobileNetV2 的倒残差瓶颈结构,并支持可选的下采样与 SE 注意力:

  • ghost_module_1:1×1 升维(hidden_dim 通道),relu 激活;
  • 当 stride == 2 时,插入一个 groups=hidden_dim 的深度可分离卷积完成空间下采样;
  • 当 use_se 为真时,插入 SEBlock(squeeze-and-excitation,先全局平均池化、两层线性映射、paddle.clip(x, min=0, max=1) 限幅得到通道权重,再与输入逐元素相乘);
  • ghost_module_2:1×1 降维回 output_channels,无 relu;
  • 残差捷径:当 stride == 1 且通道数不变时直接恒等映射,否则通过深度可分离卷积 + 1×1 卷积对齐通道后与主分支相加。

2.3 网络骨架:cfgs 配置与 width multiplier

GhostNet 类中定义了一份结构配置表 self.cfgs(module.py 第 209-227 行),每行格式为 [kernel_size, expand_size, output_channels, use_se, stride],共 16 个瓶颈层;同时设置 self.scale = 1.3,并通过 _make_divisible 函数将所有层的通道数规整为 4 的倍数(保证硬件友好的对齐)。头部由 3×3 stride=2 的 conv1、conv_last、全局平均池化、1×1 卷积升维到 1280、Dropout(0.2) 和输出维度为 class_dim 的全连接 fc_1 组成。

class_dim 的来源有两个分支:

  • 若构造时传入 label_list,则以 len(label_list) 作为分类数;
  • 否则读取模块目录下的 label_list.txt,该文件包含 ImageNet-2012 的 1000 个类别名(如 tench、goldfish、daisy 等),class_dim = 1000。

forward 的返回值为 (x, feature),其中 x 是分类 logits,feature 是池化后的特征向量,这一设计同时支持分类输出与特征提取场景。

三、环境依赖与模块安装

3.1 环境依赖

运行本模块需要满足以下版本要求:

  • paddlepaddle >= 2.0.0
  • paddlehub >= 2.0.0

3.2 安装模块

使用 PaddleHub 命令行一键安装:

$ hub install ghostnet_x1_3_imagenet

安装成功后,可通过 hub show ghostnet_x1_3_imagenet 查看模块信息,或直接进入下一节的预测环节。如您在安装过程中遇到环境问题,可参考官方安装指引:零基础 Windows 安装、零基础 Linux 安装、零基础 MacOS 安装。

四、模型 API 预测

该模块继承自 ImageClassifierModule,其 predict 实现(cv_module.py 第 82-122 行)会先调用模块内置的 transforms 预处理(Resize((256, 256)) → CenterCrop(224) → ImageNet 均值/方差归一化,to_rgb=True),再在 paddle.no_grad() 下前向得到 logits,经 F.softmax 后按概率降序取 top_k 个类别,返回 {类别名: 置信度} 形式的字典列表。

4.1 命令行预测

$ hub run ghostnet_x1_3_imagenet --input_path "/PATH/TO/IMAGE" --top_k 5
  • --input_path:必填,待分类图片路径;
  • --top_k:可选,输出概率最高的前 k 个类别,默认值为 1。

命令行入口由 ImageClassifierModule.run_cmd(cv_module.py 第 139-157 行)解析上述参数并调用 predict 完成。

4.2 Python 代码预测

import paddle
import paddlehub as hub

if __name__ == '__main__':
    model = hub.Module(name='ghostnet_x1_3_imagenet')
    result = model.predict(['flower.jpg'])

hub.Module(name='ghostnet_x1_3_imagenet') 会从本地加载已安装的模块及其预训练权重(源码中通过 paddle.load(os.path.join(self.directory, 'model.pdparams')) 加载),predict 接受图片路径或 BGR 格式的 np.ndarray 列表,并支持 batch_size 与 top_k 参数。

五、基于 Flowers 数据集的 Fine-tune

该模块支持 Fine-tuning,仓库在 demo/image_classification/train.py 中提供了完整的训练脚本模板,将 name 替换为 ghostnet_x1_3_imagenet 即可复用。整体流程分为五个步骤。

Step 1:定义数据预处理方式

import paddlehub.vision.transforms as T

transforms = T.Compose([T.Resize((256, 256)),
                        T.CenterCrop(224),
                        T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])],
                       to_rgb=True)

transforms 数据增强模块定义了丰富的数据预处理方式,用户可按照需求替换为自己需要的数据预处理方式。这里的组合(缩放 256×256 → 中心裁剪 224×224 → 按 ImageNet 统计值归一化)与模块内置的预测预处理保持一致,保证微调与推理的输入分布一致。

Step 2:下载数据集并使用

from paddlehub.datasets import Flowers

flowers = Flowers(transforms)
flowers_validate = Flowers(transforms, mode='val')

参数说明:

  • transforms:数据预处理方式;
  • mode:选择数据模式,可选项有 train、test、val,默认为 train。

Flowers 数据集的实现位于 paddlehub/datasets/flowers.py:类上标注了 @download_data(url='https://bj.bcebos.com/paddlehub-dataset/flower_photos.tar.gz') 装饰器,hub.datasets.Flowers() 会自动从网络下载数据集并解压到用户目录下 $HOME/.paddlehub/dataset 目录,num_classes = 5,三种 mode 分别对应 train_list.txt、test_list.txt、validate_list.txt 文件索引,标签类别依次为 roses、tulips、daisy、sunflowers、dandelion。

Step 3:加载预训练模型

model = hub.Module(name="ghostnet_x1_3_imagenet",
                   label_list=["roses", "tulips", "daisy", "sunflowers", "dandelion"])
  • name:选择预训练模型的名字;
  • label_list:设置输出分类类别,默认为 ImageNet-2012 的 1000 个类别(即 label_list.txt)。传入自定义 label_list 后,class_dim 会被设为 5,分类头 fc_1 相应重建,预训练骨干权重仍被加载,从而实现迁移学习。

Step 4:选择优化策略和运行配置

optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
trainer = Trainer(model, optimizer, checkpoint_dir='img_classification_ckpt')
trainer.train(flowers, epochs=100, batch_size=32, eval_dataset=flowers_validate, save_interval=1)

Trainer 主要控制 Fine-tune 的训练,其实现位于 paddlehub/finetune/trainer.py,包含以下可控制参数:

  • model:被优化模型;
  • optimizer:优化器选择;
  • use_gpu:是否使用 GPU 运行,默认 False(源码中通过 paddle.set_device('gpu')/paddle.set_device('cpu') 切换);
  • use_vdl:是否使用 VisualDL 可视化训练过程,默认 True,日志写入 checkpoint_dir/visualization;
  • checkpoint_dir:保存模型参数的地址,默认值为 ckpt_{time.time()},Trainer 初始化时会自动扫描该目录下 epoch_* 检查点实现断点续训;
  • compare_metrics:保存最优模型的衡量指标比较函数,默认取验证指标字典第一个键、数值越大越优。

trainer.train 主要控制具体的训练过程,包含以下可控制参数:

  • train_dataset:训练时所用的数据集;
  • epochs:训练轮数;
  • batch_size:训练的批大小,如果使用 GPU,请根据实际情况调整 batch_size;
  • num_workers:数据加载子进程数量,默认为 0;
  • eval_dataset:验证集,非空时 Trainer 每 save_interval 轮执行一次验证(源码中要求模型具备 validation_step 方法,ImageClassifierModule 已实现,返回 loss 与 acc 指标);
  • log_interval:打印日志的间隔,单位为执行批训练的次数,默认 10;
  • save_interval:保存模型的间隔频次,单位为执行训练的轮数,默认 10;
  • collate_fn:自定义 mini-batch 拼接函数,默认按第 0 维 stack。

训练过程中,Trainer 会:按 log_interval 打印 Epoch/Step/loss/acc/lr/step/sec/ETA 日志并同步到 VisualDL;在每个 save_interval 轮末先做验证,若 compare_metrics 判定指标更优,则将模型保存到 ${checkpoint_dir}/best_model(含 model.pdparams 与 model.pdopt),同时把周期性检查点保存到 epoch_{n} 目录,并自动恢复上次的 metrics.pkl 与 best_metrics。

模型预测(加载微调产物)

当完成 Fine-tune 后,Fine-tune 过程在验证集上表现最优的模型会被保存在 ${CHECKPOINT_DIR}/best_model 目录下,其中 ${CHECKPOINT_DIR} 目录为 Fine-tune 时所选择的保存 checkpoint 的目录。我们使用该模型来进行预测:

import paddle
import paddlehub as hub

if __name__ == '__main__':
    model = hub.Module(name='ghostnet_x1_3_imagenet',
                       label_list=["roses", "tulips", "daisy", "sunflowers", "dandelion"],
                       load_checkpoint='/PATH/TO/CHECKPOINT')
    result = model.predict(['flower.jpg'])

load_checkpoint 指向微调产物的路径(源码中通过 paddle.load(load_checkpoint) 加载并 set_dict 覆盖权重),从而使用微调后的参数进行推理。

NOTE: 进行预测时,所选择的 module、checkpoint_dir、dataset 必须和 Fine-tune 所用的一样,否则类别对齐与权重加载都会出错。

六、服务部署:PaddleHub Serving

PaddleHub Serving 可以部署一个在线分类任务服务,将模型封装为 HTTP API 供外部系统调用。

第一步:启动 PaddleHub Serving

$ hub serving start -m ghostnet_x1_3_imagenet

这样就完成了一个分类任务服务化 API 的部署,默认端口号为 8866。

NOTE: 如使用 GPU 预测,则需要在启动服务之前,设置 CUDA_VISIBLE_DEVICES 环境变量,否则不用设置。

服务端实际上会调用模块的 serving_method(cv_module.py 第 124-137 行):接收 base64 编码的图片列表与 top_k 参数,解码后转给 predict,并把 numpy 置信度转换为 Python float 后以 {"data": [{"类别": 置信度}, ...]} 结构返回。

第二步:发送预测请求

配置好服务端后,以下数行代码即可实现发送预测请求、获取预测结果:

import requests
import json
import cv2
import base64
import numpy as np

def cv2_to_base64(image):
    data = cv2.imencode('.jpg', image)[1]
    return base64.b64encode(data.tostring()).decode('utf8')

def base64_to_cv2(b64str):
    data = base64.b64decode(b64str.encode('utf8'))
    data = np.fromstring(data, np.uint8)
    data = cv2.imdecode(data, cv2.IMREAD_COLOR)
    return data

# 发送HTTP请求
org_im = cv2.imread('/PATH/TO/IMAGE')
data = {'images': [cv2_to_base64(org_im)], 'top_k': 2}
headers = {"Content-type": "application/json"}
url = "http://127.0.0.1:8866/predict/ghostnet_x1_3_imagenet"
r = requests.post(url=url, headers=headers, data=json.dumps(data))
data = r.json()["results"]['data']

请求体中 images 为 base64 编码的图片列表,top_k 控制返回的候选类别数;响应中的 results.data 即每张图片按置信度降序排列的类别预测结果。

七、更新历史

  • 1.0.0:初始发布,提供基于 ImageNet-2012 预训练的 GhostNet(width=1.3)图像分类能力。

延伸阅读

【免费下载链接】PaddleFormers PaddleFormers is an easy-to-use library of pre-trained large language model zoo based on PaddlePaddle. 【免费下载链接】PaddleFormers 项目地址: https://gitcode.com/gh_mirrors/pa/PaddleFormers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值