基于PaddleClas的人物年龄分类项目

目录

一、任务概述

二、算法研发

2.1 下载数据集

2.2 数据集预处理

2.3 安装PaddleClas套件

2.4 算法训练

2.5 静态图导出

2.6 静态图推理

三、小结


一、任务概述

    最近遇到个需求,需要将图像中的人物区分为成人和小孩,这是一个典型的二分类问题,打算采用飞桨的图像分类套件PaddleClas来完成算法研发。本文记录相关流程。

二、算法研发

2.1 下载数据集

    本文采用MaGaAge_Asian数据集,该数据集主要由亚洲人图片组成,训练集包含40000张图像,验证集包含3495张图像,每张图像都有对应的年龄真值,所有图像均处理成了统一的大小,宽178像素,高218像素。

数据集地址下载链接。数据集部分示例如下图所示:

    该数据集本意是用来做年龄预测的,属于一个数值回归任务,本文将其变成二分类任务,以13岁年龄为界限,小于该年龄的属于小孩,大于该年龄的属于成人。这里之所以选择13岁,因为这个任务是需要筛选出长得很“像”小孩的小孩,13岁以上的青少年很多本身已经长的像成人了,因此,选择13岁作为分界线。

    下面首先对该数据集进行处理。

2.2 数据集预处理

    MaGaAge_Asian数据集每张图片对应的人物年龄存放在list文件夹的两个文件中,其中train_age.txt存放训练集对应的年龄真值,test_age.txt存放验证集对应的年龄真值。下面要写一个脚本,将所有小于13岁的图片移动到一个文件夹内,所有大于等于13岁的图片移动到另一个文件夹内。

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件        :split_asian.py
@说明        :拆分megaage_asian数据集,将小于13岁的移动到一个文件夹,大于等于13岁的移动到另一个文件夹
@时间        :2024/07/16 09:11:16
@作者        :Bin Qian
@版本        :1.0
'''


import os
import cv2

thr = 13 # 年龄阈值

# 读取年龄列表
agefile = 'megaage_asian/list/test_age.txt'
f=open(agefile) 
ageLst = f.read().splitlines()
f.close() 

# 读取图像
imgFolder = 'megaage_asian/val'
imgnames = os.listdir(imgFolder)
index = 50000
for imgname in imgnames:
    imgPath = os.path.join(imgFolder,imgname)
    img = cv2.imread(imgPath)
    if img is None:
        continue
    print(imgPath)
    imgindex = int(imgname.split('.')[0])
    age = int(ageLst[imgindex-1])
    if age < thr:
        dstFolder = 'ageclas/child'
    else:
        dstFolder = 'ageclas/adult'
    
    savePath = os.path.join(dstFolder,str(index)+'_asian.jpg')
    cv2.imwrite(savePath,img)
    index += 1
print('完成')

值得注意的是MaGaAge_Asian数据集中有很多质量较差的图像,这些“脏”图像会影响学习效果,最好手工检查这些数据并将其剔除。

另外,为了能够取得更好的效果,本文从互联网和FFHQ数据集里面再挑选出一些小孩和成人的照片进行补充。部分代码如下:

import os
import cv2

# 读取图像
imgFolder = 'adult'
imgnames = os.listdir(imgFolder)
index = 1
for imgname in imgnames:
    imgPath = os.path.join(imgFolder,imgname)
    img = cv2.imread(imgPath)
    if img is None:
        continue
    print(imgPath)
    dstFolder = 'ageclas/adult'
    savePath = os.path.join(dstFolder,str(index)+'_data.jpg')
    cv2.imwrite(savePath,img)
    index += 1
print('完成')

补充完整后,最后对整理好的数据集进行拆分,并且获得对应的文件列表:

# 导入系统库
import os
import random
import cv2


# 定义参数
img_folder = 'ageclas'
trainlst = 'train_list.txt'
vallst = 'val_list.txt'
ratio = 0.95 # 训练集占比
labellst='label.txt'
 

def writeLst(lstpath,namelst):
    '''
    保存文件列表
    '''
    print('正在写入 '+lstpath)
    random.shuffle (namelst)
    # 写入训练样本文件
    f=open(lstpath, 'a', encoding='utf-8')
    for i in range(len(namelst)):
        text = namelst[i]+'\n'
        f.write(text)
    f.close()
    print(lstpath+ '已完成写入')
    

 
def main():
    '''
    主函数
    '''
    # 查找文件夹
    folderlst = os.listdir(img_folder)
    print('共找到 %d 个文件夹' % len(folderlst))
    
    # 循环处理
    trainnamelst = list()
    valnamelst = list()
    labelnamelst = list()
    for i in range(len(folderlst)):
        class_name = folderlst[i]
        class_label = i
        print('开始处理 '+class_name+' 文件夹')
        
        # 获取子文件夹文件列表
        filenamelst = os.listdir(os.path.join(img_folder,class_name))
        totalNum = len(filenamelst)
        print('当前文件夹图片数量为: ' + str(totalNum)) 
        trainNum = int(ratio*totalNum)
        text =  str(class_label)+ ' ' + class_name
        labelnamelst.append(text)
        
        # 检查并校验图像
        for j in range(totalNum):
            imgpath = os.path.join(img_folder,class_name,filenamelst[j])
            img = cv2.imread(imgpath, cv2.IMREAD_COLOR)
            if img is None:
                continue
            text = imgpath + ' ' + str(class_label)
            if j <= trainNum: 
                trainnamelst.append(text)
            else:
                valnamelst.append(text)
                
    writeLst(trainlst,trainnamelst)
    writeLst(vallst,valnamelst)   
    writeLst(labellst,labelnamelst)     
    print('全部完成')


if __name__ == '__main__':
    '''程序入口'''
    main()

运行后会生成train_lst.txt、val_lst.txt以及label.txt三个文件,有了这三个文件就可以使用PaddleClas套件进行算法研发了。

2.3 安装PaddleClas套件

git clone https://gitee.com/paddlepaddle/PaddleClas.git
cd PaddleClas
sudo python setup.py install

2.4 算法训练

在PaddleClas目录下新建一个配置文件config_lcnet.yaml,采用PPLCNet_x0_5模型来训练,配置文件代码如下:

# global configs
Global:
  checkpoints: null
  pretrained_model: null
  output_dir: ./output/
  device: gpu
  save_interval: 5
  eval_during_train: True
  eval_interval: 5
  epochs: 200
  print_batch_step: 10
  use_visualdl: True
  # used for static mode and model export
  image_shape: [3, 224, 224]
  save_inference_dir: ./output/inference
# model architecture
Arch:
  name: PPLCNet_x0_5
  class_num: 2
 
# loss function config for traing/eval process
Loss:
  Train:
    - CELoss:
        weight: 1.0
        epsilon: 0.1
  Eval:
    - CELoss:
        weight: 1.0


Optimizer:
  name: Momentum
  momentum: 0.9
  lr:
    name: Cosine
    learning_rate: 0.8
    warmup_epoch: 5
  regularizer:
    name: 'L2'
    coeff: 0.00003


# data loader for train and eval
DataLoader:
  Train:
    dataset:
      name: ImageNetDataset
      image_root: ../process_data/
      cls_label_path: ../process_data/train_list.txt
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: [224,224]
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''

    sampler:
      name: DistributedBatchSampler
      batch_size: 64
      drop_last: False
      shuffle: True
    loader:
      num_workers: 4
      use_shared_memory: True

  Eval:
    dataset: 
      name: ImageNetDataset
      image_root: ../process_data/
      cls_label_path: ../process_data/val_list.txt
      transform_ops:
        - DecodeImage:
            to_rgb: True
            channel_first: False
        - ResizeImage:
            size: [224,224]
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''
    sampler:
      name: DistributedBatchSampler
      batch_size: 64
      drop_last: False
      shuffle: False
    loader:
      num_workers: 4
      use_shared_memory: True

Infer:
  infer_imgs: "../testimgs/10.jpg"
  batch_size: 1
  transforms:
    - DecodeImage:
        to_rgb: True
        channel_first: False
    - ResizeImage:
        size: [224,224]
    - NormalizeImage:
        scale: 1.0/255.0
        mean: [0.485, 0.456, 0.406]
        std: [0.229, 0.224, 0.225]
        order: ''
    - ToCHWImage:
  PostProcess:
    name: Topk
    topk: 1
    class_id_map_file: "../process_data/label.txt"

Metric:
  Train:
    - TopkAcc:
        topk: [1]
  Eval:
    - TopkAcc:
        topk: [1]

然后使用下面的命令进行训练:

export CUDA_VISIBLE_DEVICES=0,1
python3 -m paddle.distributed.launch \
    --gpus="0,1" \
    tools/train.py \
        -c config_lcnet.yaml 

训练完成后可以使用下面的命令可视化查看训练结果:

visualdl --logdir results/vdl

运行效果如下:

可以看到,基本在epoch=100以后就收敛了,最高top1准确率达到97.5%,准确率还是比较高的。

下面可以使用动态图对单张图像进行测试,命令如下:

python3 tools/infer.py -c config_lcnet.yaml -o Global.pretrained_model=output/PPLCNet_x0_5/best_model

输出如下:

[{'class_ids': [1], 'scores': [0.93522], 'file_name': '../testimgs/10.jpg', 'label_names': ['adult']}]

2.5 静态图导出

为了方便后面进行模型部署,将训练好的最佳模型进行静态图导出。具体命令如下:

python3 tools/export_model.py \
    -c config_lcnet.yaml \
    -o Global.pretrained_model=output/PPLCNet_x0_5/best_model \
    -o Global.save_inference_dir=output/inference

导出的静态图模型存放在output/inference文件夹下面,整个模型参数加起来不超过3M,因此可以看出这个训练好的PPLCNet_x0_5模型是一个非常轻量级的模型。

2.6 静态图推理

下面使用静态图来进行推理。在推理前先使用visualdl工具查看下静态图模型的输入和输出,这将为编写推理脚本奠定基础。

可以看到,输入是[batch,3,224,224]的float型图像数据,输出是[batch,2]的float型数据。尤其是输出的两个值,代表的是两个类别的概率。

有了上面的分析,下面可以用PaddleInference写一个推理脚本infer.py:

import cv2
import numpy as np
from paddle.inference import create_predictor
from paddle.inference import Config as PredictConfig

# 加载静态图模型
model_path = "./output/inference/inference.pdmodel"
params_path = "./output/inference/inference.pdiparams"
pred_cfg = PredictConfig(model_path, params_path)
pred_cfg.enable_memory_optim()  # 启用内存优化
pred_cfg.switch_ir_optim(True)
pred_cfg.enable_use_gpu(500, 0)  # 启用GPU推理
predictor = create_predictor(pred_cfg)  # 创建PaddleInference推理器

# 解析模型输入输出
input_names = predictor.get_input_names()
input_handle = {}
for i in range(len(input_names)):
    input_handle[input_names[i]] = predictor.get_input_handle(input_names[i])
output_names = predictor.get_output_names()
output_handle = predictor.get_output_handle(output_names[0])

# 图像预处理
img = cv2.imread("../testimgs/10.jpg", flags=cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_AREA)
img = img.astype(np.float32)
PIXEL_MEANS =(0.485, 0.456, 0.406)    # RGB格式的均值和方差
PIXEL_STDS = (0.229, 0.224, 0.225)
img/=255.0
img-=np.array(PIXEL_MEANS)
img/=np.array(PIXEL_STDS)
img = np.transpose(img[np.newaxis, :, :, :], (0, 3, 1, 2))

# 预测
input_handle["x"].copy_from_cpu(img)
predictor.run()
results = output_handle.copy_to_cpu()

# 后处理
results = results.squeeze(0)
if results[0]>results[1]:
    print('小孩'+"  "+str(results[0]))
else:
    print('大人'+"  "+str(results[1]))

从网上随便找两张照片,运行效果如下:

输出结果:

小孩  0.7256172

输出结果:

大人  0.9533998

可以看到,推理效果还是比较满意的。

三、小结

本文以项目为主线,使用了PaddleClas算法套件解决了年龄分类问题。后续读者如果想要深入学习PaddlePaddle(飞桨)及相关算法套件,可以关注我的书籍(链接)。

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

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

相关文章

【数据结构】手把手教你单链表(c语言)(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 1.单链表的概念与结构 2.单链表的结构定义 3.单链表的实现 3.1 单链表的方法声明 3.2 单链表方法实现 3.2.1 打印链表 3.2.2 创建新…

C++ | Leetcode C++题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; class Solution { public:int hIndex(vector<int>& citations) {int n citations.size();int left 0, right n - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > n - mid) {right m…

使用Diffusion Models进行街景视频生成

Diffusion Models专栏文章汇总:入门与实战 前言:街景图生成相当有挑战性,目前的文本到视频的方法仅限于生成有限范围的场景的短视频,文本到3D的方法可以生成单独的对象但不是整个城市。除此之外街景图对一致性的要求相当高,这篇博客介绍如何用Diffusion Models执行街景图生…

JAW:一款针对客户端JavaScript的图形化安全分析框架

关于JAW JAW是一款针对客户端JavaScript的图形化安全分析框架&#xff0c;该工具基于esprima解析器和EsTree SpiderMonkey Spec实现其功能&#xff0c;广大研究人员可以使用该工具分析Web应用程序和基于JavaScript的客户端程序的安全性。 工具特性 1、动态可扩展的框架&#x…

Unity UGUI 之 图集

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是图集 精灵图…

C语言玩一下标准输出——颜色、闪烁、加粗、下划线属性

文章目录 C语言玩一下标准输出——颜色、闪烁、加粗、下划线属性转换Tip切换内容介绍显示方式字体色背景色 常用光标控制附示例和运行结果 C语言玩一下标准输出——颜色、闪烁、加粗、下划线属性 标准输出格式其属性可控制&#xff0c;控制由一系列的控制码指定。标准输出函数可…

一个C++模板工厂的编译问题的解决。针对第三方库的构造函数以及追加了的对象构造函数。牵扯到重载、特化等

一窥模板的替换和匹配方式&#xff1a;偏特化的参数比泛化版本的还要多&#xff1a;判断是不是std::pair&#xff1c;,&#xff1e;。_stdpair模板参数太多-CSDN博客 简介 在一个项目里&#xff0c;调用了第三封的库&#xff0c;这个库里面有个类用的很多&#xff0c;而且其构…

Godot入门 03世界构建1.0版

在game场景&#xff0c;删除StaticBody2D节点&#xff0c;添加TileMap节点 添加TileSet图块集 添加TileSet源 拖动图片到图块&#xff0c;自动创建图块 使用橡皮擦擦除。取消橡皮擦后按住Shift创建大型图块。 进入选择模式&#xff0c;TileMap选择绘制&#xff0c;选中图块后在…

zookeeper开启SASL权限认证

目录 一、SASL介绍 二、使用 SASL 进行身份验证 2.1 服务器到服务器的身份验证 2.2 客户端到服务器身份验证 三、验证功能 一、SASL介绍 默认情况下&#xff0c;ZooKeeper 不使用任何形式的身份验证并允许匿名连接。但是&#xff0c;它支持 Java 身份验证与授权服务(JAAS)…

单元测试的最佳实践

整体架构 合适的架构可以提升可测试性。比如菱形对称架构的模块化和解耦特性使得系统各个部分可以独立进行单元测试。这不仅提高了测试的效率&#xff0c;还能够减少测试的依赖性&#xff0c;提高测试准确性。 代码设计 代码设计和可测试性有密切关联。强烈建议一个方法的代码行…

使用法国云手机进行面向法国的社媒营销

在当今数字化和全球化的时代&#xff0c;社交媒体已经成为企业营销和拓展市场的重要工具。对于想进入法国市场的企业来说&#xff0c;如何在海外社媒营销中脱颖而出、抓住更多的市场份额&#xff0c;成为了一个关键问题。法国云手机正为企业提供全新的营销工具&#xff0c;助力…

Flink源码学习资料

Flink系列文档脑图 由于源码分析系列文档较多&#xff0c;本人绘制了Flink文档脑图。和下面的文档目录对应。各位读者可以选择自己感兴趣的模块阅读并参与讨论。 此脑图不定期更新中…… 文章目录 以下是本人Flink 源码分析系列文档目录&#xff0c;欢迎大家查阅和参与讨论。…

iPhone 17系列取消17 Plus版本?新一代苹果手机迎来新变革

随着科技的飞速发展&#xff0c;苹果公司再次准备刷新我们的期待&#xff0c;即将推出的iPhone 17系列携带着一系列令人兴奋的升级。今年&#xff0c;苹果打破了常规&#xff0c;将四款新机型带入市场——iPhone 17、17 Pro、17 Pro Max&#xff0c;以及一款全新的成员&#xf…

站在资本投资领域如何看待分布式光纤传感行业?

近年来&#xff0c;资本投资领域对于分布式光纤传感行业并不十分敏感。这主要是由于分布式光纤传感技术是一个专业且小众的领域&#xff0c;其生命周期相对较长&#xff0c;缺乏爆发性&#xff0c;与消费品或商业模式创新产业有所不同。此外&#xff0c;国内的投资环境也是影响…

服务器上使用Docker部署sonarQube,并集成到Jenkins实现自动化。

目标是要在目标服务器上使用docker工具部署好sonar环境&#xff0c;然后再集成到Jenkins中实现自动化的代码审查工作。 Docker 首先Dokcer的源大部分现在都用不了&#xff0c;于是我上网查询&#xff0c;终于找到了一个可用的镜像。 编辑/etc/docker/daemon.json文件&#x…

医院存储文件采集至关重要,如何可靠安全进行?

医院的存储文件是医院日常运营中不可或缺的一部分&#xff0c;它包括了许多重要的文件类型&#xff1a; 病历档案&#xff1a;包括患者的门诊病历、住院病历、手术记录、护理记录等&#xff0c;是患者医疗过程的重要记录。 文书档案&#xff1a;医院在各项医疗业务活动、职能…

2023河南萌新联赛第(二)场 南阳理工学院

A. 国际旅行Ⅰ 题目&#xff1a; 思路&#xff1a; 因为题意上每个国家可以相互到达&#xff0c;所以只需要排序&#xff0c;输出第k小的值就可以了。 AC代码&#xff1a; #include<bits/stdc.h> #define int long long #define IOS ios::sync_with_stdio(0);cin.tie…

第一批进军AI的大学生,真的赚到钱了吗?

越来越多看到风口的大学生投身AI领域创业&#xff0c;这在ChatGPT&#xff08;美国人工智能公司OpenAI的大语言模型&#xff09;掀起新一轮人工智能浪潮后更加明显。 导读 壹 || 学生所处的学校环境和技术的结合更为紧密&#xff0c;因此学生可以利用这个信息差&#xff0c;用…

ZYNQ 入门笔记(零):概述

文章目录 引言产品线Zynq™ 7000 SoCZynq UltraScale™ MPSoCZynq UltraScale RFSoCVersal™ Adaptive SoC 开发环境 引言 Xilinx FPGA 产品线从经济型的 Spartan、Artix 系列到高性能的 Kintex、Virtex、Versal 系列&#xff0c;可以说涵盖了 FPGA 的绝大部分应用场景&#x…