freestonehere/vit-dog

0

stars

17

commits

Python

primary language

Jun 14, 2026

updated

README

🐕 细粒度狗品种识别系统

基于深度学习的闭集 + 开集狗品种分类,支持 ViT / ResNet / EfficientNet / CLIP 多架构对比

GitHub HuggingFace


一、项目背景

细粒度图像分类(Fine-Grained Visual Categorization)是计算机视觉中的经典难题。狗品种识别作为其代表性任务,类间差异小、类内差异大——比如金毛和拉布拉多在毛色、体型上极为相似,而同一品种的不同个体可能因拍摄角度、光照、年龄等因素差异显著。

本项目围绕以下问题展开:

  • 闭集问题:在已知的 N 个品种中,准确识别出图片中的狗属于哪个品种
  • 开集问题:当图片中的狗品种不在已知列表中时,系统能否识别出"这不是我认识的品种",而不是强行给出一个错误答案

二、系统架构

flowchart TD
    INPUT["🖼️ 输入图片"]

    subgraph CLOSED["🔒 第一级:闭集分类(ViT)"]
        C1["ViT-L/16 预训练"]
        C2["加载 checkpoint 权重"]
        C3["Softmax → 100 类概率"]
        C1 --> C2 --> C3
    end

    subgraph OPEN["🔓 第二级:开集分类(CLIP)"]
        O1["CLIP 图像编码器"]
        O2["112 模板文本编码"]
        O3["余弦相似度 + 双阈值"]
        O1 --> O2 --> O3
    end

    INPUT --> CLOSED
    CLOSED -->|"conf ≥ 0.90 且 margin ≥ 0.2"| RESULT_CLOSED["✅ 返回品种名 (closed)"]
    CLOSED -->|"置信度不足"| OPEN
    OPEN -->|"sim ≥ 0.30 且 margin ≥ 0.10"| RESULT_OPEN["✅ 返回品种名 (open)"]
    OPEN -->|"相似度不足"| RESULT_UNKNOWN["❌ 返回 unknown"]

    classDef closed fill:#d1eafa,stroke:#0277bd,stroke-width:2px,rx:10,ry:10
    classDef open fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px,rx:10,ry:10
    classDef result fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,rx:10,ry:10
    classDef unknown fill:#ffcdd2,stroke:#c62828,stroke-width:2px,rx:10,ry:10

    class CLOSED closed
    class OPEN open
    class RESULT_CLOSED,RESULT_OPEN result
    class RESULT_UNKNOWN unknown

决策流程说明

  1. 第一级(闭集):图片先过 ViT-L/16 分类器。如果最高概率 ≥ 0.90 且 top1-top2 概率差 ≥ 0.2,直接返回品种名。
  2. 第二级(开集):如果 ViT 不确定,图片转交 CLIP。CLIP 用 112 个文本模板为每个已知品种构建文本特征,计算图像-文本余弦相似度。如果最大相似度 ≥ 0.30 且 top1-top2 差值 ≥ 0.10,返回品种名。
  3. 兜底:两级都不确定时,返回 unknown

为什么用两级? ViT 在已知品种上精度高,但遇到未知品种会"强行分类"(深度学习的过度自信问题)。CLIP 的零样本对比能力天然适合拒绝未知类别,两者互补。


三、数据集

Stanford Dogs Dataset

  • 来源Stanford Dogs Dataset
  • 规模:120 个品种、约 20,580 张图片
  • 用途:模型微调 + 验证

Atharva Dog Breeds Dataset

为什么评估需要两个数据集?

Stanford 数据集用于训练和验证,模型在该数据集上的表现可能因"见过"而偏高。Atharva 是一个完全独立的外部数据集,图片采集条件、品种命名方式、图片质量都与 Stanford 不同。在 Atharva 上评估能检验模型的泛化能力,避免"在自己出的卷子上考高分"的假象。


四、模型架构对比(闭集)

本项目实现了四种骨干网络的对比实验:

flowchart LR
    subgraph MODELS["模型架构"]
        V["ViT-L/16"]
        R["ResNet50 + Attention"]
        P["ResNet50 V2(纯)"]
        E["EfficientNet-B0"]
    end

    V -->|"src/"| D1["100 类闭集(不用 120 类是<br/>便于后面开集扩展)"]
    R -->|"src_resnet/"| D2["120 类闭集"]
    P -->|"src_resnet_pure/"| D3["120 类闭集"]
    E -->|"src_efficientnet/"| D4["120 类闭集"]

    classDef model fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,rx:8,ry:8
    class V,R,P,E model
模型骨干网络参数量特点
ViT-L/16Vision Transformer (Large)~307M全局自注意力,擅长捕捉长距离依赖
ResNet50 + AttentionResNet50 V2 + 自注意力模块~25M在残差网络基础上加入空间注意力机制
ResNet50 V2ResNet50 (纯)~25M经典基线,结构简单稳定
EfficientNet-B0EfficientNet~5.3M轻量化架构,参数量最少,效率最高

