深度学习七大经典网络精讲:CNN/GNN/YOLO/Transformer原理与实战

深度学习七大经典网络精讲:CNN/GNN/YOLO/Transformer原理与实战
深度学习别盲目自学迪哥精讲七大经典网络CNN/GNN/YOLO/Transformer 全覆盖通俗易懂直达项目实战很多同学在入门深度学习时面对各种网络模型容易陷入学了一堆理论遇到实际问题还是无从下手的困境。本文将从实际项目角度出发系统讲解七大经典深度学习网络的原理、应用场景和实战代码帮助大家建立完整的知识体系。1. 深度学习基础概念与环境搭建1.1 深度学习核心概念解析深度学习是机器学习的一个分支它通过模拟人脑神经网络的工作方式构建多层次的神经网络模型来处理复杂数据。与传统机器学习方法相比深度学习最大的优势在于能够自动从原始数据中学习特征表示无需过多的人工特征工程。深度学习的三个核心要素神经网络结构包括输入层、隐藏层和输出层通过权重连接形成复杂的数据处理网络激活函数如ReLU、Sigmoid、Tanh等为网络引入非线性变换能力损失函数与优化器衡量预测结果与真实值的差距并通过反向传播算法调整网络参数1.2 环境配置与工具选择在开始深度学习项目前需要搭建合适的开发环境。推荐使用Python 3.8版本配合以下核心库# 创建虚拟环境 python -m venv deeplearning_env source deeplearning_env/bin/activate # Linux/Mac # deeplearning_env\Scripts\activate # Windows # 安装核心依赖 pip install torch1.13.1 torchvision0.14.1 pip install tensorflow2.11.0 pip install numpy pandas matplotlib scikit-learn pip install jupyter notebook对于硬件配置如果有GPU支持建议安装对应的CUDA版本# 检查CUDA是否可用 import torch print(fCUDA available: {torch.cuda.is_available()}) print(fGPU count: {torch.cuda.device_count()})1.3 数据集准备与管理深度学习项目成功的关键在于高质量的数据集。常用的公开数据集包括图像分类CIFAR-10、ImageNet、MNIST目标检测COCO、PASCAL VOC自然语言处理IMDB电影评论、WikiTextimport torch from torchvision import datasets, transforms # 数据预处理管道 transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # 加载CIFAR-10数据集 train_dataset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform) test_dataset datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransform) # 创建数据加载器 train_loader torch.utils.data.DataLoader(train_dataset, batch_size32, shuffleTrue) test_loader torch.utils.data.DataLoader(test_dataset, batch_size32, shuffleFalse)2. 卷积神经网络CNN原理与实战2.1 CNN核心组件详解卷积神经网络是处理图像数据的首选模型其核心思想是通过局部连接和权值共享来有效处理二维数据。卷积层工作原理import torch.nn as nn # 定义一个简单的卷积层 conv_layer nn.Conv2d(in_channels3, # 输入通道数RGB图像为3 out_channels64, # 输出通道数特征图数量 kernel_size3, # 卷积核大小 stride1, # 步长 padding1) # 边缘填充 # 输入一个32x32的RGB图像 input_tensor torch.randn(1, 3, 32, 32) # [batch, channels, height, width] output conv_layer(input_tensor) print(f输入形状: {input_tensor.shape}) print(f输出形状: {output.shape})池化层的作用# 最大池化层 max_pool nn.MaxPool2d(kernel_size2, stride2) # 平均池化层 avg_pool nn.AvgPool2d(kernel_size2, stride2) # 应用池化 pooled_output max_pool(output) print(f池化后形状: {pooled_output.shape})2.2 LeNet-5实战手写数字识别LeNet-5是经典的CNN架构适合入门学习class LeNet5(nn.Module): def __init__(self, num_classes10): super(LeNet5, self).__init__() self.features nn.Sequential( nn.Conv2d(1, 6, kernel_size5), # 输入1通道输出6通道 nn.ReLU(), nn.MaxPool2d(kernel_size2), nn.Conv2d(6, 16, kernel_size5), nn.ReLU(), nn.MaxPool2d(kernel_size2) ) self.classifier nn.Sequential( nn.Linear(16 * 4 * 4, 120), # 全连接层 nn.ReLU(), nn.Linear(120, 84), nn.ReLU(), nn.Linear(84, num_classes) ) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) # 展平 x self.classifier(x) return x # 模型训练示例 model LeNet5() criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr0.001) def train_epoch(model, dataloader, criterion, optimizer): model.train() running_loss 0.0 for batch_idx, (data, target) in enumerate(dataloader): optimizer.zero_grad() output model(data) loss criterion(output, target) loss.backward() optimizer.step() running_loss loss.item() return running_loss / len(dataloader)2.3 ResNet深度残差网络解决深度网络梯度消失问题的经典架构class BasicBlock(nn.Module): def __init__(self, in_channels, out_channels, stride1): super(BasicBlock, self).__init__() self.conv1 nn.Conv2d(in_channels, out_channels, kernel_size3, stridestride, padding1, biasFalse) self.bn1 nn.BatchNorm2d(out_channels) self.relu nn.ReLU(inplaceTrue) self.conv2 nn.Conv2d(out_channels, out_channels, kernel_size3, stride1, padding1, biasFalse) self.bn2 nn.BatchNorm2d(out_channels) # 捷径连接 self.shortcut nn.Sequential() if stride ! 1 or in_channels ! out_channels: self.shortcut nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size1, stridestride, biasFalse), nn.BatchNorm2d(out_channels) ) def forward(self, x): residual x out self.conv1(x) out self.bn1(out) out self.relu(out) out self.conv2(out) out self.bn2(out) out self.shortcut(residual) # 残差连接 out self.relu(out) return out3. 图神经网络GNN与应用实践3.1 图神经网络基础概念GNN专门用于处理图结构数据在社交网络、分子结构分析等领域有广泛应用。图的基本表示import torch import torch.nn as nn import torch.nn.functional as F from torch_geometric.nn import GCNConv import networkx as nx # 构建一个简单的图 edge_index torch.tensor([[0, 1, 1, 2], [1, 0, 2, 1]], dtypetorch.long) x torch.tensor([[-1], [0], [1]], dtypetorch.float) print(f节点特征矩阵形状: {x.shape}) print(f边索引矩阵: {edge_index})3.2 图卷积网络GCN实现class GCN(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(GCN, self).__init__() self.conv1 GCNConv(input_dim, hidden_dim) self.conv2 GCNConv(hidden_dim, output_dim) def forward(self, x, edge_index): # 第一层图卷积 x self.conv1(x, edge_index) x F.relu(x) x F.dropout(x, trainingself.training) # 第二层图卷积 x self.conv2(x, edge_index) return F.log_softmax(x, dim1) # 示例节点分类任务 model GCN(input_dim1, hidden_dim16, output_dim2) optimizer torch.optim.Adam(model.parameters(), lr0.01, weight_decay5e-4) def train(): model.train() optimizer.zero_grad() out model(x, edge_index) loss F.nll_loss(out, torch.tensor([0, 1, 0])) # 假设的标签 loss.backward() optimizer.step() return loss.item()3.3 GNN在推荐系统中的应用class GraphSAGE(nn.Module): def __init__(self, in_channels, hidden_channels, out_channels, num_layers2): super(GraphSAGE, self).__init__() self.convs nn.ModuleList() self.convs.append(SAGEConv(in_channels, hidden_channels)) for _ in range(num_layers - 2): self.convs.append(SAGEConv(hidden_channels, hidden_channels)) self.convs.append(SAGEConv(hidden_channels, out_channels)) def forward(self, x, edge_index): for i, conv in enumerate(self.convs): x conv(x, edge_index) if i ! len(self.convs) - 1: x F.relu(x) x F.dropout(x, p0.5, trainingself.training) return x # 构建用户-物品二分图 user_nodes 1000 item_nodes 500 # 模拟用户-物品交互边 user_item_edges torch.randint(0, user_nodes, (2, 5000))4. YOLO目标检测算法深度解析4.1 YOLO算法原理与演进YOLOYou Only Look Once将目标检测视为回归问题实现端到端的检测流程。YOLOv5网络结构核心import torch import torch.nn as nn class ConvBNSiLU(nn.Module): 标准卷积块Conv BatchNorm SiLU激活 def __init__(self, in_channels, out_channels, kernel_size1, stride1, groups1): super().__init__() padding kernel_size // 2 self.conv nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, groupsgroups, biasFalse) self.bn nn.BatchNorm2d(out_channels) self.act nn.SiLU() def forward(self, x): return self.act(self.bn(self.conv(x))) class Bottleneck(nn.Module): 残差瓶颈块 def __init__(self, in_channels, out_channels, shortcutTrue): super().__init__() hidden_channels out_channels // 2 self.conv1 ConvBNSiLU(in_channels, hidden_channels, 1) self.conv2 ConvBNSiLU(hidden_channels, out_channels, 3) self.use_shortcut shortcut and in_channels out_channels def forward(self, x): if self.use_shortcut: return x self.conv2(self.conv1(x)) else: return self.conv2(self.conv1(x))4.2 YOLOv8实战自定义目标检测from ultralytics import YOLO import cv2 import numpy as np class YOLODetector: def __init__(self, model_pathyolov8n.pt): self.model YOLO(model_path) self.class_names self.model.names def detect(self, image_path, conf_threshold0.5): 执行目标检测 results self.model(image_path, confconf_threshold) # 解析检测结果 detections [] for result in results: boxes result.boxes for box in boxes: x1, y1, x2, y2 box.xyxy[0].cpu().numpy() confidence box.conf[0].cpu().numpy() class_id int(box.cls[0].cpu().numpy()) detections.append({ bbox: [x1, y1, x2, y2], confidence: confidence, class_id: class_id, class_name: self.class_names[class_id] }) return detections def draw_detections(self, image_path, output_path): 绘制检测结果 image cv2.imread(image_path) detections self.detect(image_path) for detection in detections: x1, y1, x2, y2 map(int, detection[bbox]) confidence detection[confidence] class_name detection[class_name] # 绘制边界框 cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 添加标签 label f{class_name}: {confidence:.2f} cv2.putText(image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imwrite(output_path, image) return image # 使用示例 detector YOLODetector() result_image detector.draw_detections(test_image.jpg, output.jpg)4.3 YOLO模型训练与优化def prepare_yolo_dataset(data_yaml): 准备YOLO训练数据 import yaml dataset_config { path: ./datasets/custom, train: images/train, val: images/val, test: images/test, nc: 3, # 类别数量 names: [class1, class2, class3] # 类别名称 } with open(data_yaml, w) as f: yaml.dump(dataset_config, f) return data_yaml def train_yolo_model(): 训练YOLO模型 from ultralytics import YOLO # 加载预训练模型 model YOLO(yolov8n.pt) # 训练配置 results model.train( datadataset.yaml, epochs100, imgsz640, batch16, lr00.01, patience10, saveTrue, device0 if torch.cuda.is_available() else cpu ) return results # 模型评估 def evaluate_model(model_path, val_dataset): model YOLO(model_path) metrics model.val(dataval_dataset) print(fmAP50: {metrics.box.map50}) print(fmAP50-95: {metrics.box.map}) return metrics5. Transformer架构原理与实战5.1 Transformer核心机制解析Transformer通过自注意力机制彻底改变了序列建模的方式成为NLP领域的基石。自注意力机制实现import torch import torch.nn as nn import math class MultiHeadAttention(nn.Module): def __init__(self, d_model, num_heads): super(MultiHeadAttention, self).__init__() assert d_model % num_heads 0 self.d_model d_model self.num_heads num_heads self.d_k d_model // num_heads self.w_q nn.Linear(d_model, d_model) self.w_k nn.Linear(d_model, d_model) self.w_v nn.Linear(d_model, d_model) self.w_o nn.Linear(d_model, d_model) def scaled_dot_product_attention(self, q, k, v, maskNone): attn_scores torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k) if mask is not None: attn_scores attn_scores.masked_fill(mask 0, -1e9) attn_weights torch.softmax(attn_scores, dim-1) output torch.matmul(attn_weights, v) return output, attn_weights def forward(self, q, k, v, maskNone): batch_size, seq_len q.size(0), q.size(1) # 线性变换并分头 q self.w_q(q).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) k self.w_k(k).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) v self.w_v(v).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2) # 计算注意力 attn_output, attn_weights self.scaled_dot_product_attention(q, k, v, mask) # 合并多头输出 attn_output attn_output.transpose(1, 2).contiguous().view( batch_size, seq_len, self.d_model) return self.w_o(attn_output), attn_weights5.2 位置编码与前馈网络class PositionalEncoding(nn.Module): def __init__(self, d_model, max_seq_len5000): super(PositionalEncoding, self).__init__() pe torch.zeros(max_seq_len, d_model) position torch.arange(0, max_seq_len, dtypetorch.float).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(0) self.register_buffer(pe, pe) def forward(self, x): return x self.pe[:, :x.size(1)] class FeedForward(nn.Module): def __init__(self, d_model, d_ff, dropout0.1): super(FeedForward, self).__init__() self.linear1 nn.Linear(d_model, d_ff) self.dropout nn.Dropout(dropout) self.linear2 nn.Linear(d_ff, d_model) def forward(self, x): return self.linear2(self.dropout(torch.relu(self.linear1(x))))5.3 完整Transformer编码器实现class TransformerEncoderLayer(nn.Module): def __init__(self, d_model, num_heads, d_ff, dropout0.1): super(TransformerEncoderLayer, self).__init__() self.self_attn MultiHeadAttention(d_model, num_heads) self.feed_forward FeedForward(d_model, d_ff, dropout) self.norm1 nn.LayerNorm(d_model) self.norm2 nn.LayerNorm(d_model) self.dropout nn.Dropout(dropout) def forward(self, x, maskNone): # 自注意力子层 attn_output, _ self.self_attn(x, x, x, mask) x self.norm1(x self.dropout(attn_output)) # 前馈网络子层 ff_output self.feed_forward(x) x self.norm2(x self.dropout(ff_output)) return x class TransformerEncoder(nn.Module): def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_len, dropout0.1): super(TransformerEncoder, self).__init__() self.token_embedding nn.Embedding(vocab_size, d_model) self.pos_encoding PositionalEncoding(d_model, max_seq_len) self.layers nn.ModuleList([ TransformerEncoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers) ]) self.dropout nn.Dropout(dropout) def forward(self, x, maskNone): # 嵌入层 位置编码 x self.token_embedding(x) x self.pos_encoding(x) x self.dropout(x) # 通过所有编码器层 for layer in self.layers: x layer(x, mask) return x6. 经典网络对比与选型指南6.1 各网络适用场景分析不同的深度学习网络架构适用于不同的任务类型选择合适的模型是项目成功的关键。CNN适用场景图像分类、目标检测、图像分割处理具有局部相关性的网格数据需要平移不变性的任务GNN适用场景社交网络分析、推荐系统分子性质预测、知识图谱任何图结构数据的处理Transformer适用场景机器翻译、文本生成语音识别、时间序列预测需要长距离依赖建模的任务YOLO适用场景实时目标检测视频监控、自动驾驶需要高速度和高精度的检测任务6.2 性能对比与选择标准网络类型计算复杂度内存需求训练难度推理速度适用数据CNN中等中等容易快图像、视频GNN高高中等中等图结构数据Transformer高高困难慢序列数据YOLO中等中等中等很快图像检测选择建议图像分类任务优先选择ResNet、EfficientNet等CNN变体目标检测任务YOLO系列适合实时应用Faster R-CNN适合高精度需求自然语言处理Transformer架构BERT、GPT是当前最佳选择图数据分析根据图规模选择GCN、GraphSAGE或GAT6.3 混合架构设计实践在实际项目中经常需要组合不同网络架构class MultiModalNetwork(nn.Module): 多模态网络结合CNN和Transformer def __init__(self, image_size, vocab_size, d_model, num_classes): super().__init__() # 图像分支CNN特征提取 self.cnn_backbone nn.Sequential( nn.Conv2d(3, 64, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(64, 128, 3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.AdaptiveAvgPool2d((1, 1)) ) # 文本分支Transformer编码器 self.text_encoder TransformerEncoder( vocab_size, d_model, num_heads8, num_layers6, d_ff2048, max_seq_len512 ) # 融合层 self.fusion nn.Sequential( nn.Linear(128 d_model, 512), nn.ReLU(), nn.Dropout(0.1), nn.Linear(512, num_classes) ) def forward(self, images, text_tokens): # 图像特征提取 image_features self.cnn_backbone(images) image_features image_features.view(image_features.size(0), -1) # 文本特征提取 text_features self.text_encoder(text_tokens) text_features text_features.mean(dim1) # 池化操作 # 特征融合 combined torch.cat([image_features, text_features], dim1) output self.fusion(combined) return output7. 项目实战智能图像分类系统7.1 项目需求分析与设计构建一个完整的智能图像分类系统支持多种网络架构具备以下功能支持CNN、Transformer等多种模型提供训练、评估、预测完整流程可视化训练过程和结果模型导出和部署支持系统架构设计import os import json from datetime import datetime import matplotlib.pyplot as plt class ImageClassificationSystem: def __init__(self, config_pathconfig.json): self.config self.load_config(config_path) self.model None self.train_history [] def load_config(self, config_path): 加载配置文件 default_config { model_type: resnet18, num_classes: 10, batch_size: 32, learning_rate: 0.001, epochs: 100, data_path: ./data, output_dir: ./outputs } if os.path.exists(config_path): with open(config_path, r) as f: user_config json.load(f) default_config.update(user_config) return default_config7.2 模型工厂与训练流水线class ModelFactory: 模型工厂类支持多种网络架构 staticmethod def create_model(model_type, num_classes, **kwargs): if model_type resnet18: from torchvision.models import resnet18 model resnet18(pretrainedTrue) model.fc nn.Linear(model.fc.in_features, num_classes) elif model_type vit: from transformers import ViTForImageClassification model ViTForImageClassification.from_pretrained( google/vit-base-patch16-224, num_labelsnum_classes ) elif model_type custom_cnn: model CustomCNN(num_classesnum_classes) else: raise ValueError(f不支持的模型类型: {model_type}) return model class TrainingPipeline: 训练流水线 def __init__(self, model, train_loader, val_loader, config): self.model model self.train_loader train_loader self.val_loader val_loader self.config config self.device torch.device(cuda if torch.cuda.is_available() else cpu) self.model.to(self.device) self.criterion nn.CrossEntropyLoss() self.optimizer torch.optim.Adam( model.parameters(), lrconfig[learning_rate] ) self.scheduler torch.optim.lr_scheduler.StepLR( self.optimizer, step_size30, gamma0.1 ) def train_epoch(self): 训练一个epoch self.model.train() running_loss 0.0 correct 0 total 0 for batch_idx, (inputs, targets) in enumerate(self.train_loader): inputs, targets inputs.to(self.device), targets.to(self.device) self.optimizer.zero_grad() outputs self.model(inputs) loss self.criterion(outputs, targets) loss.backward() self.optimizer.step() running_loss loss.item() _, predicted outputs.max(1) total targets.size(0) correct predicted.eq(targets).sum().item() epoch_loss running_loss / len(self.train_loader) epoch_acc 100. * correct / total return epoch_loss, epoch_acc def validate(self): 验证模型 self.model.eval() val_loss 0.0 correct 0 total 0 with torch.no_grad(): for inputs, targets in self.val_loader: inputs, targets inputs.to(self.device), targets.to(self.device) outputs self.model(inputs) loss self.criterion(outputs, targets) val_loss loss.item() _, predicted outputs.max(1) total targets.size(0) correct predicted.eq(targets).sum().item() val_loss / len(self.val_loader) val_acc 100. * correct / total return val_loss, val_acc def run_training(self): 执行完整训练流程 best_acc 0 train_history { train_loss: [], train_acc: [], val_loss: [], val_acc: [] } for epoch in range(self.config[epochs]): train_loss, train_acc self.train_epoch() val_loss, val_acc self.validate() self.scheduler.step() # 记录历史 train_history[train_loss].append(train_loss) train_history[train_acc].append(train_acc) train_history[val_loss].append(val_loss) train_history[val_acc].append(val_acc) print(fEpoch: {epoch1:03d} | fTrain Loss: {train_loss:.4f} | Train Acc: {train_acc:.2f}% | fVal Loss: {val_loss:.4f} | Val Acc: {val_acc:.2f}%) # 保存最佳模型 if val_acc best_acc: best_acc val_acc torch.save(self.model.state_dict(), best_model.pth) return train_history7.3 结果可视化与模型部署class ResultVisualizer: 结果可视化工具 def __init__(self, train_history): self.history train_history def plot_training_curves(self, save_pathNone): 绘制训练曲线 fig, (ax1, ax2) plt.subplots(1, 2, figsize(15, 5)) # 损失曲线 ax1.plot(self.history[train_loss], labelTrain Loss) ax1.plot(self.history[val_loss], labelValidation Loss) ax1.set_title(Training and Validation Loss) ax1.set_xlabel(Epoch) ax1.set_ylabel(Loss) ax1.legend() ax1.grid(True) # 准确率曲线 ax2.plot(self.history[train_acc], labelTrain Accuracy) ax2.plot(self.history[val_acc], labelValidation Accuracy) ax2.set_title(Training and Validation Accuracy) ax2.set_xlabel(Epoch) ax2.set_ylabel(Accuracy (%)) ax2.legend() ax2.grid(True) plt.tight_layout() if save_path: plt.savefig(save_path, dpi300, bbox_inchestight) plt.show() def plot_confusion_matrix(self, model, test_loader, class_names, save_pathNone): 绘制混淆矩阵 from sklearn.metrics import confusion_matrix import seaborn as sns model.eval() all_preds [] all_targets [] with torch.no_grad(): for inputs, targets in test_loader: inputs inputs.to(next(model.parameters()).device) outputs model(inputs) _, preds outputs.max(1) all_preds.extend(preds.cpu().numpy()) all_targets.extend(targets.numpy()) cm confusion_matrix(all_targets, all_preds) plt.figure(figsize(10, 8)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.title(Confusion Matrix) plt.ylabel(True Label) plt.xlabel(Predicted Label) if save_path: plt.savefig(save_path, dpi300, bbox_inchestight) plt.show() class ModelDeployer: 模型部署工具 staticmethod def export_to_onnx(model, dummy_input, onnx_path): 导出为ONNX格式 torch.onnx.export( model, dummy_input, onnx_path, export_paramsTrue, opset_version11, do_constant_foldingTrue, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, output: {0: batch_size}} ) print(f模型已导出到: {onnx_path}) staticmethod def create_flask_api(model_path, class_names): 创建Flask API服务 flask_template from flask import Flask, request, jsonify import torch from torchvision import transforms from PIL import Image import io app Flask(__name__) # 加载模型 model torch.load({}, map_locationcpu) model.eval() # 图像预处理 transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) class_names {} app.route(/predict, methods[POST]) def predict(): if file not in request.files: return jsonify({error: 没有文件上传}) file request.files[file] if file.filename : return jsonify({error: 没有选择文件}) try: # 处理图像 image Image.open(io.BytesIO(file.read())).convert(RGB) image_tensor transform(image).unsqueeze(0) # 预测 with torch.no_grad