年龄性别预测4:C/C++实现年龄性别预测和识别(含源码,可实时预测)

年龄性别预测4:C/C++实现年龄性别预测和识别(含源码,可实时预测)

目录

年龄性别预测4:C/C++实现年龄性别预测和识别(含源码,可实时预测)

1.年龄性别预测和识别方法

2.人脸检测方法

3.年龄性别预测和识别模型(Python)

(1) 年龄性别预测和识别模型训练

(2) 将Pytorch模型转换ONNX模型

(3) 将ONNX模型转换为TNN模型

4.年龄性别预测和识别模型C/C++部署

(1)项目结构

(2)配置开发环境(OpenCV+OpenCL+base-utils+TNN)

(3)部署TNN模型

(4)CMake配置

(5)main源码

(6)源码编译和运行

(7)Demo测试效果 

5.项目源码下载


本项目将实现年龄性别预测和识别,整套方案采用二阶段方法实现,即首先使用通用的人脸检测算法(Face Detection)定位人脸区域,裁剪人脸,再构建多任务模型,分别进行年龄预测(Age)和性别识别(Gender)。项目分为数据集说明,Pytorch模型训练和C++/Android部署等多个章节,本篇是项目《年龄性别预测》系列文章之C/C++实现年龄性别预测和识别;本篇主要分享将Python训练后的年龄性别预测和识别模型移植到C/C++平台。我们将开发一个简易的、可实时检测的年龄性别识别C/C++ Demo;项目源码模型推理支持CPU和GPU加速,开启GPU(OpenCL)加速,可以达到实时的检测识别效果,基本满足业务的性能需求。

340eedce8e8b46838ea49228faa18c10.png

 C++版本与Python版本的结果几乎是一致,下面是年龄性别预测和识别效果展示

8fbc1002408047588f2e997bebe9f683.gif

尊重原创,转载请注明出处https://blog.csdn.net/guyuealian/article/details/135556843


 更多项目《年龄性别预测》和《面部表情识别》系列文章请参考:

  1. 面部表情识别1:表情识别数据集(含下载链接)
  2. 面部表情识别2:Pytorch实现表情识别(含表情识别数据集和训练代码)
  3. 面部表情识别3:Android实现表情识别(含源码,可实时检测)
  4. 面部表情识别4:C++实现表情识别(含源码,可实时检测)
  5. 年龄性别预测1:年龄性别数据集说明(含下载地址)
  6. 年龄性别预测2:Pytorch实现年龄性别预测和识别(含训练代码和数据)
  7. 年龄性别预测3:Android实现年龄性别预测和识别(含源码,可实时预测)
  8. 年龄性别预测4:C/C++实现年龄性别预测和识别(含源码,可实时预测)

139a07d0b14741b4a7b80dee106c2b1f.gif


1.年龄性别预测和识别方法

年龄性别预测和识别方法有多种实现方案,这里采用最常规的二阶段方法实现,即首先使用通用的人脸检测算法(Face Detection)定位人脸区域,裁剪人脸,再构建多任务模型,分别进行年龄预测(Age)和性别识别(Gender)。

  • 人脸检测:人脸检测算法已经有很多成熟开源项目了,本项目不作分析,可以参考使用MTCNN,DSFD,FaceBoxes,RFB等方法。
  • 性别识别:性别识别是一个简单二分类,训练使用交叉熵损失函数即可
  • 年龄预测:可以采用年龄分类方法,如SSR-Net模型,也可以结合回归的方法,如Label Distribution。就调研而言,基于Label Distribution的方法会比分类方法准确率会高一些。

下图本项目构建的年龄性别预测和识别模型,其中

  • Backbone:主杆网络,用于提取人脸图像特征,可以使用任意的骨干网络,如resnet18,resnet34,resnet50以及轻量化模型mobilenet_v2等
  • Gender-branch: 性别识别分支,用于对性别进行分类识别,损失函数使用交叉熵
  • Age-branch: 年龄预测分支,对年龄进行预测,损失函数可以使用交叉熵或者Label Distribution,项目设定最大周岁是70周岁,训练数据中年龄大于70的lalel,会重置为70。