所有模型均使用 ImageNet 预训练权重,冻结主干网络,仅训练分类头。


五、项目结构

vit-dog/
│
├── input/                              # 数据集
│   ├── Stanford-Dogs-Dataset/          # Stanford 数据集
│   └── Atharva-Dog-Breeds-Dataset/     # Atharva 数据集
│
├── checkpoint/                         # 训练好的模型权重
│   ├── ViT-top80.pt                    # ViT (前 80 类)
│   ├── ViT-top100.pt                   # ViT (前 100 类)
│   └── ViT-full120.pt                  # ViT (全部 120 类)
│
├── src/                                # ViT-L/16 闭集分类
│   ├── model.py                        # PretrainViT 模型定义
│   ├── dataset.py                      # 数据集加载
│   ├── train.py                        # 训练脚本
│   ├── inference.py                    # 推理 + 生成提交文件
│   └── config.py                       # 路径与超参数配置
│
├── src_resnet/                         # ResNet50 + 自注意力
├── src_resnet_pure/                    # ResNet50 V2(纯)
├── src_efficientnet/                   # EfficientNet-B0
├── src_vit_org/                        # ViT 原始版本(参考)
│
├── open_finegrained_stanford/          # 开集系统(Stanford 评估)
├── open_finegrained_Atharva_demo/      # 开集系统(Atharva 评估)
├── open_finegrained_stanford_param_analysis/  # 阈值参数分析
│
├── FG-CLIP/                            # FG-CLIP 源码仓库
├── fg-clip-base/                       # FG-CLIP HuggingFace 推理包
└── src_FG_CLIP/                        # FG-CLIP 实验代码

六、开集识别原理

开集分类器不使用 Softmax,而是基于 CLIP 的零样本对比学习

flowchart LR
    subgraph OFFLINE["离线阶段:文本特征预计算"]
        T1["112 个文本模板"]
        T2["品种名填入模板"]
        T3["CLIP 文本编码器"]
        T4["取均值 → 文本特征向量"]
        T1 --> T2 --> T3 --> T4
    end

    subgraph ONLINE["在线阶段:推理"]
        I1["输入图片"]
        I2["CLIP 图像编码器"]
        I3["余弦相似度"]
        I4["双阈值决策"]
        I1 --> I2 --> I3 --> I4
    end

    T4 -->|"预计算好的特征矩阵"| I3

    classDef offline fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,rx:8,ry:8
    classDef online fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,rx:8,ry:8
    class OFFLINE offline
    class ONLINE online

112 个文本模板

模板覆盖多个维度,提升文本特征的鲁棒性:

维度示例
基础a photo of a {}
场景a photo of a {} running on the green grass
动作a photo of a {} wagging its tail and barking happily
外观a photo of a fluffy {} with golden fur and floppy ears
状态a photo of a wet {} after playing in the puddle
交互a photo of a {} playing fetch with its owner in the park
视角a macro photo of the {}'s paw pads and tiny claws

双阈值决策

  • 相似度阈值 (OPEN_SIM_THRESHOLD = 0.30):最大余弦相似度必须超过此值
  • 间距阈值 (OPEN_MARGIN_THRESHOLD = 0.10):top1 与 top2 的差值必须超过此值

两个条件同时满足才认为是"已知品种",否则判为 unknown


七、环境配置

# 创建 conda 环境
conda create -n Static_Learn python=3.10 -y
conda activate Static_Learn

# 安装依赖
pip3 install typing-extensions==4.10.0
pip3 install torch torchvision torchaudio --index-url https://mirrors.nju.edu.cn/pytorch/whl/cu126
pip install pandas scikit-learn pillow tqdm matplotlib transformers gradio fastapi uvicorn

八、快速开始

闭集训练(以 ViT 为例)

cd src/
python train.py

闭集推理(生成 submission.csv,没有其他输出)

cd src/
python inference.py

开集评估

cd open_finegrained_Atharva_demo/
python run.py

启动 Web 演示

cd open_finegrained_Atharva_demo/demo/
# 需先修改 open_finegrained_Atharva_demo/config.py 中的 SRC_VIT_MODEL_PATH 参数
# 为指向 ViT-top100.pt 的权重路径
python gradio_app.py
# 浏览器访问 http://127.0.0.1:7861

九、权重文件

Model-Weights

文件说明
ViT-top80.ptViT-L/16,前 80 个品种(用于参数分析)
ViT-top100.ptViT-L/16,前 100 个品种(最终权重)
ViT-full120.ptViT-L/16,全部 120 个品种(中期模型,纯闭集分类)

十、参考

Contributors

freestonehere

16 commits

JunchenShen

1 commits

