首页 分享 CV学习赛宠物狗年龄自动识别的一种python实现方法

CV学习赛宠物狗年龄自动识别的一种python实现方法

来源:萌宠菠菠乐园 时间:2025-09-03 22:22

一、问题及背景

随着我国居民可支配收入持续增长及宠物饲养人群的显著扩大,宠物消费市场呈现多元化、精细化发展趋势,涵盖食品、用品、医疗、服务等多维度商品与服务形态。在此驱动下,国内宠物产业规模进入高速扩张期。2017至2022年间,中国宠物市场规模年均复合增长率达18.7%,至2022年已突破千亿人民币量级。前瞻产业研究数据显示,2023年市场规模约达1500亿元,预计2025年将突破2000亿元。伴随养宠人口基数的持续扩容与“拟人化”“健康化”养宠理念的深度渗透,宠物消费市场预计将保持强劲增长态势。

宠物医疗保险作为宠物经济生态链中的关键环节,其保费规模亦呈现逐年攀升趋势。据《中国宠物医疗行业白皮书》统计,2023年宠物保险渗透率较五年前提升320%,市场规模突破50亿元。然而,随着宠物平均寿命延长及老龄化进程加速,相关医疗赔付风险同步抬升——高龄宠物慢性病发病率较青年宠物高出47%,单次诊疗费用均值增加65%。这一结构性变化对保险产品的精算模型与风险管控机制提出严峻挑战。

当前行业亟需在承保环节建立高效、准确的宠物年龄识别机制。传统依赖用户自主申报或纸质档案的方式,存在信息滞后、主观误差率高(约32%)等缺陷,难以有效拦截高龄宠物投保风险,导致赔付率持续突破健康阈值(行业健康赔付率阈值为60%-70%,部分险企实际赔付率已超85%)。因此,亟需构建基于客观数据的自动化年龄评估体系。本研究聚焦于通过计算机视觉技术实现宠物生理年龄的精准预估。通过深度解析宠物面部图像中的生物特征(如毛发纹理、眼部晶状体浑浊度、面部肌肉松弛度等),构建端到端的年龄预测模型。该技术的应用将显著提升核保环节的风险识别精度,为动态保费定价、赔付率控制及产品可持续设计提供核心数据支撑,进而推动宠物医疗保险市场的规范化与高质量发展。

二、方法原理

本方案实现宠物年龄识别的基本思想是利用深度学习模型对宠物图像进行特征提取和分析,进而精准判断宠物的年龄。深度学习模型凭借其卓越的特征学习能力,能够自动从海量的图像数据中挖掘出与宠物年龄紧密相关的特征模式。通过对标注好年龄的宠物图像数据集进行训练,模型可以捕捉到不同年龄段宠物图像在毛发质地、皮肤纹理、眼神等方面的细微特征差异,从而在面对新的宠物图像时,依据所学的特征模式精准预测出宠物的年龄范围。

卷积神经网络(Convolutional Neural Network, CNN)是该实现方案的核心理论基础。CNN 是一种专为处理具有网格结构数据(如图像)而设计的神经网络,其独特架构使其在图像识别领域表现出色。CNN 主要由卷积层、池化层和全连接层等关键组件构成,这些组件协同工作,实现对图像特征的高效提取与分析。卷积层运用多个卷积核在图像上滑动执行卷积操作,从而敏锐地提取图像的局部特征,例如宠物毛发的纹理走向、眼睛的清澈度等。池化层则通过最大池化或平均池化等操作降低特征图的维度,这不仅大幅减少计算量,还有效增强特征的鲁棒性,使模型对图像的细微变化具有更强的容忍度。全连接层将提取到的特征进行深度融合与整合,最终输出一个精确的年龄预测值。

训练过程中,采用 Adam 优化器与自适应学习率调度器,加速训练进程并提升模型性能。每个训练周期后,在验证集上对模型进行严格评估,并依据验证损失保存表现最佳的模型。预测阶段,加载最佳模型对测试集进行预测,并将预测结果以指定格式保存,以便于后续的评估与分析。

三、主要方法

3.1数据预处理

数据来源于阿里云天池大赛的宠物年龄自动辨识学习赛,包括20000个训练集数据及3000个测试集数据,训练集中噪声含量约6%,测试集不含噪声,宠物年龄按月龄给出,年龄标签范围为[0,192]。

