跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

PyTorch 实战:从拟合直线到识别手写数字

记录用 PyTorch 从零实现线性回归、简单神经网络,再到 CNN 识别 MNIST 手写数字的过程。包含完整可运行代码,并对比了 Rust 开发者上手 Python AI 的体会,指出 Python 生态高效,但可通过静态类型标注和跨语言部署弥补不足。

城市逃兵发布于 2026/6/30更新于 2026/10/1570 浏览

搭建环境

开头总是装库。PyTorch 用 pip 装就行,顺便带上 numpy 和 matplotlib:

pip install torch torchvision
pip install numpy matplotlib

线性回归:最简模型

第一个程序用线性回归,拟合带噪声的直线。生成数据、定义模型、训练、画图,一条龙。代码直给:

import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt

# 生成训练数据
x = torch.linspace(0, 10, 100).unsqueeze(1)
y = 2 * x + 1 + torch.randn(100, 1) * 0.5

# 定义模型
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.linear = nn.Linear(1, 1)

    def forward(self, x):
        return self.linear(x)

# 创建模型实例
model = LinearModel()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练模型
epochs = 100
for epoch in range(epochs):
    # 前向传播
    outputs = model(x)
    # 计算损失
    loss = criterion(outputs, y)
    # 反向传播
    optimizer.zero_grad()
    loss.backward()
    # 更新参数
    optimizer.step()
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')

# 测试模型
with torch.no_grad():
    predicted = model(x)

# 可视化结果
plt.scatter(x.numpy(), y.numpy(), label='Original data')
plt.plot(x.numpy(), predicted.numpy(), 'r-', label='Fitted line')
plt.legend()
plt.show()
print("Hello World! AI 模型训练完成")

Loss 下降到 0.1 左右就能看出红线基本穿过散点。没什么难点,SGD 调调学习率就行。

拐点:加上非线性

线性回归只能画直线,遇到抛物线立刻抓瞎。这时候就得靠神经网络引入非线性了。这段代码在之前基础上加了一个隐藏层,用 ReLU 激活,拟合 y = x² 加噪声的数据:

import torch
import torch.nn as nn
import torch.optim as optim

# 生成非线性数据
x = torch.linspace(-1, 1, 100).unsqueeze(1)
y = x.pow(2) + 0.2 * torch.randn(100, 1)

# 定义神经网络模型
class NeuralNet(nn.Module):
    def __init__(self):
        super(NeuralNet, self).__init__()
        self.hidden = nn.Linear(1, 10)
        self.output = nn.Linear(10, 1)

    def forward(self, x):
        x = torch.relu(self.hidden(x))
        x = self.output(x)
        return x

# 创建模型实例
model = NeuralNet()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
epochs = 1000
for epoch in range(epochs):
    outputs = model(x)
    loss = criterion(outputs, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')

# 测试模型
with torch.no_grad():
    predicted = model(x)

# 可视化结果
import matplotlib.pyplot as plt
plt.scatter(x.numpy(), y.numpy(), label='Original data')
plt.plot(x.numpy(), predicted.numpy(), 'r-', label='Neural network prediction')
plt.legend()
plt.show()

训练 1000 轮,损失降到 0.1 左右,曲线基本贴合抛物线。这里用 SGD 依然可行,但如果收敛慢,试试 Adam 会快很多——实际用的时候我一般直接上 Adam。

网络结构其实很简单:输入 -> 隐藏层(10 个神经元,ReLU) -> 输出。核心就两点:层间线性变换加激活函数,以及反向传播自动算梯度。不用自己推导链式法则,PyTorch 全包了。

手写数字识别:CNN 初接触

MNIST 是图像分类的 Hello World。数据加载用 torchvision 一行搞定,预处理做 ToTensor 和归一化:

import torch
import torchvision
import torchvision.transforms as transforms

# 数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# 加载 MNIST 数据集
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)

# 查看数据
import matplotlib.pyplot as plt
import numpy as np

# 函数:显示图像
def imshow(img):
    img = img / 2 + 0.5  # 反归一化
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# 获取一批训练数据
dataiter = iter(trainloader)
images, labels = next(dataiter)

# 显示图像
imshow(torchvision.utils.make_grid(images))
print('标签:', ' '.join(f'{labels[j]}' for j in range(4)))

模型是一个两层卷积加两层全连接的简单 CNN:

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 卷积层
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        # 池化层
        self.pool = nn.MaxPool2d(2, 2)
        # 全连接层
        self.fc1 = nn.Linear(64 * 12 * 12, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 64 * 12 * 12)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 创建模型实例
net = Net()
print(net)

print(net) 能看到每一层的形状和参数数量。接下来训练 5 个 epoch,打印每个批次损失:

import torch.optim as optim

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 训练模型
epochs = 5
for epoch in range(epochs):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 获取输入
        inputs, labels = data
        # 清零梯度
        optimizer.zero_grad()
        # 前向传播
        outputs = net(inputs)
        # 计算损失
        loss = criterion(outputs, labels)
        # 反向传播
        loss.backward()
        # 更新参数
        optimizer.step()
        # 统计损失
        running_loss += loss.item()
        if i % 100 == 99:
            print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 100:.3f}')
    running_loss = 0.0
