楼层: 首页/ 软件技术/ Python AI 数据科学/ AI 实战项目综合
7

AI 实战项目综合

End-to-End Projects & Deployment

学完零件,该拼整车了。端到端项目的标准路径:数据获取 → 清洗 → 分析 → 建模 → 评估 → 部署。下面两个项目覆盖经典 ML 和深度学习两大方向。

项目一:电影推荐系统

论思路

拿 MovieLens 数据集(用户-电影评分表),用协同过滤:找"和你口味相似的用户喜欢什么,就推荐给你"。Pandas 做数据清洗,Scikit-learn 的 cosine_similarity 算用户相似度。

from sklearn.metrics.pairwise import cosine_similarity # 假设 ratings 是个 DataFrame:user_id, movie_id, rating # 透视为用户×电影矩阵 user_movie = ratings.pivot_table(index="user_id", columns="movie_id", values="rating") # 缺失值填 0(没看过=没打分) user_movie = user_movie.fillna(0) # 算用户之间的相似度 sim = cosine_similarity(user_movie) # 给用户 42 推荐:找和他最像的 5 个用户看过的电影 target = 42 similar_users = sim[target].argsort()[-6:-1] # 然后取这些用户看过、target 没看过的电影,按评分排

论这个项目的三个看点

① pivot_table:把长表转成宽表,这是协同过滤的标准预处理。

② cosine_similarity:不用自己算向量夹角,sklearn 一行搞定。

③ 冷启动问题:新用户没评分,相似度算不出来——这是真实推荐系统要解决的,入门阶段知道有这回事就行。

项目二:图像分类 CIFAR-10

import torch.nn as nn # 用 CNN(卷积神经网络)处理图像,比全连接强 class CNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc = nn.Linear(64 * 8 * 8, 10) def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = self.pool(torch.relu(self.conv2(x))) x = x.view(-1, 64 * 8 * 8) return self.fc(x) # 同样的四步训练循环,跑 20 轮左右能到 75% 准确率

论CNN 为什么比全连接强

全连接网络把图片拉成一维向量,丢掉了"像素之间的位置关系"。CNN 用卷积核在图片上滑动,能识别"边缘、纹理、形状"这些局部特征——第一层学边缘,第二层学纹理,后面几层学物体部件。这就是为什么处理图像要用 CNN 而不是全连接。

迁移学习:别从零开始训

论为什么用预训练模型

自己从零训一个 ResNet 要几百块 GPU 几星期。但 PyTorch Hub 里有"别人在 ImageNet 上训好的"权重——你拿来,改一下最后几层,用自己几百张图微调几轮,效果就比从零训好得多。这就是迁移学习:让模型先学会"看世界",再教它看你的特定任务。

from torchvision import models # 加载预训练 ResNet18 model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) # 冻结前面的层(只训最后一层) for param in model.parameters(): param.requires_grad = False # 把最后一层改成你自己的类别数(比如 5 类) model.fc = nn.Linear(model.fc.in_features, 5) model = model.to(device) # 然后照常训练,几百张图就能出不错的效果

模型保存与加载

# PyTorch:只存权重(推荐) torch.save(model.state_dict(), "model.pth") # 加载:要先 new 一个同结构的模型 model = MyNet() model.load_state_dict(torch.load("model.pth", weights_only=True)) model.eval() # 切到评估模式 # Scikit-learn 模型用 joblib import joblib joblib.dump(model, "rf.joblib") model = joblib.load("rf.joblib")

简单部署:FastAPI 推理接口

from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() model.eval() class Input(BaseModel): features: list[float] @app.post("/predict") def predict(data: Input): x = torch.tensor(data.features).float() with torch.no_grad(): # 推理时不用算梯度,省内存 out = model(x) pred = out.argmax().item() return {"prediction": pred} # 跑起来:uvicorn main:app --reload # 访问 http://127.0.0.1:8000/docs 有自动生成的接口文档

论部署三步走

① 存模型:训练好后 torch.save(model.state_dict(), "model.pth")。

② 起服务:FastAPI 包一个 /predict 接口,接 JSON 输入返回 JSON 结果。

③ 上线:用 uvicorn 跑,生产环境前面套个 Nginx。入门阶段本地跑通就够,Docker、K8s 是后话。

部署常见问题

① 加载慢:模型文件几百 MB,启动时别每次请求都 load 一次——服务启动时 load 到内存。
② 预处理要一致:训练时怎么 normalize,推理时就得怎么 normalize,别让前端传原始像素、后端忘了 normalize。
③ 别阻塞:FastAPI 是异步的,但 PyTorch 推理本身是阻塞的——真要高并发得多开几个 worker。

推理时的正确姿势

model.eval() with torch.no_grad(): # 前向传播不计算梯度,省显存省时间 outputs = model(new_data.to(device)) pred_class = outputs.argmax(dim=1).item() # 如果要概率,过个 softmax probs = torch.softmax(outputs, dim=1)

常见报错速查

报错大概率原因
RuntimeError: Expected all tensors on same device数据在 CPU,模型在 GPU。两边都 .to(device)。
RuntimeError: mat1 and mat2 shapes cannot be multiplied输入维度和第一层不匹配,检查 .view(-1, 784)。
loss 变 nan学习率太大、除零、数据有 NaN。先降 lr 到 0.0001。
CUDA out of memorybatch_size 太大,或者忘了 no_grad()。
TypeError: can't convert cuda tensorGPU 张量要 .cpu() 才能转 numpy。