数据预处理流程包含以下关键增强策略:

1)空间变换增强:

随机水平翻转(概率0.5)

随机旋转(±15度)

随机仿射变换(平移±10%,缩放90-110%)

2)颜色空间增强:

亮度抖动(±20%)

对比度抖动(±20%)

饱和度抖动(±20%)

色相抖动(±10%)

3)标准化处理:

使用ImageNet预训练的RGB通道均值[0.485, 0.456, 0.406]

标准差[0.229, 0.224, 0.225]进行归一化

3.2 模型选择策略

在本方案中,选用预训练的 ResNet-18 模型作为基础架构,并结合宠物年龄识别任务的特点进行针对性微调。通过以下创新设计提升性能:

1)全参数微调策略:取消预训练参数冻结,对所有层进行端到端训练

2)双阶段回归头:512→256→1 的层级特征压缩结构

3)动态正则化:在 256 维特征空间引入 40% Dropout 率

4)批归一化优化:在每层激活前插入 BatchNorm1d

3.3 特征工程优化

1)关键特征增强:通过图像变换和标准化处理增强年龄相关特征的表征能力

2)特征提取与降维:利用 ResNet-18 提取高维特征,并通过回归头逐步降维,保留与年龄相关的特征信息,降低模型复杂度,提高训练效率

3.4 损失函数与优化设计

采用 L1 损失函数(平均绝对误差)作为优化目标,其对异常值具有较强的鲁棒性,能够更好地约束数值预测精度,在处理包含噪声的数据时表现出更稳定的性能。

优化器:选用 Adam 优化器配合学习率调度,初始学习率设为 1e-4。Adam 优化器结合了动量和自适应学习率的优点,能够有效加速模型收敛,并在训练后期通过学习率调度器动态调整学习率,进一步提高模型的优化效果。

正则化:在全连接层中加入 Dropout(0.4)操作,随机丢弃部分神经元输出,破坏神经元之间的协同适应,从而抑制过拟合现象,提高模型的泛化能力。

3.5代码实现策略

为实现宠物年龄自动辨识模型的构建与训练,以下是具体的实现策略:

1)数据集划分

将原始训练集按 8:2 的比例划分为训练集和验证集。利用 torch.utils.data.random_split 函数实现划分,并创建对应的 DataLoader 以供模型训练与验证使用。在划分过程中,确保数据分布的代表性,使得训练集和验证集能够全面覆盖原始训练集的特征与标签分布,为模型训练和验证奠定基础。具体来说,通过指定生成随机数的种子,保证每次划分的一致性,避免因数据划分的随机性导致的实验结果差异。同时,合理设置 batch_size 参数,控制每个批次的样本数量,以充分利用 GPU 的并行计算能力,提高训练效率。

2)无效数据过滤处理

在数据集初始化时,通过图片路径检查过滤掉无效数据。在数据集的getitem方法中,若图像加载失败,则尝试加载下一个图像。在创建数据集时,仅保留有效数据的标注信息,确保模型训练数据的有效性,避免无效数据对模型训练的干扰,提高数据利用效率,保证模型输入数据的质量。具体实现中,利用 Python 的异常处理机制,在图像加载过程中捕获可能发生的错误,如文件不存在、文件损坏等,从而实现对无效数据的自动跳过。

3)模型训练与验证

在模型训练阶段,使用 Adam 优化器与学习率调度器,通过梯度下降法更新模型参数。每个训练周期后,通过evaluate_model函数在验证集上评估模型性能,并保存表现最佳的模型。验证过程计算验证损失以监控模型的泛化能力,基于验证损失,学习率调度器动态调整学习率,确保模型在训练后期能够稳定收敛。此外,采用早停机制(Early Stopping),当验证损失在一定轮数内没有改善时,提前停止训练,防止过拟合。具体来说,设置一个耐心值(patience),当验证损失连续 patience 轮没有下降时,停止训练过程,从而避免模型在训练后期过度拟合训练数据,提高模型的泛化性能。

4)模型预测与结果保存