print('训练完成')

训练后测试:

# 测试模型
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
print(f'测试准确率:{100 * correct / total:.2f}%')

# 查看预测结果
dataiter = iter(testloader)
images, labels = next(dataiter)

# 显示图像
imshow(torchvision.utils.make_grid(images))
print('真实标签:', ' '.join(f'{labels[j]}' for j in range(4)))

# 预测
outputs = net(images)
_, predicted = torch.max(outputs, 1)
print('预测标签:', ' '.join(f'{predicted[j]}' for j in range(4)))

准确率在 97% 左右,再跑几轮能到 99%。这个模型很小,参数量不到 1M,拿 CPU 跑也很快。

站在 Rust 的角度看 Python AI

写 Rust 的人初看 Python AI 栈,有几个明显感受:

  • 开发节奏:Python 写起来确实快,不用跟生命周期和所有权较劲。不过 PyTorch 的底层是 C++/CUDA,性能瓶颈不在这里。
  • 生态碾压:torchvision、transformers、diffusers……现成轮子太多,想做个东西几乎不用从零造轮子。Rust 的 ML 生态还在早期,tch-rs 之类的绑定能用,但顺滑程度差远了。
  • 动态类型的两面:一方面写起来随性,不用定义一大堆 struct;另一方面,没类型检查,复杂项目容易出一眼看不出的 bug。我会尽量加类型标注,比如 def forward(self, x: torch.Tensor) -> torch.Tensor:,再配合 mypy 做静态检查,算是折中。
  • 内存与部署:Python 的内存管理是自动的,模型训练完保存 state_dict,线上推理可以用 TorchScript 或 ONNX 导出,再用 Rust 的 tract 或 sonos 跑,速度不错,内存也可控。这个组合挺实用。

如果从 Rust 转过来学 Python AI,个人觉得几点比较有用:

  • 系统编程的经验对理解张量布局、设备(CPU/GPU)管理、数据加载的流水线很有帮助,不是黑盒瞎调。
  • 保持写 Rust 时养成的模块化习惯,把数据加载、模型定义、训练循环拆开,比全塞在一个 Jupyter 单元格里强。
  • 尽早接触实战项目,最好结合自己领域的数据,比看十遍教程管用。
  • Python 和 Rust 不是非此即彼:用 Python 做实验和原型,用 Rust 做高性能推理或后处理,各取所长。

结尾

从线性回归到 CNN,算是在 Python AI 的世界里走了一圈。最大的感触是:语言只是工具,生态和库才是真正决定开发效率的东西。Rust 的确定性让人安心,Python 的灵活省时间,两者结合反而更顺手。

代码都在这,拿过去跑一跑,改一改网络结构或超参数,比看再多理论都实际。

目录

  1. 搭建环境
  2. 线性回归:最简模型
  3. 生成训练数据
  4. 定义模型
  5. 创建模型实例
  6. 定义损失函数和优化器
  7. 训练模型
  8. 测试模型
  9. 可视化结果
  10. 拐点:加上非线性
  11. 生成非线性数据
  12. 定义神经网络模型
  13. 创建模型实例
  14. 定义损失函数和优化器
  15. 训练模型
  16. 测试模型
  17. 可视化结果
  18. 手写数字识别:CNN 初接触
  19. 数据预处理
  20. 加载 MNIST 数据集
  21. 查看数据
  22. 函数:显示图像
  23. 获取一批训练数据
  24. 显示图像
  25. 创建模型实例
  26. 定义损失函数和优化器
  27. 训练模型
  28. 测试模型
  29. 查看预测结果
  30. 显示图像
  31. 预测
  32. 站在 Rust 的角度看 Python AI
  33. 结尾

更多推荐文章

查看全部
  • 网络安全工程师转行指南与行业发展前景
  • SuperAgent HTTP 请求库快速上手指南
  • VS Code + WSL 下 GitHub 访问不稳定及 Copilot 卡死解决方案
  • Python AI 大模型部署实战:本地运行、API 服务与 Docker 封装
  • 基于 Obsidian 与 OpenClaw 的 AI 知识管理方案
  • 程序员技术变现与远程工作平台精选
  • 前端三年成长复盘:从迷茫到互联网实战
  • 飞算 Java AI 编程助手功能介绍与实践
  • HDFS 读写机制深度解析与分布式存储架构
  • PyCharm 零基础入门指南:项目创建、配置与高效开发
  • 数据结构:二叉树基础与链式存储实现
  • Windows 10/11 系统下 WSL2 安装 Ubuntu 全流程指南
  • Python 桌面应用开发入门:基于 Tkinter 实现简易计算器
  • Vibe Coding 前端搭建:用 Playwright MCP 解决视觉盲区
  • Kali Linux 环境下使用 Docker 搭建 Vulhub 靶场
  • CentOS Stream Docker 安装与配置全流程指南
  • RabbitMQ 技术指南(C/C++版)
  • 在 macOS 上通过 Docker 本地安装 OpenClaw 完整教程
  • 使用 Github 与 Hexo 搭建在线个人博客
  • Ubuntu 22.04 下 libwebkit2gtk-4.1-0 安装全记录:从踩坑到落地

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online