freestonehere/vit-dog

0

stars

17

commits

Python

primary language

Jun 14, 2026

updated

README

🐕 细粒度狗品种识别系统

基于深度学习的闭集 + 开集狗品种分类,支持 ViT / ResNet / EfficientNet / CLIP 多架构对比

GitHub HuggingFace


一、项目背景

细粒度图像分类(Fine-Grained Visual Categorization)是计算机视觉中的经典难题。狗品种识别作为其代表性任务,类间差异小、类内差异大——比如金毛和拉布拉多在毛色、体型上极为相似,而同一品种的不同个体可能因拍摄角度、光照、年龄等因素差异显著。

本项目围绕以下问题展开:

  • 闭集问题:在已知的 N 个品种中,准确识别出图片中的狗属于哪个品种
  • 开集问题:当图片中的狗品种不在已知列表中时,系统能否识别出"这不是我认识的品种",而不是强行给出一个错误答案

二、系统架构

flowchart TD
    INPUT["🖼️ 输入图片"]

    subgraph CLOSED["🔒 第一级:闭集分类(ViT)"]
        C1["ViT-L/16 预训练"]
        C2["加载 checkpoint 权重"]
        C3["Softmax → 100 类概率"]
        C1 --> C2 --> C3
    end

    subgraph OPEN["🔓 第二级:开集分类(CLIP)"]
        O1["CLIP 图像编码器"]
        O2["112 模板文本编码"]
        O3["余弦相似度 + 双阈值"]
        O1 --> O2 --> O3
    end

    INPUT --> CLOSED
    CLOSED -->|"conf ≥ 0.90 且 margin ≥ 0.2"| RESULT_CLOSED["✅ 返回品种名 (closed)"]
    CLOSED -->|"置信度不足"| OPEN
    OPEN -->|"sim ≥ 0.30 且 margin ≥ 0.10"| RESULT_OPEN["✅ 返回品种名 (open)"]
    OPEN -->|"相似度不足"| RESULT_UNKNOWN["❌ 返回 unknown"]

    classDef closed fill:#d1eafa,stroke:#0277bd,stroke-width:2px,rx:10,ry:10
    classDef open fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px,rx:10,ry:10
    classDef result fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px,rx:10,ry:10
    classDef unknown fill:#ffcdd2,stroke:#c62828,stroke-width:2px,rx:10,ry:10

    class CLOSED closed
    class OPEN open
    class RESULT_CLOSED,RESULT_OPEN result
    class RESULT_UNKNOWN unknown

决策流程说明

  1. 第一级(闭集):图片先过 ViT-L/16 分类器。如果最高概率 ≥ 0.90 且 top1-top2 概率差 ≥ 0.2,直接返回品种名。
  2. 第二级(开集):如果 ViT 不确定,图片转交 CLIP。CLIP 用 112 个文本模板为每个已知品种构建文本特征,计算图像-文本余弦相似度。如果最大相似度 ≥ 0.30 且 top1-top2 差值 ≥ 0.10,返回品种名。
  3. 兜底:两级都不确定时,返回 unknown

为什么用两级? ViT 在已知品种上精度高,但遇到未知品种会"强行分类"(深度学习的过度自信问题)。CLIP 的零样本对比能力天然适合拒绝未知类别,两者互补。


三、数据集

Stanford Dogs Dataset

  • 来源Stanford Dogs Dataset
  • 规模:120 个品种、约 20,580 张图片
  • 用途:模型微调 + 验证

Atharva Dog Breeds Dataset

为什么评估需要两个数据集?

Stanford 数据集用于训练和验证,模型在该数据集上的表现可能因"见过"而偏高。Atharva 是一个完全独立的外部数据集,图片采集条件、品种命名方式、图片质量都与 Stanford 不同。在 Atharva 上评估能检验模型的泛化能力,避免"在自己出的卷子上考高分"的假象。


四、模型架构对比(闭集)

本项目实现了四种骨干网络的对比实验:

flowchart LR
    subgraph MODELS["模型架构"]
        V["ViT-L/16"]
        R["ResNet50 + Attention"]
        P["ResNet50 V2(纯)"]
        E["EfficientNet-B0"]
    end

    V -->|"src/"| D1["100 类闭集(不用 120 类是<br/>便于后面开集扩展)"]
    R -->|"src_resnet/"| D2["120 类闭集"]
    P -->|"src_resnet_pure/"| D3["120 类闭集"]
    E -->|"src_efficientnet/"| D4["120 类闭集"]

    classDef model fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,rx:8,ry:8
    class V,R,P,E model
模型骨干网络参数量特点
ViT-L/16Vision Transformer (Large)~307M全局自注意力,擅长捕捉长距离依赖
ResNet50 + AttentionResNet50 V2 + 自注意力模块~25M在残差网络基础上加入空间注意力机制
ResNet50 V2ResNet50 (纯)~25M经典基线,结构简单稳定
EfficientNet-B0EfficientNet~5.3M轻量化架构,参数量最少,效率最高