训练完成后,加载最佳模型并对测试集进行预测。预测过程通过 predict 函数实现,模型对测试集图像逐批次进行前向传播,输出预测年龄。预测结果以指定格式保存,便于后续评估与分析。save_predictions 函数将预测结果写入文本文件,每行包含图像文件名和对应的预测年龄,确保结果的可追溯性与可验证性。在保存结果时,按照要求的格式进行输出,方便用户对预测结果进行进一步的处理和评估。

5)模型设计与优化

模型基于 ResNet-18 构建,取消预训练参数冻结,对所有层进行端到端训练。特征提取部分采用 ResNet-18 的卷积层,经过全局平均池化后,将特征输入到回归层。回归层包含多个全连接层,逐步将高维特征映射到年龄预测值。为增强模型的表达能力,回归层中引入了 Dropout 层以防止过拟合,并通过 ReLU 激活函数引入非线性。具体来说,回归层的设计如下:首先将 512 维的特征向量通过一个全连接层映射到 256 维,并在该层后添加 BatchNorm1d 和 ReLU 激活函数,以及 40% 的 Dropout;然后将 256 维特征向量进一步映射到 1 维,得到最终的年龄预测值。这种设计不仅保留了 ResNet-18 的强大特征提取能力,还通过回归头的逐步降维和正则化手段,提高了模型对宠物年龄预测的准确性和泛化能力。

四、实验结果与分析

4.1运行结果

模型训练完成后,生成了损失曲线图,如图4.1所示,并对测试集进行了预测,预测结果以指定格式保存在了文件 pred_result.txt 中(附录1)。文件中每行包含一张图像的文件名和对应的预测年龄,从预测结果来看,模型对不同图像的年龄预测涵盖了从 9.1 到 125.6 等较为广泛的范围,表明模型能够对不同年龄段的宠物图像进行有效识别。

图4.1 损失曲线图

4.2模型性能分析

从图4.1中可以观察到,训练损失和验证损失均呈下降趋势,这表明模型在训练过程中逐渐学习到了数据的特征,并且在验证集上的表现也在不断提升。在训练初期,训练损失和验证损失下降较快,说明模型在初期学习到了较为明显的特征模式。随着训练的进行,损失下降速度逐渐放缓,这可能是由于模型逐渐接近收敛,学习到的特征更加细致和复杂。最终训练损失和验证损失分别稳定在约 0.09 和 0.12 左右,表明模型在训练集和验证集上都取得了较好的拟合效果,没有出现明显的过拟合或欠拟合现象。

4.3模型结果评估

从预测结果来看,模型对不同年龄段的宠物图像均能给出合理的预测值。对于年龄较小的宠物图像,如预测年龄为 9.1 月龄的图像,模型能够识别出其较为年轻的特征;对于年龄较大的宠物图像,如预测年龄为 125.6 月龄的图像,模型也能较好地捕捉到其年龄较大的特征。这表明模型具有较好的泛化能力,能够在未见过的图像上稳定地进行年龄预测。然而,也存在一些预测结果可能与实际年龄存在偏差的情况。这可能是由于宠物的品种、个体差异、图像拍摄条件等因素对模型的预测产生了一定的影响。尽管如此,从整体上看,模型在大多数情况下能够给出较为准确的预测结果,满足宠物年龄自动辨识的基本需求。综合考虑模型的训练过程、验证过程以及最终的测试结果,得出以下结论:

1)模型拟合效果:模型在训练集上的损失逐渐降低,验证集上的损失在早期阶段也随之降低,表明模型在训练过程中有效地学习到了数据的特征,并且在一定程度上具备泛化能力。然而,验证损失在训练后期出现波动或轻微上升的趋势,这可能暗示模型在训练后期开始出现轻微的过拟合现象。尽管如此,验证损失的波动幅度较小,且整体趋势并未明显恶化,说明模型的过拟合风险较低,仍能保持较好的泛化性能。

2)模型优势:从测试结果来看,模型在大多数样本上能够较为准确地预测宠物年龄,尤其在中间年龄段(如 24-96 月龄)的预测表现较为出色,准确率较高,误差较小。这表明模型对这一年龄段的宠物特征具有较强的识别能力。此外,模型基于 ResNet-18 架构,充分利用了深度学习的优势,能够自动提取图像中的复杂特征,为宠物年龄预测提供了一种有效的解决方案。

