这次我们直接看一套东西VGG/ResNet 图像分类、图像风格迁移、TextCNN 文本分类、图像字幕生成。对 AI 算法工程师来说这四块内容不是期末考试题而是面试、业务落地、技术方案选型时反复出现的核心组合。很多人在单个任务上跑过 Demo但真正把四件事串起来理解的人不多。先说结论这四个项目覆盖了图像分类、图像生成、NLP 基础分类任务、跨模态理解四条主线。VGG/ResNet 解决“图像是什么”图像风格迁移解决“图像怎么改”TextCNN 解决“文本说什么”图像字幕生成解决“图像和文本怎么连起来”。如果你正在准备算法岗位面试或者想把深度学习基础做成一套可以复用的实战能力这四个项目是最值得优先跑通的组合。本文会按照“核心能力速览 - 环境准备 - 四项目实战 - 性能观察 - 问题排查 - 最佳实践”的顺序展开。每个项目都会给出原理要点、PyTorch 实现思路、训练验证方法和效果判断标准。代码能直接参考但数据集路径和超参数需要根据自己的机器调整。这四个项目的最大好处是门槛适中一张支持 CUDA 的 NVIDIA 显卡就能跑4G 到 8G 显存的显卡能完成大多数训练和推理实验没有独立显卡时用 CPU 跑小数据集也能验证流程只是速度慢很多。更稳妥的判断是显存占用取决于模型尺寸、batch size、图像分辨率和文本序列长度实际数字要以本机nvidia-smi显示为准。1. 四个核心项目速览先把四个项目的核心信息放在一起方便快速对照。这里是一个表格项目任务类型核心技术常用数据集学习价值典型落地场景VGG/ResNet 图像分类计算机视觉 / 图像分类CNN、残差连接、批量归一化CIFAR-10、CIFAR-100、ImageNet掌握 CNN 结构设计和训练调参工业质检、医学影像分类、内容审核图像风格迁移计算机视觉 / 图像生成VGG 特征提取、Gram 矩阵、内容损失与风格损失COCO、WikiArt、任意风格图片理解特征图语义层次和损失函数设计图片美化、设计辅助、视频滤镜TextCNN 文本分类NLP / 文本分类Embedding、Conv1d、MaxPoolingIMDB、THUCNews、自建语料理解卷积在文本中的应用和文本预处理情感分析、垃圾评论过滤、舆情分类图像字幕生成跨模态 / 图文生成CNN Encoder LSTM Decoder、注意力机制MS COCO、Flickr8k、Flickr30k理解跨模态表征和序列生成图片内容描述、信息无障碍、图文检索从依赖关系看VGG/ResNet 是基础风格迁移和字幕生成都依赖预训练 CNN 提取图像特征TextCNN 相对独立但可以理解成后续 BERT 等大模型之前最经典的分类基线。四个项目全部掌握后再去看 YOLO、Transformer、CLIP 等进阶内容会顺很多。2. 适用场景与使用边界这四个项目适合谁主要三类人准备 AI 算法工程师岗位面试的候选人。VGG/ResNet 的结构和残差思想几乎是必问项TextCNN 是 NLP 入门必聊的基线模型图像字幕生成能体现对跨模态任务的理解深度。刚进入深度学习方向、需要用最小成本建立完整实战经验的同学。这四个项目都适合在小数据集上快速跑通不需要动辄几十张显卡的算力。业务中需要快速验证视觉、文本、跨模态方案可行性的开发人员。四个项目可以拆成独立的基线方案先跑出效果再决定是否升级到更大模型。边界也要说清楚。TextCNN 适合短文本和中等长度文本分类但遇到长文本语义依赖、复杂上下文时效果会明显弱于 BERT 等预训练模型。图像风格迁移的经典方法适合离线生成实时视频风格化需要换成快速风格迁移或蒸馏方案。图像字幕生成在公开数据集上效果很好但用于真实业务时必须注意图像中的隐私信息、人脸肖像、品牌 logo 和版权素材不能把未授权数据随便扔进模型训练或生成流程。另外一个容易被忽略的点这四个项目使用的公开数据集和预训练模型都有各自的开源协议。商用前要确认数据集是否允许商用、预训练权重的许可范围和发布限制。3. 深度学习环境准备与前置条件环境配置是很多人最容易卡住的地方。先列一份通用检查清单然后给出一套适合这四个项目的环境搭建方案。硬件方面四个项目都不需要顶级显卡。NVIDIA 显卡只要是支持 CUDA 的型号就可以例如 GTX 1660、RTX 2060、RTX 3060、RTX 4000 系列等。没有 NVIDIA 显卡也能在 CPU 上运行但训练时间会成倍增加建议先在 CIFAR-10 这类小数据集上验证。软件方面核心依赖是 Python、CUDA、cuDNN、PyTorch 和 torchvision。常见的组合是 Python 3.8 到 3.11、PyTorch 2.x、torchvision 对应版本。CUDA 版本必须与 PyTorch 安装版本匹配否则会出现“找不到 CUDA 驱动”的错误。推荐用 conda 创建独立环境避免把系统 Python 弄乱# 创建独立环境建议 Python 3.10 conda create -n dl_projects python3.10 -y conda activate dl_projectsPyTorch 的安装命令以官网为准。下面是使用国内镜像源时的通用写法实际版本号需要替换为官网最新稳定版# 先确认本机 CUDA 版本 nvidia-smi # 安装 PyTorch下面示例以 CUDA 11.8 为例实际请按官网对应命令 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118安装完成后检查 GPU 是否可用import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU mode)项目目录建议按功能拆分dl_projects/ ├── classification/ # VGG/ResNet 图像分类 ├── style_transfer/ # 图像风格迁移 ├── textcnn/ # TextCNN 文本分类 ├── captioning/ # 图像字幕生成 ├── datasets/ # 下载好的数据集 └── checkpoints/ # 模型权重保存目录磁盘空间方面CIFAR-10 数据集不到 200MBMS COCO 需要几十 GBImageNet 更不用说。建议先把四个项目的默认数据集全部确认好再统一规划磁盘。4. 项目一VGG/ResNet 图像分类实战图像分类是深度学习的起点最能说明模型结构如何影响效果。VGG 的核心是把卷积层堆深。它用连续的小卷积核堆叠替代大卷积核例如用两层 3x3 卷积替代一层 5x5 卷积在保持感受野的同时减少参数。VGG 的结构非常规整从 VGG11 到 VGG19区别主要在网络深度。ResNet 的改进思路是解决深层网络难以训练的问题。网络越深梯度在反向传播中越容易消失单纯叠加层数反而会让训练集准确率下降。ResNet 引入残差连接让网络学习残差 F(x) H(x) - x而不是直接拟合 H(x)。残差连接使得梯度可以跨层传播因此能训练上百层的网络。在 PyTorch 中可以直接使用 torchvision 里的预训练模型做迁移学习也可以自己写一个简化版本。下面以 CIFAR-10 为例用 torchvision 加载 ResNet18并替换最后的全连接层import torch import torch.nn as nn import torchvision import torchvision.transforms as transforms from torchvision.models import resnet18 device torch.device(cuda if torch.cuda.is_available() else cpu) # 数据增强和归一化 transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) transform_test transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ]) trainset torchvision.datasets.CIFAR10( root./datasets, trainTrue, downloadTrue, transformtransform_train ) testset torchvision.datasets.CIFAR10( root./datasets, trainFalse, downloadTrue, transformtransform_test ) trainloader torch.utils.data.DataLoader(trainset, batch_size128, shuffleTrue, num_workers4) testloader torch.utils.data.DataLoader(testset, batch_size128, shuffleFalse, num_workers4) # 使用 ImageNet 预训练权重迁移学习 model resnet18(weightstorchvision.models.ResNet18_Weights.IMAGENET1K_V1) num_features model.fc.in_features model.fc nn.Linear(num_features, 10) model model.to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.SGD(model.parameters(), lr0.01, momentum0.9, weight_decay5e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30)训练循环可以统一写成一个函数方便三个项目复用def train_one_epoch(model, loader, criterion, optimizer, device): model.train() total_loss 0.0 correct 0 total 0 for images, labels in loader: images, labels images.to(device), labels.to(device) outputs model(images) loss criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() * images.size(0) _, predicted outputs.max(1) total labels.size(0) correct predicted.eq(labels).sum().item() return total_loss / total, 100.0 * correct / total验证时的标准是如果 CIFAR-10 上使用 ResNet18 迁移学习训练几十个 epoch 后准确率能稳定到 85% 到 95% 之间如果是随机初始化从零训练准确率会低一些但也能到 85% 左右。VGG 系列在小数据集上参数量偏大容易出现显存占用高、训练速度慢的情况所以实际实验更推荐 ResNet 系列。5. 项目二图像风格迁移实战图像风格迁移的目标是把一张风格图片的纹理、笔触、色彩分布迁移到内容图片上同时保持内容图片的物体结构。经典方法不是直接生成一个新网络而是针对每一对输入图片做优化。核心思路是使用一个预训练的 VGG16 作为特征提取器定义内容损失和风格损失然后通过梯度下降优化生成图片。内容损失衡量生成图片和内容图片在中间层特征图上的差异通常使用较高层特征因为高层特征保留了更多语义信息。风格损失则用 Gram 矩阵表示特征通道之间的相关性Gram 矩阵可以近似描述纹理风格。下面是 PyTorch 中风格损失的常用计算方式import torch import torch.nn as nn def gram_matrix(feature_map): batch_size, channels, height, width feature_map.size() features feature_map.view(batch_size, channels, height * width) gram torch.bmm(features, features.transpose(1, 2)) return gram / (channels * height * width) def style_loss(gen_feat, style_feat): return nn.functional.mse_loss(gram_matrix(gen_feat), gram_matrix(style_feat))使用预训练 VGG16 时需要把网络的前若干层提取出来作为特征提取器并在不同层同时计算内容损失和风格损失。内容层通常选择较深的卷积层风格层通常选择多个不同尺度的卷积层这样能捕捉从局部笔触到整体配色的多层风格。风格迁移训练过程比较特殊训练的对象不是模型权重而是输入图片本身。训练前将一张噪声图片或内容图片复制一份并设置requires_gradTruetarget_img content_img.clone().requires_grad_(True) optimizer torch.optim.LBFGS([target_img], lr0.1)然后在一个循环里反复计算内容损失和风格损失更新目标图片的像素。每过一定轮次把目标图片保存下来可以明显看到生成图片逐渐向风格图片靠拢。效果判断标准有三点一内容图片里的主体轮廓仍然能识别二风格图片的色彩和纹理痕迹明显三生成图片没有明显噪声块或过度扭曲。风格迁移对显存要求取决于输入图片分辨率512x512 左右时消费级显卡基本可以跑但更大分辨率需要减少优化迭代次数或使用小尺寸输入。经典风格迁移的缺点是慢因为每次更换内容图或风格图都要重新迭代优化。工程上如果要部署到业务中更常用的是快速风格迁移训练一个生成网络输入一张图片直接输出风格化结果一次前向推理完成。但作为深度学习基础项目经典方法能把损失函数设计和特征图语义理解讲得更清楚建议先跑通这个。6. 项目三TextCNN 文本分类实战TextCNN 是 2015 年前后出现的经典文本分类模型。它的基本思想是把文本看成由词向量组成的序列用一维卷积提取局部 n-gram 特征再用最大池化保留每个卷积核最显著的特征最后接全连接层做分类。TextCNN 的优势是简单、训练快、在小规模文本分类任务上效果稳定。很多短文本场景下TextCNN 是验证新数据效果最快的基线模型。先看数据处理。以 THUCNews 或 IMDB 这类分类数据集为例流程是分词 - 构建词表 - 文本转索引序列 - padding 到固定长度。下面是一段直接的 PyTorch 数据预处理思路from torch.utils.data import Dataset class TextDataset(Dataset): def __init__(self, texts, labels, word2idx, max_len128): self.texts texts self.labels labels self.word2idx word2idx self.max_len max_len def __len__(self): return len(self.texts) def __getitem__(self, idx): tokens self.texts[idx] ids [self.word2idx.get(w, 1) for w in tokens] # 1 表示 unknown if len(ids) self.max_len: ids ids [0] * (self.max_len - len(ids)) # 0 表示 padding else: ids ids[:self.max_len] return torch.tensor(ids, dtypetorch.long), torch.tensor(self.labels[idx])TextCNN 模型本身结构很简单import torch.nn as nn class TextCNN(nn.Module): def __init__(self, vocab_size, embed_dim100, num_classes2, kernel_sizes(3, 4, 5), num_filters100): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim, padding_idx0) self.convs nn.ModuleList([ nn.Conv1d(in_channelsembed_dim, out_channelsnum_filters, kernel_sizeks) for ks in kernel_sizes ]) self.fc nn.Linear(len(kernel_sizes) * num_filters, num_classes) self.dropout nn.Dropout(0.5) def forward(self, x): # x: (batch, seq_len) x self.embedding(x) # (batch, seq_len, embed_dim) x x.transpose(1, 2) # (batch, embed_dim, seq_len) conv_outputs [] for conv in self.convs: conv_out conv(x) # (batch, num_filters, seq_len - kernel_size 1) pooled conv_out.max(dim-1).values # (batch, num_filters) conv_outputs.append(pooled) x torch.cat(conv_outputs, dim1) # (batch, num_filters * len(kernel_sizes)) x self.dropout(x) return self.fc(x)训练 TextCNN 时最需要注意的是词表构建。如果使用预训练词向量例如 word2vec 或 GloVe需要保证预训练词表的索引与 embedding 矩阵对齐如果随机初始化 Embedding训练数据量要足够大否则词向量学不好。推荐在小数据集上先用随机初始化跑通流程后再尝试加载预训练词向量。TextCNN 的显存占用通常非常低因为 Conv1d 的参数量远小于图像卷积网络序列长度 128、词向量维度 100 时单卡训练几乎不会遇到显存问题。训练十几轮后观察验证集准确率情感二分类任务通常能达到 85% 以上多分类任务视数据集难度而定。7. 项目四图像字幕生成实战图像字幕生成是四个项目里最有综合性的一个它同时涉及视觉和语言模块。目标是输入一张图片输出一句描述图片内容的文本。经典架构是 Encoder-Decoder。Encoder 使用预训练 CNN 提取图片特征Decoder 使用 LSTM 按时间步生成单词。第一种简单做法是用 ResNet 提取整图特征作为 LSTM 的初始隐状态第二种做法是加入注意力机制让 LSTM 每一步生成时关注图片的不同区域。工程入门建议先跑通第一种再升级到注意力版本。下面是一个简化版 Encoder-Decoder 结构import torch import torch.nn as nn class EncoderCNN(nn.Module): def __init__(self, embed_size256): super().__init__() resnet torchvision.models.resnet18(weightstorchvision.models.ResNet18_Weights.IMAGENET1K_V1) self.cnn nn.Sequential(*list(resnet.children())[:-1]) # 去掉 fc 层 self.fc nn.Linear(resnet.fc.in_features, embed_size) def forward(self, images): features self.cnn(images) # (batch, 512, 1, 1) features features.view(features.size(0), -1) return self.fc(features) # (batch, embed_size) class DecoderLSTM(nn.Module): def __init__(self, embed_size256, hidden_size512, vocab_size5000, max_len20): super().__init__() self.embedding nn.Embedding(vocab_size, embed_size) self.lstm nn.LSTM(embed_size, hidden_size, batch_firstTrue) self.fc nn.Linear(hidden_size, vocab_size) def forward(self, features, captions): # captions: (batch, max_len) embeddings self.embedding(captions) # (batch, max_len, embed_size) outputs, _ self.lstm(embeddings) return self.fc(outputs) # (batch, max_len, vocab_size)训练阶段图片通过 EncoderCNN 得到特征向量然后把这个向量作为 LSTM 的初始输入。常见做法是把特征向量拼到第一个时间步或者用它初始化 LSTM 的隐状态。训练损失使用交叉熵目标是把真实描述文本的每个词按顺序预测出来。数据准备是字幕生成里最繁琐的部分。MS COCO 数据集需要下载 JSON 格式的标注文件每个图片对应 5 条人工描述。训练时要把所有描述分词、构建词表过滤掉出现次数过少的词并统一限制句子最大长度。如果预算有限可以先用 Flickr8k 这类小数据集跑通全流程。效果评估常用 BLEU 指标。BLEU 计算生成文本与参考文本之间的 n-gram 重合度数值越高说明生成描述与人工描述越接近。但 BLEU 并不完美它偏向字面匹配对语义多样性不敏感。实际看效果时除了看 BLEU还要人工检查生成句子是否合理。字幕生成对显存的要求主要来自两个地方图片分辨率导致 CNN 特征图显存占用以及 LSTM 展开长度导致的中间状态占用。用 ResNet18 小 batch size在消费级显卡上可以训练如果使用更大的 ResNet101 或者加入注意力机制显存会明显上升需要实际试用nvidia-smi观察。8. 资源占用与性能观察四个项目的资源占用差异很大。分类模型和 TextCNN 属于常规监督训练显存主要由 batch size 和模型参数决定风格迁移属于输入图片优化显存主要由图片分辨率和 VGG 网络层数决定字幕生成同时包含视觉和文本模块显存会更复杂。观察 GPU 占用和显存最直接的方法是# 实时查看 GPU 状态 nvidia-smi # 每隔 1 秒刷新一次 watch -n 1 nvidia-smi训练过程中如果显存不足优先调小 batch size或者在 DataLoader 中设置num_workers为 0 排查数据加载问题。PyTorch 还支持自动混合精度# 要点需要安装 torch.cuda.ampPyTorch 1.6 内置支持混合精度训练混合精度训练可以减少显存占用并提升训练速度但在风格迁移这种需要精确像素优化的任务上要小心精度损失导致生成质量下降。更稳妥的做法是先用单精度 FP32 跑通全部流程再尝试混合精度优化。CPU 和 GPU 的差距非常大。以 CIFAR-10 的 ResNet18 训练为例GPU 上一个 epoch 可能只要几十秒CPU 可能需要几分钟到十几分钟。风格迁移每张图的优化轮次更多CPU 上几乎不可用。TextCNN 在小数据集上用 CPU 跑还能接受但字幕生成建议直接使用 GPU。9. 常见问题与排查方法下面这张表总结了四个项目里最容易遇到的坑这里是一个表格问题现象可能原因排查方式解决方案torch.cuda.is_available()返回 FalseCUDA 版本与 PyTorch 不匹配或驱动未正确安装运行nvidia-smi查看驱动版本检查 PyTorch 安装命令按官网对应 CUDA 版本重装 PyTorch训练 loss 不下降学习率过大或过小数据预处理有误标签错乱打印前几个 batch 的输入和标签检查数据增强调整学习率先用小 batch 调试分类准确率偏低数据不平衡、模型过拟合或欠拟合、预训练权重未正确加载观察训练集和验证集准确率差距增加数据增强、加入 dropout、适当降低学习率风格迁移出现彩色噪声块风格损失权重过大、优化迭代次数不足、学习率过高分别查看内容损失和风格损失数值调低风格权重增加迭代次数降低学习率TextCNN 训练时报维度错误不同 kernel size 的卷积输出维度不一致padding 未对齐查看每层输出 shape统一文本 padding 长度处理边界条件字幕生成训练时词表索引越界词汇表大小设置小于实际词数或 JSON 标注解析异常检查 vocab 大小和 captions 索引范围过滤低频词重建词表显存不足 OOMbatch size 过大、分辨率过高、模型过大查看nvidia-smi显存占用减小 batch size降低图片分辨率使用梯度累积训练突然中断数据加载线程崩溃、磁盘空间不足、网络下载数据集失败检查日志和数据目录先下载好数据集关闭num_workers测试遇到依赖安装失败时最简单的办法是新建一个干净的 conda 环境不要和已有项目混用依赖。模型文件缺失时优先检查权重下载路径和缓存目录确认预训练权重是否下载完整。10. 最佳实践与合规提醒四套项目全部跑通后建议按下面这些方式组织后续工作。第一保留一套最小可运行配置。把每个项目的数据集、模型结构、训练参数、启动命令写成 README确保换一台机器也能在三十分钟内跑起来。这样后续排查问题、给同事演示、做基线对比都方便。第二训练时统一使用 checkpoint 保存机制。每训练一个 epoch 保存一次模型权重同时保存 optimizer 的 state_dict方便中途断点续训checkpoint { model: model.state_dict(), optimizer: optimizer.state_dict(), epoch: epoch, best_acc: best_acc, } torch.save(checkpoint, checkpoints/classification_resnet18.pt)第三批量任务和接口服务要保持日志完整。如果要把模型部署成 API 服务建议记录请求时间、输入尺寸、显存占用、推理耗时、异常错误。接口服务上线前要设置访问限制避免被外部随意调用。第四数据版权和使用授权一定要确认。CIFAR-10、MS COCO、THUCNews 等公开数据集适合学习和实验但商用前需要核对数据集许可协议。使用预训练模型权重时同样要检查模型是否有额外的商业限制。图像字幕生成如果处理的是真实人物照片必须确保获得了肖像授权人脸、声音、品牌标识等敏感信息不能随意进入训练集。第五发布模型或内容前要做效果复核。分类模型要检查边界样本和偏见问题风格迁移要检查是否存在明显篡改痕迹或不良信息字幕生成要检查是否生成了错误描述。尤其在实际业务中错误结果带来的影响比模型准确率下降更大。11. 总结与下一步这四个项目最值得尝试的是它们能帮你建立一条完整的深度学习技术链路用 VGG/ResNet 理解图像表征用风格迁移理解损失函数设计用 TextCNN 理解文本特征提取用字幕生成理解跨模态建模。四个项目都跑通之后你再看 Vision Transformer、CLIP、BLIP、Stable Diffusion 等进阶方向会明显感觉基础更扎实。建议先跑 VGG/ResNet 图像分类这是最快看到结果、最不容易挫败信心的项目接着做 TextCNN代码量少能快速理解 NLP 数据流再跑风格迁移它会强迫你深入理解特征图和损失函数最后挑战图像字幕生成因为它的数据预处理和模型结构最复杂。最容易踩的坑有两个一是环境配置阶段 CUDA 和 PyTorch 版本不匹配二是数据处理阶段图片尺寸、文本长度、词表索引没对齐。这两类问题占到运行时错误的大半排查时优先看数据形状和网卡状态。下一步的扩展方向也很清晰图像分类可以升级到 EfficientNet 或 Vision Transformer风格迁移可以尝试 AdaIN、CycleGAN文本分类可以转向 BERT 微调字幕生成可以引入注意力机制、Transformer Decoder甚至用 CLIP 做图文对齐。每个方向都能继续挖很深但基础始终是这四个经典项目。建议把本文提到的四套流程在本地完整跑一遍再决定选哪个方向深入。