所有模型均使用 ImageNet 预训练权重,冻结主干网络,仅训练分类头。


五、项目结构

vit-dog/
│
├── input/                              # 数据集
│   ├── Stanford-Dogs-Dataset/          # Stanford 数据集
│   └── Atharva-Dog-Breeds-Dataset/     # Atharva 数据集
│
├── checkpoint/                         # 训练好的模型权重
│   ├── ViT-top80.pt                    # ViT (前 80 类)
│   ├── ViT-top100.pt                   # ViT (前 100 类)
│   └── ViT-full120.pt                  # ViT (全部 120 类)
│
├── src/                                # ViT-L/16 闭集分类
│   ├── model.py                        # PretrainViT 模型定义
│   ├── dataset.py                      # 数据集加载
│   ├── train.py                        # 训练脚本
│   ├── inference.py                    # 推理 + 生成提交文件
│   └── config.py                       # 路径与超参数配置
│
├── src_resnet/                         # ResNet50 + 自注意力
├── src_resnet_pure/                    # ResNet50 V2(纯)
├── src_efficientnet/                   # EfficientNet-B0
├── src_vit_org/                        # ViT 原始版本(参考)
│
├── open_finegrained_stanford/          # 开集系统(Stanford 评估)
├── open_finegrained_Atharva_demo/      # 开集系统(Atharva 评估)
├── open_finegrained_stanford_param_analysis/  # 阈值参数分析
│
├── FG-CLIP/                            # FG-CLIP 源码仓库
├── fg-clip-base/                       # FG-CLIP HuggingFace 推理包
└── src_FG_CLIP/                        # FG-CLIP 实验代码

六、开集识别原理

开集分类器不使用 Softmax,而是基于 CLIP 的零样本对比学习

flowchart LR
    subgraph OFFLINE["离线阶段:文本特征预计算"]
        T1["112 个文本模板"]
        T2["品种名填入模板"]
        T3["CLIP 文本编码器"]
        T4["取均值 → 文本特征向量"]
        T1 --> T2 --> T3 --> T4
    end

    subgraph ONLINE["在线阶段:推理"]
        I1["输入图片"]
        I2["CLIP 图像编码器"]
        I3["余弦相似度"]
        I4["双阈值决策"]
        I1 --> I2 --> I3 --> I4
    end

    T4 -->|"预计算好的特征矩阵"| I3

    classDef offline fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,rx:8,ry:8
    classDef online fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,rx:8,ry:8
    class OFFLINE offline
    class ONLINE online

112 个文本模板

模板覆盖多个维度,提升文本特征的鲁棒性:

维度示例
基础a photo of a {}
场景a photo of a {} running on the green grass
动作a photo of a {} wagging its tail and barking happily
外观a photo of a fluffy {} with golden fur and floppy ears
状态a photo of a wet {} after playing in the puddle
交互a photo of a {} playing fetch with its owner in the park
视角a macro photo of the {}'s paw pads and tiny claws

双阈值决策

  • 相似度阈值 (OPEN_SIM_THRESHOLD = 0.30):最大余弦相似度必须超过此值
  • 间距阈值 (OPEN_MARGIN_THRESHOLD = 0.10):top1 与 top2 的差值必须超过此值

两个条件同时满足才认为是"已知品种",否则判为 unknown


七、环境配置

# 创建 conda 环境
conda create -n Static_Learn python=3.10 -y
conda activate Static_Learn

# 安装依赖
pip3 install typing-extensions==4.10.0
pip3 install torch torchvision torchaudio --index-url https://mirrors.nju.edu.cn/pytorch/whl/cu126
pip install pandas scikit-learn pillow tqdm matplotlib transformers gradio fastapi uvicorn

八、快速开始

闭集训练(以 ViT 为例)

cd src/
python train.py

闭集推理(生成 submission.csv,没有其他输出)

cd src/
python inference.py

开集评估

cd open_finegrained_Atharva_demo/
python run.py

启动 Web 演示

cd open_finegrained_Atharva_demo/demo/
# 需先修改 open_finegrained_Atharva_demo/config.py 中的 SRC_VIT_MODEL_PATH 参数
# 为指向 ViT-top100.pt 的权重路径
python gradio_app.py
# 浏览器访问 http://127.0.0.1:7861

九、权重文件

Model-Weights

文件说明
ViT-top80.ptViT-L/16,前 80 个品种(用于参数分析)
ViT-top100.ptViT-L/16,前 100 个品种(最终权重)
ViT-full120.ptViT-L/16,全部 120 个品种(中期模型,纯闭集分类)

十、参考

Contributors

freestonehere

16 commits

JunchenShen

1 commits

Languages

Python

99.3%