698d2400a5674176bc14e5c47660a294.png


2.人脸检测方法

 本项目人脸检测训练代码请参考:https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB 

这是一个基于SSD改进且轻量化后人脸检测模型,很轻巧,整个模型仅仅1.7M左右,在普通Android手机都可以实时检测。人脸检测方法在网上有一大堆现成的方法可以使用,如MTCNN,DSFD,FaceBoxes,完全可以不局限我这个方法。

da566a77c27c6d21c8d7ca477782e4d8.jpeg​​

关于人脸检测的方法,可以参考我的另一篇博客:

行人检测和人脸检测和人脸关键点检测(C++/Android源码)


3.年龄性别预测和识别模型(Python)

(1) 年龄性别预测和识别模型训练

本篇博文不含Python版本的模型以及相关训练代码,关于年龄性别预测和识别模型的训练方法,请参考本人另一篇博文《Pytorch实现年龄性别预测和识别(含训练代码和数据)》;

Python项目源码backbone模型支持的有resnet18,resnet50,以及轻量化模型mobilenet_v2等常见的深度学习模型,用户也可自定义模型进行训练;准确率还挺高的,采用轻量级mobilenet_v2模型的性别识别准确率0.9603左右,年龄预测MAE(平均绝对误差:)3.1935左右,CS5(预测年龄与真实年龄的绝对误差不过5年的准确率)0.8021左右,基本满足业务性能需求。

模型input size性别准确率年龄MAE年龄CS3年龄CS5

AE_mobilenet_v2

112×112

0.9603

3.1935

0.5969

0.8021

AE_resnet18

112×112

0.9606

3.1795

0.5956

0.8010

AE_resnet50

112×112

0.9609

3.2008

0.5900

0.8035

关于模型训练以及测试的建议:

  1. ​ 关于性别识别的问题:目前性别识别的准确率约96%,识别错误的主要有两种情况,(1)儿童性别容易误识别,特别是1~3岁左右的儿童,性别识别比较困难 (2) 长头发的男生或者短头发的女生的,也容易误识别;其他情况,正常穿着打扮的男士女生识别准确率可以达到99%左右。
  2. 关于年龄预测的问题:现有数据年龄部分不均匀,大部分人脸数据年龄分布在20-40岁之间的年轻人,而儿童和老年人的数据比较少;导致儿童和老年人年龄预测精准度比较差;另外,也是强烈建议的:采集同一个人不同年龄阶段的人脸数据加入模型训练,可以有效提升年龄预测的精准度。损失函数使用Label Distribution方法进行训练,也会比直接使用交叉熵损失函数效果要好。
  3. 当人脸存在遮挡时,如戴眼镜,戴口罩,头发遮挡,年龄预测的误差较大,建议实际使用过程中,尽量采集正脸,无遮挡的人脸图片进行测试
  4. 清洗数据集(最重要):尽管鄙人已经清洗一部分了,但还是建议你,训练前,再次清洗数据集,不然会影响模型的识别的准确率。
  5. 增加训练的样本数据: 建议根据自己的业务场景,采集相关数据,提高模型泛化能力
  6. 使用参数量更大的模型: 本教程使用的是mobilenet_v2模型,属于比较轻量级的分类模型,采用更大的模型(如resnet50),理论上其精度更高,但推理速度也较慢。
  7. 尝试不同数据增强的组合进行训练
  8. 增加数据增强: 已经支持: 随机裁剪,随机翻转,随机旋转,颜色变换等数据增强方式,可以尝试诸如mixup,CutMix等更复杂的数据增强方式
  9. 样本均衡: 原始数据年龄类别数据并不均衡,类别20-40岁的数据偏多,而老年人和小孩的数据偏少,这会导致训练的模型会偏向于样本数较多的类别。建议进行样本均衡处理。
  10. 调超参: 比如学习率调整策略,优化器(SGD,Adam等)
  11. 损失函数: 目前训练代码已经支持:交叉熵,LabelSmoothing,可以尝试FocalLoss等损失函数

