尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI导论实践指南:从CNN原理到PyTorch猫狗分类项目全解析

AI导论实践指南:从CNN原理到PyTorch猫狗分类项目全解析 如果你是一名计算机相关专业的学生正在为《人工智能导论》这门课的期末大作业或实践报告发愁那么这篇文章就是为你准备的。这门课听起来高大上但落到实践环节很多同学都会陷入迷茫选题太简单显得没深度选题太难又无从下手代码跑不起来模型训练不动最后报告写成了流水账或者干脆变成了“调包侠”的说明书。这背后真正的问题是缺乏一个将AI理论知识与具体工程实践有效结合的“脚手架”。本文将以一份虚构但极具代表性的《人工智能导论期末实践报告2026春季12班》为蓝本为你拆解一份优秀实践报告的核心要素。我们不止步于“做什么”更要深入“为什么这么做”以及“如何做得更好”。你将看到如何从一个具体的、可实现的选题出发完成从环境搭建、模型训练、结果分析到报告撰写的全流程并避开那些新手最容易踩的“坑”。1. 一份优秀的AI实践报告究竟在考察什么在开始动手之前我们必须先理解课程实践的目标。它绝不是让你复现一个最前沿的SOTA模型也不是比拼谁的GPU更强大。《人工智能导论》的实践核心在于“理解与验证”。教授希望看到的是对核心概念的理解你是否真的理解了监督学习、无监督学习、神经网络、损失函数、优化器等基础概念而不是仅仅会调用model.fit()。将理论转化为实践的能力能否针对一个具体问题选择合适的模型、准备数据、设计训练流程并评估结果。系统的工程化思维从问题定义、数据预处理、模型构建、训练调试到结果分析是否有一个清晰、完整的逻辑链条。分析与反思的能力结果好为什么好结果不好问题出在哪里能否提出改进方向因此选题的合适性远比复杂性重要。一个在MNIST手写数字识别上深入分析不同模型性能差异的报告其价值可能远高于一个勉强跑通但完全不懂原理的复杂目标检测项目。基于此我们本次的实践报告将围绕一个经典且数据集易于获取的任务展开基于卷积神经网络CNN的图像分类任务。具体课题定为“基于PyTorch的猫狗图像分类实践与不同模型性能对比分析”。这个选题直接关联课程中的机器学习、神经网络章节实践过程能完整覆盖AI项目生命周期。2. 环境准备打造可复现的AI实验基础一个稳定、清晰的环境是成功的一半。很多同学的作业无法被助教复现问题首先就出在环境上。我们强烈建议使用Conda进行环境管理它能完美解决Python包版本冲突这个世界性难题。2.1 创建并激活专属的Conda环境打开终端Windows: Anaconda Prompt / Cmd, Linux/macOS: Terminal执行以下命令# 创建一个名为 ai_intro_project 的Python 3.8环境 conda create -n ai_intro_project python3.8 -y # 激活该环境 conda activate ai_intro_project激活后你的命令行提示符前通常会显示(ai_intro_project)表明你已进入该独立环境。2.2 安装核心依赖库我们将使用PyTorch作为深度学习框架它相比TensorFlow对新手更友好动态图机制也更利于调试。根据你的电脑是否有NVIDIA显卡安装命令不同。首先安装通用数据科学库pip install numpy pandas matplotlib seaborn jupyter notebook scikit-learn然后安装PyTorch。访问 PyTorch官网 获取最适合你系统的安装命令是最稳妥的方式。以下以主流情况为例无独立显卡仅用CPUpip install torch torchvision torchaudio有NVIDIA显卡需已安装CUDA驱动假设CUDA 11.8请以官网生成命令为准例如pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118验证安装创建一个Python脚本或直接在Jupyter Notebook中运行import torch import torchvision print(fPyTorch版本: {torch.__version__}) print(fCUDA是否可用: {torch.cuda.is_available()}) # 如果CUDA可用输出显卡信息 if torch.cuda.is_available(): print(f显卡设备: {torch.cuda.get_device_name(0)})如果成功输出版本号说明环境配置正确。3. 项目结构与数据准备清晰的目录结构体现了你的工程素养。在项目根目录下创建如下文件夹ai_intro_final_project/ ├── data/ # 存放数据集 │ ├── train/ # 训练集 │ │ ├── cat/ # 猫的图片 │ │ └── dog/ # 狗的图片 │ └── test/ # 测试集同样有cat, dog子文件夹 ├── src/ # 源代码 │ ├── data_loader.py # 数据加载与预处理模块 │ ├── model.py # 模型定义模块 │ ├── train.py # 模型训练脚本 │ ├── evaluate.py # 模型评估脚本 │ └── utils.py # 工具函数如可视化 ├── outputs/ # 输出目录 │ ├── models/ # 保存训练好的模型权重 │ ├── logs/ # 训练日志 │ └── figures/ # 生成的图表 ├── requirements.txt # 项目依赖列表 └── report/ # 报告相关内容如最终报告PDF、PPT3.1 获取与组织数据我们使用经典的Kaggle“Dogs vs Cats”数据集的一个子集。你可以从Kaggle官网下载完整数据集或使用一些公开的小样本集。为了快速实验我们可以在代码中自动下载一个简化版但为了体现完整流程我们假设你已经将图片按上述结构放好。关键点务必保证data/train/cat和data/train/dog文件夹下分别只有猫和狗的图片。这是torchvision.datasets.ImageFolder能够自动识别标签的前提。4. 核心代码实现拆解接下来我们进入核心环节。我们将代码模块化这不仅使结构清晰也便于报告中对每个部分进行说明。4.1 数据加载与预处理 (src/data_loader.py)数据是AI模型的“燃料”预处理至关重要。# file: src/data_loader.py import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import os def get_data_loaders(data_dir../data, batch_size32, img_size224): 创建训练和测试数据加载器。 参数: data_dir: 数据根目录路径 batch_size: 批大小 img_size: 图像缩放尺寸 返回: train_loader, test_loader, class_names # 数据增强仅在训练集使用用于提升模型泛化能力 train_transforms transforms.Compose([ transforms.RandomResizedCrop(img_size), # 随机裁剪缩放 transforms.RandomHorizontalFlip(), # 随机水平翻转 transforms.ToTensor(), # 转换为Tensor并归一化到[0,1] transforms.Normalize([0.485, 0.456, 0.406], # ImageNet均值 [0.229, 0.224, 0.225]) # ImageNet标准差 ]) # 测试集只需进行基础转换和归一化 test_transforms transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(img_size), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) # 使用ImageFolder自动根据子文件夹名生成标签 train_dataset datasets.ImageFolder(rootos.path.join(data_dir, train), transformtrain_transforms) test_dataset datasets.ImageFolder(rootos.path.join(data_dir, test), transformtest_transforms) # 创建数据加载器训练集打乱顺序测试集不需要 train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue, num_workers2) test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse, num_workers2) # 获取类别名称例如 [cat, dog] class_names train_dataset.classes return train_loader, test_loader, class_names if __name__ __main__: # 简单测试一下数据加载 train_loader, test_loader, class_names get_data_loaders(batch_size4) print(f类别: {class_names}) images, labels next(iter(train_loader)) print(f一个批次的图像形状: {images.shape}) # [batch, channel, height, width] print(f对应的标签: {labels})代码解释transforms定义了图像预处理流水线。RandomHorizontalFlip是数据增强让模型看到更多样的数据防止过拟合。Normalize使用ImageNet的均值和标准差进行归一化这是使用在ImageNet上预训练模型时的常见做法。DataLoader负责批量读取数据shuffleTrue在训练时打乱数据顺序使每个epoch的数据分布都不同。4.2 模型定义 (src/model.py)我们将实现两个模型进行对比一个自定义的简单CNN用于理解原理和一个使用预训练的ResNet18体现迁移学习的威力。# file: src/model.py import torch.nn as nn import torch.nn.functional as F from torchvision import models class SimpleCNN(nn.Module): 自定义的简单卷积神经网络 def __init__(self, num_classes2): super(SimpleCNN, self).__init__() # 卷积层块 (提取特征) self.conv1 nn.Conv2d(3, 16, kernel_size3, padding1) # 输入3通道(RGB)输出16通道 self.pool nn.MaxPool2d(2, 2) # 池化层尺寸减半 self.conv2 nn.Conv2d(16, 32, kernel_size3, padding1) self.conv3 nn.Conv2d(32, 64, kernel_size3, padding1) # 全连接层块 (分类) # 特征图尺寸计算输入224x224经过三次pool(2,2)后变为 224/(2^3)28 self.fc1 nn.Linear(64 * 28 * 28, 512) # 64通道 * 28*28 self.fc2 nn.Linear(512, num_classes) self.dropout nn.Dropout(0.5) # Dropout防止过拟合 def forward(self, x): x self.pool(F.relu(self.conv1(x))) x self.pool(F.relu(self.conv2(x))) x self.pool(F.relu(self.conv3(x))) # 将多维特征图“展平”成一维向量以便输入全连接层 x x.view(-1, 64 * 28 * 28) x self.dropout(F.relu(self.fc1(x))) x self.fc2(x) # 输出层不需要激活函数损失函数会处理 return x def get_pretrained_resnet(num_classes2): 获取预训练的ResNet18模型并替换其最后一层全连接层以适应我们的分类任务。 参数: num_classes: 输出类别数猫和狗所以是2 返回: model: 修改后的ResNet18模型 # 加载在ImageNet上预训练的ResNet18模型 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) # 冻结所有卷积层的参数在训练初期不更新它们 # 这样我们可以先只训练新添加的全连接层节省计算并利用预训练特征 for param in model.parameters(): param.requires_grad False # 获取原模型最后一层全连接层fc的输入特征数 num_ftrs model.fc.in_features # 替换为一个新的全连接层输出维度为我们的类别数 # nn.Linear会自动初始化该层的权重和偏置 model.fc nn.Linear(num_ftrs, num_classes) # 只让新替换的fc层参数可训练 for param in model.fc.parameters(): param.requires_grad True return model代码解释SimpleCNN手动定义了三个“卷积ReLU池化”的块最后接两个全连接层。这是理解CNN工作原理的绝佳示例。get_pretrained_resnet使用了迁移学习。weights参数加载预训练权重。requires_gradFalse冻结了卷积层我们只训练最后的fc层。这能极大加快训练速度并在小数据集上获得更好效果。4.3 模型训练脚本 (src/train.py)这是整个项目的引擎负责驱动训练循环。# file: src/train.py import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import time import copy from tqdm import tqdm # 用于显示进度条 import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src.data_loader import get_data_loaders from src.model import SimpleCNN, get_pretrained_resnet def train_model(model, criterion, optimizer, scheduler, dataloaders, dataset_sizes, device, num_epochs10, model_namemodel): 通用模型训练函数 参数: model: 要训练的模型 criterion: 损失函数 optimizer: 优化器 scheduler: 学习率调度器 dataloaders: 包含train和val的DataLoader字典 dataset_sizes: 包含train和val数据集大小的字典 device: 训练设备CPU或GPU num_epochs: 训练轮数 model_name: 模型名称用于保存 返回: model: 训练好的最佳模型 history: 训练历史记录损失和准确率 since time.time() best_model_wts copy.deepcopy(model.state_dict()) best_acc 0.0 history {train_loss: [], train_acc: [], val_loss: [], val_acc: []} for epoch in range(num_epochs): print(fEpoch {epoch1}/{num_epochs}) print(- * 40) # 每个epoch都有训练和验证阶段 for phase in [train, val]: if phase train: model.train() # 设置模型为训练模式 else: model.eval() # 设置模型为评估模式 running_loss 0.0 running_corrects 0 # 使用tqdm包装数据加载器以显示进度条 data_loader dataloaders[phase] for inputs, labels in tqdm(data_loader, descf{phase.capitalize()} Epoch {epoch1}): inputs inputs.to(device) labels labels.to(device) # 梯度清零 optimizer.zero_grad() # 前向传播 with torch.set_grad_enabled(phase train): outputs model(inputs) _, preds torch.max(outputs, 1) loss criterion(outputs, labels) # 只在训练阶段进行反向传播和优化 if phase train: loss.backward() optimizer.step() # 统计 running_loss loss.item() * inputs.size(0) running_corrects torch.sum(preds labels.data) if phase train and scheduler is not None: scheduler.step() epoch_loss running_loss / dataset_sizes[phase] epoch_acc running_corrects.double() / dataset_sizes[phase] # 记录历史 history[f{phase}_loss].append(epoch_loss) history[f{phase}_acc].append(epoch_acc.item()) print(f{phase.capitalize()} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}) # 深度复制表现最好的模型权重 if phase val and epoch_acc best_acc: best_acc epoch_acc best_model_wts copy.deepcopy(model.state_dict()) # 保存最佳模型 torch.save(best_model_wts, f../outputs/models/{model_name}_best.pth) print(f Best model saved with Val Acc: {best_acc:.4f}) print() time_elapsed time.time() - since print(fTraining complete in {time_elapsed // 60:.0f}m {time_elapsed % 60:.0f}s) print(fBest val Acc: {best_acc:.4f}) # 加载最佳模型权重 model.load_state_dict(best_model_wts) return model, history def main(): # 设置设备 device torch.device(cuda:0 if torch.cuda.is_available() else cpu) print(f使用设备: {device}) # 超参数设置 batch_size 32 num_epochs 15 # SimpleCNN可以多训几轮ResNet可以少一些 learning_rate 0.001 # 获取数据 print(加载数据...) train_loader, val_loader, class_names get_data_loaders(batch_sizebatch_size) dataloaders {train: train_loader, val: val_loader} dataset_sizes {train: len(train_loader.dataset), val: len(val_loader.dataset)} print(f类别: {class_names}) print(f训练集大小: {dataset_sizes[train]}, 验证集大小: {dataset_sizes[val]}) # --- 训练 SimpleCNN --- print(\n *50) print(开始训练 SimpleCNN 模型) print(*50) model_cnn SimpleCNN(num_classeslen(class_names)).to(device) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model_cnn.parameters(), lrlearning_rate) # 每7个epoch将学习率乘以0.1 scheduler lr_scheduler.StepLR(optimizer, step_size7, gamma0.1) model_cnn, history_cnn train_model( model_cnn, criterion, optimizer, scheduler, dataloaders, dataset_sizes, device, num_epochsnum_epochs, model_namesimple_cnn ) # --- 训练 ResNet18 (迁移学习) --- print(\n *50) print(开始训练 ResNet18 (迁移学习) 模型) print(*50) model_resnet get_pretrained_resnet(num_classeslen(class_names)).to(device) # 只训练最后一层所以学习率可以设大一点 optimizer_resnet optim.Adam(model_resnet.fc.parameters(), lrlearning_rate*10) # 对于微调学习率调度策略可以不同 scheduler_resnet lr_scheduler.StepLR(optimizer_resnet, step_size5, gamma0.1) model_resnet, history_resnet train_model( model_resnet, criterion, optimizer_resnet, scheduler_resnet, dataloaders, dataset_sizes, device, num_epochs10, model_nameresnet18 # ResNet训练轮次可以少一些 ) # 保存训练历史用于后续绘图分析 torch.save(history_cnn, ../outputs/logs/history_cnn.pth) torch.save(history_resnet, ../outputs/logs/history_resnet.pth) print(所有模型训练完成) if __name__ __main__: main()5. 模型评估与结果可视化 (src/evaluate.py)训练完成后我们需要科学地评估模型性能并用图表直观展示。# file: src/evaluate.py import torch import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns from src.data_loader import get_data_loaders from src.model import SimpleCNN, get_pretrained_resnet import os def evaluate_model(model, test_loader, device, class_names, model_nameModel): 在测试集上评估模型并打印详细指标。 model.eval() all_preds [] all_labels [] with torch.no_grad(): for inputs, labels in test_loader: inputs inputs.to(device) labels labels.to(device) outputs model(inputs) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) # 计算并打印分类报告精确率、召回率、F1分数 print(f\n{*60}) print(f{model_name} 分类报告:) print(*60) print(classification_report(all_labels, all_preds, target_namesclass_names)) # 计算并绘制混淆矩阵 cm confusion_matrix(all_labels, all_preds) plt.figure(figsize(8,6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.title(f{model_name} - 混淆矩阵) plt.ylabel(真实标签) plt.xlabel(预测标签) plt.tight_layout() plt.savefig(f../outputs/figures/confusion_matrix_{model_name.lower()}.png, dpi300) plt.show() # 计算整体准确率 accuracy np.sum(np.array(all_preds) np.array(all_labels)) / len(all_labels) print(f{model_name} 在测试集上的整体准确率: {accuracy:.4f}) return accuracy def plot_training_history(history_dict, model_name): 绘制训练过程中的损失和准确率曲线。 epochs range(1, len(history_dict[train_loss]) 1) fig, (ax1, ax2) plt.subplots(1, 2, figsize(15, 5)) # 绘制损失曲线 ax1.plot(epochs, history_dict[train_loss], b-, label训练损失) ax1.plot(epochs, history_dict[val_loss], r-, label验证损失) ax1.set_title(f{model_name} - 训练与验证损失) ax1.set_xlabel(Epochs) ax1.set_ylabel(Loss) ax1.legend() ax1.grid(True) # 绘制准确率曲线 ax2.plot(epochs, history_dict[train_acc], b-, label训练准确率) ax2.plot(epochs, history_dict[val_acc], r-, label验证准确率) ax2.set_title(f{model_name} - 训练与验证准确率) ax2.set_xlabel(Epochs) ax2.set_ylabel(Accuracy) ax2.legend() ax2.grid(True) plt.tight_layout() plt.savefig(f../outputs/figures/training_history_{model_name.lower()}.png, dpi300) plt.show() def main(): device torch.device(cuda:0 if torch.cuda.is_available() else cpu) print(f使用设备: {device}) # 加载测试数据 _, test_loader, class_names get_data_loaders(batch_size32) print(f测试集大小: {len(test_loader.dataset)}) # --- 评估 SimpleCNN --- print(\n评估 SimpleCNN 模型...) model_cnn SimpleCNN(num_classeslen(class_names)).to(device) # 加载之前保存的最佳权重 model_cnn.load_state_dict(torch.load(../outputs/models/simple_cnn_best.pth, map_locationdevice)) acc_cnn evaluate_model(model_cnn, test_loader, device, class_names, SimpleCNN) # --- 评估 ResNet18 --- print(\n评估 ResNet18 模型...) model_resnet get_pretrained_resnet(num_classeslen(class_names)).to(device) model_resnet.load_state_dict(torch.load(../outputs/models/resnet18_best.pth, map_locationdevice)) acc_resnet evaluate_model(model_resnet, test_loader, device, class_names, ResNet18 (迁移学习)) # --- 加载并绘制训练历史 --- print(\n绘制训练历史曲线...) history_cnn torch.load(../outputs/logs/history_cnn.pth, map_locationcpu) history_resnet torch.load(../outputs/logs/history_resnet.pth, map_locationcpu) plot_training_history(history_cnn, SimpleCNN) plot_training_history(history_resnet, ResNet18) # --- 模型对比 --- print(\n *60) print(模型性能对比总结) print(*60) print(f{模型名称:25} {测试准确率:15}) print(f{-*25} {-*15}) print(f{SimpleCNN:25} {acc_cnn:.4f}) print(f{ResNet18 (迁移学习):25} {acc_resnet:.4f}) print(*60) if __name__ __main__: main()6. 运行结果与效果验证按照上述步骤你应该能成功运行整个项目。以下是预期的关键输出和验证点训练过程输出在终端或Notebook中你会看到每个epoch的训练和验证损失、准确率。观察验证准确率是否在逐步提升并最终趋于稳定。如果训练准确率远高于验证准确率可能是过拟合。模型保存在outputs/models/目录下应生成simple_cnn_best.pth和resnet18_best.pth两个文件分别对应两个模型在验证集上表现最好的权重。评估报告运行evaluate.py后控制台会打印出详细的分类报告包括每个类别的精确率、召回率、F1分数和整体准确率。例如SimpleCNN 分类报告: precision recall f1-score support cat 0.85 0.82 0.83 500 dog 0.83 0.86 0.84 500 accuracy 0.84 1000可视化图表在outputs/figures/目录下应生成四张图confusion_matrix_simplecnn.png和confusion_matrix_resnet18.png混淆矩阵热力图直观显示模型在猫狗两类上的分类错误情况。training_history_simplecnn.png和training_history_resnet18.png训练损失/准确率曲线用于分析模型是否收敛、是否过拟合。如何判断成功基础成功代码能从头到尾无错误运行生成模型文件和图表。良好表现SimpleCNN在测试集上准确率能达到80%以上ResNet18能达到90%以上。训练曲线显示验证损失在下降后趋于平稳验证准确率在上升后趋于平稳。优秀分析你能从混淆矩阵中看出模型更擅长识别猫还是狗能从训练曲线中分析出SimpleCNN可能更早出现过拟合能解释为什么ResNet18表现更好预训练特征、更深网络。7. 常见问题与排查思路在实践过程中你几乎一定会遇到以下问题。这里提供排查思路问题现象可能原因排查方式解决方案RuntimeError: CUDA out of memory显卡显存不足批次大小batch_size或图像尺寸img_size太大。1. 使用nvidia-smi命令查看显存占用。2. 尝试减小batch_size如从32降到16。1. 减小batch_size。2. 减小img_size如从224降到128。3. 在代码中添加torch.cuda.empty_cache()。4. 使用pin_memoryFalse。训练损失Loss为NaN学习率learning_rate过高导致梯度爆炸。检查第一个epoch的损失值是否突然变得极大或直接变成NaN。大幅降低学习率如从0.001降到0.0001或使用梯度裁剪torch.nn.utils.clip_grad_norm_。验证准确率远低于训练准确率模型过拟合。在训练集上表现好但泛化能力差。观察训练曲线训练准确率持续上升而验证准确率停滞或下降。1. 增加数据增强的强度如随机旋转、颜色抖动。2. 增强Dropout强度或添加更多Dropout层。3. 使用更小的模型。4. 收集更多训练数据。FileNotFoundError或数据集加载错误数据路径错误或图片没有按cat/,dog/子文件夹存放。1. 检查data_dir参数路径是否正确。2. 检查data/train/目录下是否有cat和dog文件夹。1. 使用绝对路径或仔细检查相对路径。2. 确保数据集结构符合ImageFolder要求。训练速度极慢1. 使用了CPU而非GPU。2.num_workers设置过小默认为0数据加载成瓶颈。1. 检查device输出是否为cuda:0。2. 观察任务管理器看CPU或GPU哪个利用率高。1. 确认PyTorch CUDA版本安装正确。2. 适当增加DataLoader的num_workers如设置为4或8。3. 使用pin_memoryTrue当使用GPU时。迁移学习模型ResNet准确率不升反降1. 学习率可能不合适。2. 预训练模型的特征提取层被错误地更新了。检查是否在训练ResNet时错误地将所有参数都设置了requires_gradTrue。1. 确保仅训练最后的全连接层model.fc。2. 为微调设置更小的学习率通常是基础学习率的1/10。3. 可以先冻结训练几轮再解冻部分深层网络进行微调。8. 最佳实践与报告撰写建议完成代码实践只是第一步如何将其组织成一份出色的报告同样关键。8.1 工程实践建议版本控制使用Git管理你的代码和报告。.gitignore文件应忽略data/,outputs/,__pycache__/等文件夹。依赖管理使用pip freeze requirements.txt生成准确的依赖列表方便助教复现环境。实验记录对于重要的超参数调整如学习率、批次大小、epoch数记录下每次实验的设置和结果可以使用TensorBoard或简单的文本日志。模块化设计如本文所示将数据加载、模型定义、训练、评估分离使代码清晰、易维护、易复用。8.2 报告内容结构建议你的实践报告应包含以下核心部分并体现你的思考摘要用200-300字概括整个项目包括任务、方法、主要结果和结论。引言阐述选题背景猫狗分类的意义、项目目标以及报告结构。相关工作简要介绍CNN和迁移学习的基本原理说明为何选择ResNet作为对比模型。方法与实现数据集描述数据来源、规模、预处理缩放、归一化、增强方法及原因。模型架构图文并茂地介绍SimpleCNN和ResNet18的结构。重点画出SimpleCNN的结构图可以使用torchsummary库输出参数表解释每层的作用。训练细节列出所有超参数学习率、优化器、批次大小、epoch数等及其选择依据。解释学习率调度器的作用。实验结果与分析这是报告的重中之重。定量分析用表格对比两个模型的最终测试准确率、精确率、召回率、F1分数。定性分析训练曲线分析展示并解释损失和准确率曲线。指出模型何时收敛是否有过拟合/欠拟合迹象。混淆矩阵分析展示两个模型的混淆矩阵。分析模型更容易将猫误判为狗还是反之可能的原因是什么例如数据集中某种类别的图片更模糊错误样本分析选取几个被模型错误分类的图片可视化并尝试解释原因如背景复杂、姿态奇特、拍摄模糊。这能极大提升报告的深度。讨论性能对比为什么ResNet18表现远优于SimpleCNN从模型深度、参数量、预训练知识等角度讨论。局限性当前方法有哪些不足例如只能分猫狗对猫科/犬科其他动物无效对极端光照图片效果差等。改进方向如果继续这个项目你会从哪些方面改进例如尝试更复杂的模型如EfficientNet、Vision Transformer使用更丰富的数据增强尝试解冻更多层进行微调集成多个模型等。结论总结项目成果重申核心发现。参考文献规范引用你参考的论文、技术博客、API文档等。附录可以附上核心代码的片段不必全部以及完整的项目Git仓库链接。通过这样一个从理论到实践、从实现到分析、从结果到反思的完整流程你提交的将不仅仅是一份“作业”而是一个标准的、可复现的AI项目原型。这不仅能让你在《人工智能导论》课程中获得高分更能为你未来从事更复杂的AI研究或开发工作打下坚实的思维和工程基础。
返回列表