3)模型局限性:尽管模型整体性能较好,但在某些特定年龄段的预测上仍存在一定的偏差。例如,在幼龄期和老年期的样本中,模型的预测误差相对较大,准确率相对较低。这可能是由于以下几个原因:一方面,幼龄期宠物的外观特征变化较快,不同个体之间的差异较大,导致模型难以准确捕捉其年龄特征;另一方面,老年期宠物的外观特征变化趋于缓慢,且可能受到个体健康状况等多种因素的影响,增加了模型预测的难度。此外,测试集中的某些样本可能存在数据质量问题,如图像模糊、角度不正等,也会影响模型的预测效果。

综上所述,所构建的基于 ResNet-18 的宠物年龄识别模型在给定数据集上表现良好,能够有效实现宠物年龄的自动识别功能,为相关应用场景提供了一种可行的解决方案。未来可以考虑进一步优化模型结构、增加数据量或引入更多特征信息来进一步提升模型的性能和准确性。

import os

import torch

import torch.nn as nn

import numpy as np

from pathlib import Path

from PIL import Image

from tqdm import tqdm

import matplotlib.pyplot as plt

from torchvision import models, transforms

from torch.utils.data import Dataset, DataLoader, random_split

class DogAgeDataset(Dataset):

def __init__(self, root_dir, annotation_file, mode='train'):

self.root = Path(root_dir)

self.annotations = []

self.mode = mode

self.max_age = 192.0

label_path = self.root / "annotations" / annotation_file

with open(label_path, 'r') as f:

for line in f:

parts = line.strip().split()

if len(parts) >= 2:

img_folder = "trainset" if self.mode == 'train' else "valset"

img_path = self.root / img_folder / parts[0]

if img_path.exists():

age = float(parts[1])

if 0 <= age <= 192:

normalized_age = age / self.max_age

self.annotations.append((parts[0], normalized_age))

if mode == 'train':

self.transform = transforms.Compose([

transforms.Resize(256),

transforms.RandomCrop(224),

transforms.RandomHorizontalFlip(),

transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),

transforms.RandomRotation(15),

transforms.RandomAffine(degrees=0, translate=(0.1, 0.1), scale=(0.9, 1.1)),

transforms.ToTensor(),

transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

])

else:

self.transform = transforms.Compose([

transforms.Resize(256),

transforms.CenterCrop(224),

transforms.ToTensor(),

transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

])

def __len__(self):

return len(self.annotations)

def __getitem__(self, idx):

img_name, normalized_age = self.annotations[idx]

img_folder = "trainset" if self.mode == 'train' else "valset"

img_path = self.root / img_folder / img_name

try:

image = Image.open(img_path).convert('RGB')

image = self.transform(image)

return image, torch.tensor(normalized_age, dtype=torch.float32)

except Exception:

return self.__getitem__((idx + 1) % len(self))

def create_data_loaders(data_root, batch_size, num_workers):

train_dataset = DogAgeDataset(data_root, "train.txt", mode='train')

test_dataset = DogAgeDataset(data_root, "val.txt", mode='val')

train_size = int(0.8 * len(train_dataset))

val_size = len(train_dataset) - train_size

train_subset, val_subset = random_split(train_dataset, [train_size, val_size])

train_loader = DataLoader(train_subset, batch_size=batch_size, shuffle=True, num_workers=num_workers, pin_memory=True)

val_loader = DataLoader(val_subset, batch_size=batch_size // 2, shuffle=False, num_workers=num_workers, pin_memory=True)

test_loader = DataLoader(test_dataset, batch_size=batch_size // 2, shuffle=False, num_workers=num_workers, pin_memory=True)

return train_loader, val_loader, test_loader, train_dataset, test_dataset

class DogAgeModelV2(nn.Module):

def __init__(self, pretrained=True):

super().__init__()

base_model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)

for param in base_model.parameters():

param.requires_grad = True

self.feature_extractor = nn.Sequential(*list(base_model.children())[:-1])

self.regressor = nn.Sequential(

nn.Flatten(),

nn.Linear(512, 512),

nn.BatchNorm1d(512),

nn.ReLU(inplace=True),

nn.Dropout(0.4),

nn.Linear(512, 256),

nn.BatchNorm1d(256),

nn.ReLU(inplace=True),

nn.Linear(256, 1)

)

def forward(self, x):

x = self.feature_extractor(x)

x = self.regressor(x)

return x.squeeze(1)

def train_model(model, train_loader, val_loader, epochs=30, lr=1e-4, patience=10):

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = model.to(device)

criterion = nn.L1Loss()

optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=1e-5)

scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=5)

history = {'train_loss': [], 'val_loss': []}

best_val_loss = float('inf')

early_stopping_patience = patience

early_stopping_counter = 0

for epoch in range(epochs):

model.train()

train_loss = 0.0

for images, ages in train_loader:

images, ages = images.to(device), ages.to(device)

optimizer.zero_grad()

outputs = model(images)

loss = criterion(outputs, ages)

loss.backward()

optimizer.step()

train_loss += loss.item() * images.size(0)

train_loss /= len(train_loader.dataset)

history['train_loss'].append(train_loss)

val_loss = evaluate_model(model, val_loader, criterion, device)

history['val_loss'].append(val_loss)

scheduler.step(val_loss)

print(f"Epoch {epoch+1}/{epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f}")

if val_loss < best_val_loss:

best_val_loss = val_loss

torch.save(model.state_dict(), 'best_dog_age_model.pth')

print(f"Saved best model (val loss: {val_loss:.4f})")

early_stopping_counter = 0

else:

early_stopping_counter += 1

if early_stopping_counter >= early_stopping_patience:

print(f"Early stopping triggered (no improvement in {early_stopping_patience} epochs)")

break

plt.figure()

plt.plot(history['train_loss'], label='Train')

plt.plot(history['val_loss'], label='Val')

plt.title("Loss Curve")

plt.xlabel("Epoch")

plt.ylabel("Loss")

plt.legend()

plt.savefig("loss_curve.png")

return model

def evaluate_model(model, data_loader, criterion, device):

model.eval()

total_loss = 0.0

with torch.no_grad():

for images, ages in data_loader:

images, ages = images.to(device), ages.to(device)

outputs = model(images)

loss = criterion(outputs, ages)

total_loss += loss.item() * images.size(0)

return total_loss / len(data_loader.dataset)

def predict(model, data_loader, device):

model.eval()

preds = []

with torch.no_grad():

for images, _ in data_loader:

images = images.to(device)

outputs = model(images)

preds.extend(outputs.cpu().numpy())

return preds

def save_predictions(predictions, dataset, save_path):

with open(save_path, 'w') as f:

for i, pred in enumerate(predictions):

img_name, _ = dataset.annotations[i]

pred_age = pred * dataset.max_age

f.write(f"{img_name} {pred_age:.1f}n")

if __name__ == "__main__":

DATA_ROOT = "D:/Z_VS/A/data/raw"

BATCH_SIZE = 16

EPOCHS = 200

NUM_WORKERS = 4

train_loader, val_loader, test_loader, train_dataset, test_dataset = create_data_loaders(DATA_ROOT, BATCH_SIZE, NUM_WORKERS)

model = DogAgeModelV2(pretrained=True)

model = train_model(model, train_loader, val_loader, epochs=EPOCHS)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model.load_state_dict(torch.load('best_dog_age_model.pth'))

model.to(device)

predictions = predict(model, test_loader, device)

save_predictions(predictions, test_dataset, 'pred_result.txt')

print("Predictions saved to 'pred_result.txt'")

python

运行

相关知识

宠物年龄自动辨识学习赛
python宠物狗年龄
宠物狗年龄计算器python
python宠物信息管理系统的思路,方法与算法
机器学习之数据预处理(Python 实现)
基于python的桌面宠物需要配置什么环境
Python学习手册
吴恩达机器学习第五次作业(python 实现):偏差与方差
【计算机科学】【2019.03】基于深度学习的动物识别
【毕业设计】基于深度学习的水族馆生物识别 人工智能 深度学习 目标检测 Python

网址: CV学习赛宠物狗年龄自动识别的一种python实现方法 https://www.mcbbbk.com/newsview1253413.html

所属分类:萌宠日常
上一篇: 53宠物狗大赛
下一篇: 宠物狗识别大赛学习之旅

推荐分享