(2) 将Pytorch模型转换ONNX模型

目前CNN模型有多种部署方式,可以采用TNN,MNN,NCNN,以及TensorRT等部署工具,鄙人采用TNN进行C/C++端上部署。部署流程可分为四步:训练模型->将模型转换ONNX模型->将ONNX模型转换为TNN模型->C/C++部署TNN模型。

训练好Pytorch模型后,我们需要先将模型转换为ONNX模型,以便后续模型部署。

  • 原始项目提供转换脚本,你只需要修改model_file为你模型路径即可
  •  convert_torch_to_onnx.py实现将Pytorch模型转换ONNX模型的脚本
python libs/convert/convert_torch_to_onnx.py
"""
This code is used to convert the pytorch model into an onnx format model.
"""
import sys
import os
 
sys.path.insert(0, os.getcwd())
import argparse
from demo import Predictor
from basetrainer.utils import log, setup_config
from basetrainer.utils.converter import pytorch2onnx
 
 
def get_parser():
    # 配置文件
    config_file = "../../configs/config.yaml"
    # 模型文件
    # model_file = "../../work_space/AE_mobilenet_v2_1.0_L1Loss_20240103_191147_2420/model/best_model_073_0.8107.pth"
    model_file = "../../work_space/AE_mobilenet_v2_1.0_L1Loss_20240105_181151_9813/model/best_model_082_0.8021.pth"
    parser = argparse.ArgumentParser(description="Inference Argument")
    parser.add_argument("-c", "--config_file", help="configs file", default=config_file, type=str)
    parser.add_argument("-m", "--model_file", help="model_file", default=model_file, type=str)
    parser.add_argument("--use_age_ld", help="use age label distribution", default=1, type=int)
    parser.add_argument("--device", help="cuda device id", default="cuda:0", type=str)
    return parser
 
 
def convert_torch_to_onnx(cfg):
    p = Predictor(cfg=cfg)
    model = p.model
    w, h = cfg.input_size
    input_shape = (1, 3, h, w)
    onnx_file = str(cfg.model_file).replace(".pth", ".onnx")
    pytorch2onnx.convert2onnx(model,
                              input_shape=input_shape,
                              input_names=['input'],
                              output_names=['age', 'gender'],
                              onnx_file=onnx_file,
                              opset_version=9)
 
 
if __name__ == "__main__":
    parser = get_parser()
    print(parser.parse_args())
    cfg = setup_config.parser_config(parser.parse_args(), cfg_updata=False)
    convert_torch_to_onnx(cfg)

(3) 将ONNX模型转换为TNN模型

目前CNN模型有多种部署方式,可以采用TNN,MNN,NCNN,以及TensorRT等部署工具,鄙人采用TNN进行C/C++端上部署

TNN转换工具:

baa5c3a1527340d89194ec142af6aba0.png​​​​

 模型转换成功后,会得到两个TNN模型,一个描述模型结构的*.tnnproto的文件,一个是模型参数*.tnnmodel文件;下载到本地,后面C++/Android端上部署,需要加载*.tnnproto和*.tnnmodel文件进行模型推理。

4.年龄性别预测和识别模型C/C++部署

项目IDE开发工具使用CLion,相关依赖库主要有OpenCV,base-utils以及TNN和OpenCL(可选),其中OpenCV必须安装,OpenCL用于模型加速,base-utils以及TNN已经配置好,无需安装;

项目仅在Ubuntu18.04进行测试,Windows系统下请自行配置好开发环境。

(1)项目结构

d9e00f07a375499fbd7265ae20a2473c.png

(2)配置开发环境(OpenCV+OpenCL+base-utils+TNN)

项目IDE开发工具使用CLion,相关依赖库主要有OpenCV,base-utils以及TNN和OpenCL(可选),其中OpenCV必须安装,OpenCL用于模型加速,base-utils以及TNN已经配置好,无需安装;

项目仅在Ubuntu18.04进行测试,Windows系统下请自行配置和编译

  • 安装OpenCV:图像处理

