# FacialAgePrediction **Repository Path**: eobard721/facial-age-prediction ## Basic Information - **Project Name**: FacialAgePrediction - **Description**: 轻量级人脸年龄预测模型,可应用于中小规模数据集年龄预测任务,可选择三个backbone:resnet50、efficientnet_b0、vit_small_patch14_dinov2 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-17 - **Last Updated**: 2026-01-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: Python, PyTorch, 人脸年龄预测模型 ## README # Facial Age Prediction --- > :pencil2:: **Eobard Thawne** > :calendar::2025-10-22 11:11:12 > :e-mail::gxp1838777268@163.com > :link:(原仓库地址):https://github.com/Ebimsv/Facial_Age_estimation_PyTorch/tree/main --- ## 1. 环境准备 > **本机环境:python=3.10、torch=2.0.0、torchaudio=2.0.2、torchmetrics=1.1.1、torchsummary=1.5.1、torchvision==0.15.1** * matplotlib==3.7.2 * numpy==1.25.2 * opencv-python==4.8.0.76 * pandas==2.1.0 * scikit-learn==1.3.0 * tensorboard==2.14.0 * tensorboard-data-server==0.7.1 * tqdm==4.66.1 * timm * onnxruntime * seaborn :warning:: **请根据自己的GPU版本,下载对应的pytorch的版本,** ## 2. 数据预处理 ### 2.0 上传数据集文件 > **将自己的数据集图片上传到服务器的某个位置** ### 2.1 计算均值与方差 > **需要根据自己数据集的数据分布去计算均值与方差,然后把它归一化处理,这里不能用别人的现成,因为它可能不适合我们自己的数据集分布** ```python # 运行utils.py里面的方法 calc_mean_std("/Users/eobardgu/Desktop/mex_face_age/images") # 将输出的均值和方差复制到config.py里面去替换 [info] Mean: [0.177533, 0.153219, 0.144794] [info] Variance: [0.032154, 0.026371, 0.024352] ``` image-20251022180518640 **注:计算 mean 、 std 时,路径应指向包含「训练集、验证集和测试集」的`整个数据集根目录`,而不是分别计算每个子集的mean 、 std 。如果你有多个国家的数据集,请先把它们放在一起,然后用它们的上一层目录去计算,这样才是所有图片计算出来的总mean、std** ```tex eg: 就是写/Users/eobardgu/folder/这个路径 /Users/eobardgu/folder/ /mex_images /pak_images .... /xxx ``` ### 2.2 构建数据集描述文件 > **构建总的数据集描述文件,生成`xxx.csv`文件,其中前两列为固定训练列,第三列为补充信息列** > > | image_name | age | apply_uuid(补充信息的列) | > | ---------- | ---- | -------------------------- | ```python # 图片路径 mex_path = "/Users/eobardgu/Desktop/mex_face_age/images" # 生成的csv文件路径 mex_csv = f"./filelists/mex/mex_image_filelists.csv" # 运行data_preprocess.py中的方法 build_image_desc_csv(mex_path,mex_csv) ``` ⚠️**:这里的脚本函数生成规则要求每个图片的命名规则必须是`[真实年龄]_[apply_uuid]_[其它信息].jpg `,如果数据集图片不符合这样的要求,那么可以自己创建脚本生成描述文件,只要符合生成的csv文件的前两列是固定训练列的名称(即image_name、age)即可,第三列的列名称随意取,对应的值随意放** #### 汇总脚本(可选) **注:如果有多个国家的数据集(eg:泰国、菲律宾、印尼),那么每个国家生成后的描述文件可以合并成一个总的描述文件,方便后续步骤使用** ```python # 假设有两个国家的描述文件 mex_csv = f"./filelists/mex/mex_image_filelists.csv" pak_csv = f"./filelists/pak/pak_image_filelists.csv" # 运行data_preprocess.py中的方法,合并成一个总的描述文件 merge_all_desc_csv([mex_csv,pak_csv],"./output.csv") [info] 原始记录数: - mex_image_filelists.csv: 1521 条 - pak_image_filelists.csv: 1454 条 = 共计: 2975 [info]合并后总记录数: 2975 ``` ### 2.3 数据集划分 image-20251022183157126 ```python # 运行data_preprocess.py中的方法,划分数据集为8:1:1 df_train,df_valid,df_test=split_datasets("./output.csv",use_stratified_samping=True) # 可视化三个数据集里面的年龄数据分布: # 我在代码里写了一个分层分桶采样方式,因为这几个国家的年龄分布不太均衡,所以我使用分层分桶采样而没有使用随机采样,所以最终结果可看到三者的数据分布还是比较均衡的;以后的数据可以设为False用随机采样的方式,但是我推荐还是使用分层分桶采样,采样方式主要取决于使用分层分桶或随机采样划分后的数据集分布是不是均衡的,没有绝对的对错之分) plot_dataset_distribution(df_train,df_valid,df_test) [info] Train: 2380 | Valid: 297 | Test: 298 [info] All CSV files created successfully. - 训练集: 2380 条 - 验证集: 297 条 - 测试集: 298 条 - 输出目录: /Users/eobardgu/Desktop/facial-age-prediction/filelists ``` image-20251022170642881 ### 2.4 超参数处理 > **在训练前需要调整config.py里面的超参数** ![image-20251022181041543](./readme_images/image-20251022181041543.png) ## 3. 训练 > **当训练完后,模型保存到`checkpoints`文件夹里面,损失曲线会保存到`figs`文件夹里面** ```bash python train.py ``` image-20251022183722447 ![image-20251022183744027](./readme_images/image-20251022183744027.png) **注意:checkpoints文件夹保存模型的规则为  config【“model”】【"model_name"】-epoch-【训练轮数】-loss_valid-【验证集loss值】.pt,默认会根据当前config【“model”】【"model_name"】的名称保存三个最优的模型;所以如果要重新训练相同backbone的时候,请务必把之前的模型保存到其它文件夹去,否则会替换之前的** ## 4.微调 ### 4.1 全量微调 * 修改`config.py`中微调超参数 ![image-20251023145408720](./readme_images/image-20251023145408720.png) > **现在微调方法中只有全量微调,以后可以根据需要进行自定义微调方式(见setup_finetune_model函数,eg:只训练分类头、分阶段解冻)** * 运行`fine_tune.py`,发现前后的权重值不一样则说明成功加载到了本地pretrain_model ```bash python fine_tune.py ``` ![image-20251023145814908](./readme_images/image-20251023145814908.png) > **第一次的权重值是随机初始化的,每次运行都不一样;而第二次权重则是加载到了本地的权重值** * 微调模型会默认保存到`项目根路径/finetune`下 image-20251023150631653 ## 5.推理 > **推理函数中有三个方法可以选择:对单个图片推理、对文件夹下图片推理、用dataloader方式推理,如果使用dataloader方式推理,可以把test_dataloader放入进行推理,推理得到的结果会在output文件夹中体现** ```python # 普通推理方式(可以修改使用哪种推理方式:单个文件、文件夹、dataloader,修改main函数即可) python inference.py # onnx推理方式 from inference_onnx import AgePredictOnnx from config import config model=AgePredictOnnx("你的onnx",config) age_pred=model.predict("你的图片地址") # 可选命令:将output文件夹直接压缩,方便下载下来到本机查看效果 tar -czvf output.tar.gz ./output ``` image-20251022184923099 ## 6.torch vs onnx > **这一步是为了验证torch模型和onnx的输出是否有严重差异,onnx_utils.py中以下三个方法可供选择** * **torch_vs_onnx_with_no_data_preprocess**:使用随机tensor对比两个模型的年龄预测 * **torch_vs_onnx_with_same_data_preprocess**:使用相同的数据预处理方式(PIL+torch),使用测试集路径随机选择n个样本进行年龄预测 * **torch_vs_onnx_with_different_data_preprocess**:使用不同的数据预处理方式(torch:PIL+Torch;onnx:Numpy+cv2),使用测试集路径随机选择n个样本进行年龄预测 > **因为两个库对数据预处理方式不同,所以输出的结果有一些差异,只要整体预测接近即可** ![image-20251031153923786](./readme_images/image-20251031153923786.png) ### 注: > **因为训练时候图片预处理和onnx推理的预处理不同,如果实在想要torch模型和onnx模型输出完全一致,那么在训练的时候,吧图片预处理换成和onnx预处理一样即可** image-20251031154439851 ## 7. 相关代码使用 * **data_preprocess.py** * 构建图片描述文件 * 合并多个图片描述文件成一个总的图片描述文件 * 划分数据集 * **datasets_utils.py** * 数据预处理操作(获取transform_train、transform_test) * 获取训练、验证集dataloader * 获取测试集dataloader * **inference.py** * 对单个图片进行推理 * 批量对文件夹进行推理 * 用dataloader推理(将预测结果和真实结果显示在图片上) * 用dataloader推理,把结果写出到csv文件中 * **data_analysis_utils.py** * 可视化显示csv文件里面指定列的数据分布 * 可视化train、val、test数据集里面指定列的数据分布 * 分析模型的性能(模型的预测准确性误差) * **utils.py** * 将csv文件的图片列信息复制到新的文件夹里面 * 打印当前模型的权重(判断是否已经加载到pretrain model,默认会打印最后一层的权重) * 导出为JIT格式 * 随机显示dataset_folder里面的图片 * 计算模型的训练参数大小 * **onnx_utils.py** * 将模型导出为Onnx * 指定次数循环测试onnx模型性能 * 无限循环测试onnx模型性能