图像处理(如读取图片,图像裁剪等)都需要使用OpenCV库进行处理

安装教程:Ubuntu18.04安装opencv和opencv_contrib

OpenCV库使用opencv-4.3.0版本,opencv_contrib库暂时未使用,可不安装

  • 安装OpenCL:模型加速

 安装教程:Ubuntu16.04 安装OpenCV&OpenCL

OpenCL用于模型GPU加速,若不使用OpenCL进行模型推理加速,纯C++推理模型,速度会特别特别慢

  • base-utils:C++库

GitHub:https://github.com/PanJinquan/base-utils (无需安装,项目已经配置了)

base_utils是个人开发常用的C++库,集成了C/C++ OpenCV等常用的算法

  • TNN:模型推理

GitHub:https://github.com/Tencent/TNN (无需安装,项目已经配置了)

由腾讯优图实验室开源的高性能、轻量级神经网络推理框架,同时拥有跨平台、高性能、模型压缩、代码裁剪等众多突出优势。TNN框架在原有Rapidnet、ncnn框架的基础上进一步加强了移动端设备的支持以及性能优化,同时借鉴了业界主流开源框架高性能和良好拓展性的特性,拓展了对于后台X86, NV GPU的支持。手机端 TNN已经在手机QQ、微视、P图等众多应用中落地,服务端TNN作为腾讯云AI基础加速框架已为众多业务落地提供加速支持。

(3)部署TNN模型

项目实现了C/C++版本的车牌检测和车牌识别,车牌检测模型YOLOv5和车牌识别模型PlateNet,模型推理采用TNN部署框架(支持多线程CPU和GPU加速推理);图像处理采用OpenCV库,模型加速采用OpenCL,在普通设备即可达到实时处理。

如果你想在这个 Demo部署你自己训练的车牌检测模型YOLOv5和车牌识别模型PlateNet,你可将训练好的Pytorch模型转换ONNX ,再转换成TNN模型,然后把原始的模型替换成你自己的TNN模型即可。

(4)CMake配置

这是CMakeLists.txt,其中主要配置OpenCV+OpenCL+base-utils+TNN这四个库,Windows系统下请自行配置和编译

cmake_minimum_required(VERSION 3.5)
project(Detector)

add_compile_options(-fPIC) # fix Bug: can not be used when making a shared object
set(CMAKE_CXX_FLAGS "-Wall -std=c++11 -pthread")
#set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
#set(CMAKE_CXX_FLAGS_DEBUG "-g")

if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    # -DCMAKE_BUILD_TYPE=Debug
    # -DCMAKE_BUILD_TYPE=Release
    message(STATUS "No build type selected, default to Release")
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (default Debug)" FORCE)
endif ()

# opencv set
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS} ./src/)
#MESSAGE(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")

# base_utils
set(BASE_ROOT 3rdparty/base-utils) # 设置base-utils所在的根目录
add_subdirectory(${BASE_ROOT}/base_utils/ base_build) # 添加子目录到build中
include_directories(${BASE_ROOT}/base_utils/include)
include_directories(${BASE_ROOT}/base_utils/src)
MESSAGE(STATUS "BASE_ROOT = ${BASE_ROOT}")


# TNN set
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
# build for platform
# set(TNN_BUILD_SHARED OFF CACHE BOOL "" FORCE)
if (CMAKE_SYSTEM_NAME MATCHES "Android")
    set(TNN_OPENCL_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_ARM_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_BUILD_SHARED OFF CACHE BOOL "" FORCE)
    set(TNN_OPENMP_ENABLE ON CACHE BOOL "" FORCE)  # Multi-Thread
    #set(TNN_HUAWEI_NPU_ENABLE OFF CACHE BOOL "" FORCE)
    add_definitions(-DTNN_OPENCL_ENABLE)           # for OpenCL GPU
    add_definitions(-DTNN_ARM_ENABLE)              # for Android CPU
    add_definitions(-DDEBUG_ANDROID_ON)            # for Android Log
    add_definitions(-DPLATFORM_ANDROID)
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
    set(TNN_OPENCL_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_CPU_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_X86_ENABLE OFF CACHE BOOL "" FORCE)
    set(TNN_QUANTIZATION_ENABLE OFF CACHE BOOL "" FORCE)
    set(TNN_OPENMP_ENABLE ON CACHE BOOL "" FORCE)  # Multi-Thread
    add_definitions(-DTNN_OPENCL_ENABLE)           # for OpenCL GPU
    add_definitions(-DDEBUG_ON)                    # for WIN/Linux Log
    add_definitions(-DDEBUG_LOG_ON)                # for WIN/Linux Log
    add_definitions(-DDEBUG_IMSHOW_OFF)            # for OpenCV show
    add_definitions(-DPLATFORM_LINUX)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(TNN_OPENCL_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_CPU_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_X86_ENABLE ON CACHE BOOL "" FORCE)
    set(TNN_QUANTIZATION_ENABLE OFF CACHE BOOL "" FORCE)
    set(TNN_OPENMP_ENABLE ON CACHE BOOL "" FORCE)  # Multi-Thread
    add_definitions(-DTNN_OPENCL_ENABLE)           # for OpenCL GPU
    add_definitions(-DDEBUG_ON)                    # for WIN/Linux Log
    add_definitions(-DDEBUG_LOG_ON)                # for WIN/Linux Log
    add_definitions(-DDEBUG_IMSHOW_OFF)            # for OpenCV show
    add_definitions(-DPLATFORM_WINDOWS)
endif ()
set(TNN_ROOT 3rdparty/TNN)
include_directories(${TNN_ROOT}/include)
include_directories(${TNN_ROOT}/third_party/opencl/include)
add_subdirectory(${TNN_ROOT}) # 添加外部项目文件夹
set(TNN -Wl,--whole-archive TNN -Wl,--no-whole-archive)# set TNN library
MESSAGE(STATUS "TNN_ROOT = ${TNN_ROOT}")


# Detector
include_directories(src)
set(SRC_LIST
        src/classification.cpp
        src/object_detection.cpp
        src/face_alignment.cpp
        src/Interpreter.cpp
        )
add_library(dlcv SHARED ${SRC_LIST})
target_link_libraries(dlcv ${OpenCV_LIBS} base_utils)
MESSAGE(STATUS "DIR_SRCS = ${SRC_LIST}")

add_executable(Detector src/main.cpp)
target_link_libraries(Detector dlcv ${TNN} -lpthread)


(5)main源码

主程序中函数main实现提供了年龄性别预测和识别的使用方法,支持图片,视频和摄像头测试

  •     test_image_file();   // 测试图片文件
  •     test_video_file();   // 测试视频文件
  •     test_camera();       //测试摄像头
 

(6)源码编译和运行

编译脚本,或者直接:bash build.sh

#!/usr/bin/env bash
if [ ! -d "build/" ];then
  mkdir "build"
else
  echo "exist build"
fi
cd build
cmake ..
make -j4
sleep 1
./demo

  • 如果你要测试CPU运行的性能,请修改src/main.cpp

DeviceType device = CPU;

  • 如果你要测试GPU运行的性能,请修改src/main.cpp (需配置好OpenCL) 

DeviceType device = GPU;

PS:纯CPU C++推理模式比较耗时,需要几秒的时间,而开启OpenCL加速后,GPU模式耗时仅需十几毫秒,性能极大的提高。

(7)Demo测试效果 

 C++版本与Python版本的结果几乎是一致,下面是年龄性别预测和识别效果展示

5c51efe19ee543218bd3ddc265d87f1e.gifb4b82d5c533144fb96a533a5cda10d28.gif

56bc00478fdc4d018c14dd4d74fae562.jpeg

ce2035bd7d4e4bfa8d8c3de11c6a8437.png


5.项目源码下载

C/C++项目源码下载地址:C/C++实现年龄性别预测和识别(含源码,可实时预测)

整套项目源码内容包含:

  1. 提供C/C++版本的人脸检测模型
  2. 提供C/C++版本的年龄性别预测和识别项目源码,源码可用于二次开发
  3. C++源码支持CPU和GPU,开启GPU(OpenCL)可以实时检测和识别(纯CPU推理速度很慢,模型加速需要配置好OpenCL,GPU推理约15ms左右)
  4. 项目配置好了base-utils和TNN,而OpenCV和OpenCL需要自行编译安装
  5. C/C++ Demo支持图片,视频,摄像头测试

如果你需要年龄性别预测和识别训练代码,请参考本人另一篇博文《Pytorch实现年龄性别预测和识别(含训练代码和数据)》;

目前已经实现Android版本的年龄性别预测和识别,详细项目请参考:

年龄性别预测和识别Android APP Demo体验:https://download.csdn.net/download/guyuealian/88743711

06806202ad494d489ad44d072b01a949.gifec2a11af44ba4efdb09d2f5200bdbb66.gif

 

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
随机生成指定数量的人名字,如下面的运行结果: 100个男性名字 古彬邦 司徒军会 饶光振 乐东涛 史哲广 李岩安 邓松勇 韩彪诚 时辉东 齐才贵 欧坚飞 丁江彬 黎飞哲 江进坚 骆富壮 毕壮山 石涛江 倪俊河 郎刚兴 黄强宁 蔡胜新 车先保 宁杰达 邱成志 贺福震 岑博有 赖贵清 简龙学 范绍光 姜良星 任裕发 柳健民 彭志亮 强义信 廉伟天 穆诚昌 钱兴富 傅元超 潘天峰 池力良 路永国 施新成 甘心林 苏林明 龙峰乐 姬民茂 霍学伟 蒋宁厚 盛清武 关毅生 程思元 华乐刚 方勇功 马祥豪 沈顺强 连达彪 孔超博 陆全健 何明俊 高康心 冯保杰 金河胜 卞豪永 廖星文 区生进 卢有辉 刘广中 成浩裕 侯海绍 费功才 皮波海 母利磊 林和波 梅仁利 鲁友敬 秦震先 陈平和 曹文承 莫邦群 常昌康 郭敬义 蒲信仁 葛振松 柯群善 雷会子 罗厚军 符庆思 康亮平 吕世福 白山庆 洪发毅 凌国友 戚善顺 樊武龙 孟子力 胡承浩 丘磊祥 孙中世 梁茂岩 龚安全 100个女性名字 路雪芬 樊桂梦 葛璐静 母霞娴 时珊红 梅静颖 宁洁怡 齐琴婵 黎晶玉 欧娜翠 邓玉荷 梁娴娜 关香芳 黄娣美 卞惠凡 费馨琳 胡燕霞 凌莺晶 华怡燕 雷勤月 邱倩佳 皮婵眉 符仪娥 江素瑞 施璧琦 彭娟珊 曹兰莉 丘婉梅 范岚珠 李月娣 卢爱璧 常菁蓉 陈露菊 郎荣纨 孔青媛 鲁环华 孟妍春 柯芬丹 蔡叶君 蒋翠莲 郭芝仪 甘瑶倩 饶玲云 莫蓓青 古颖娟 程莲玲 区娅惠 史菊娅 龚蓉环 姜媛婕 倪雅雅 秦婷蓓 强慧妍 池秋贞 龙萍嘉 钱琳素 柳艳叶 苏荷瑶 孙妹茜 盛瑞雪 赖婕凤 姬彩妹 马珠薇 蒲苑洁 穆淑莺 洪嘉慧 白瑾姣 司徒莉秀 金华雁 吕英彩 高丹岚 贺君琴 石薇璐 乐黛勤 康云苑 任雁珍 岑梦巧 潘锦锦 冯真芝 毕凤秋 连珍馨 何纨萍 廖凡淑 简茜菁 罗佳莎 廉贞爱 车莎艳 沈蕊桂 陆梅香 林秀婉 傅娥兰 侯琼琼 刘眉真 成巧婷 霍美蕊 骆芳瑾 韩姣荣 丁春露 戚琦英 方红黛
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI吃大瓜

尊重原创,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值