🚀 3、快速上手:第一个MindSpore训练脚本

说实话,很多初学者拿到一个新框架,最怕的就是“跑不起来”。我刚开始接触MindSpore时也踩过几个坑,但一旦把第一个脚本跑通,后面就顺了。这一章咱们直接动手——写一个极简的训练脚本,在昇腾设备上跑起来,然后看看日志和性能数据。你跟着我走一遍,半小时内就能看到loss下降。

① 训练脚本 网络 + 数据 + 循环 ② 昇腾运行 NPU 设备 / 图模式 ③ 日志 & 性能 loss / 吞吐 / 耗时 快速上手三连:写脚本 → 昇腾执行 → 看数据 本章核心流程,一个闭环

📝 3.1 写一个能跑的脚本

我个人习惯先用一个最简单的全连接网络做验证。下面这个例子用 MindSpore 实现了一个两层的分类器,数据集就用随机生成的 fake data。你直接复制就能跑。

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor, context
from mindspore.ops import operations as P

# 设置运行环境:昇腾 NPU
context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")

# 定义一个简单的网络
class SimpleNet(nn.Cell):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Dense(32, 64)
        self.fc2 = nn.Dense(64, 10)
        self.relu = nn.ReLU()

    def construct(self, x):
        x = self.relu(self.fc1(x))
        return self.fc2(x)

net = SimpleNet()
loss_fn = nn.SoftmaxCrossEntropyWithLogits()
optimizer = nn.SGD(net.trainable_params(), learning_rate=0.01)

# 伪造数据
data = Tensor(np.random.randn(128, 32).astype(np.float32))
label = Tensor(np.random.randint(0, 10, (128,)).astype(np.int32))

# 训练一步
def forward_fn(data, label):
    logits = net(data)
    loss = loss_fn(logits, label)
    return loss

grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters)
for step in range(20):
    loss, grads = grad_fn(data, label)
    optimizer(grads)
    print(f"step {step}, loss: {loss.asnumpy():.4f}")
💡 我的小习惯: 第一次跑的时候把 mode=context.GRAPH_MODE 打开,昇腾在静态图下性能最好。如果你遇到算子报错,可以先切到 PYNATIVE_MODE 调试,我经常这么干。

⚙️ 3.2 在昇腾上运行

脚本写好了,怎么在昇腾设备上跑?其实很简单。只要你的环境按照第2章搭好了,直接 python train.py 就行。MindSpore 会自动检测到昇腾芯片。

但我遇到过一种情况:明明插了卡,却报错“No device found”。后来发现是环境变量 ASCEND_DEVICE_ID 没设。你可以用下面命令确认:

# 查看可用昇腾设备
npu-smi info
# 或者
ascend-dmi -i

# 指定设备(可选)
export ASCEND_DEVICE_ID=0
python train.py
✅ 跑起来之后你会看到类似输出:
step 0, loss: 2.4123
step 1, loss: 2.3101
step 2, loss: 2.1987
…… loss 逐渐下降,说明网络在正常学习。

嗯,这里要注意:如果你用 PyNative 模式,昇腾也能跑,但图模式才是它的完全体。我建议你一开始就用 GRAPH_MODE,后面调优时再对比。

📊 3.3 查看训练日志与性能数据

光看 loss 打印还不够,咱们得学会“看透”训练过程。MindSpore 提供了 Callback 机制,可以轻松记录时间、吞吐、loss 曲线。

下面我加了一个 LossMonitor 和 TimeMonitor,你跑完就能看到每个 step 的耗时:

from mindspore.train.callback import LossMonitor, TimeMonitor
from mindspore import Model

model = Model(net, loss_fn=loss_fn, optimizer=optimizer)
model.train(epoch=1, train_dataset=dataset, callbacks=[LossMonitor(), TimeMonitor()])

输出会变成这样:

epoch: 1 step: 0, loss: 2.312, per_step_time: 23.45 ms
epoch: 1 step: 1, loss: 2.201, per_step_time: 21.02 ms
...

你想想看,如果 per_step_time 突然飙到 100ms,那肯定有瓶颈。我一般会先看数据加载是不是成了短板。

📈 3.4 性能数据进阶:profiler 初探

想更深入地看算子耗时、内存占用?MindSpore 自带 Profiler,一键导出性能数据。我个人觉得这是调优最实用的工具。

from mindspore.profiler import Profiler

profiler = Profiler(output_path="./profiler_data")
# 训练代码...
model.train(epoch=1, train_dataset=dataset)
profiler.analyse()

跑完后在 ./profiler_data 下会生成 ascend_*.json 文件。你可以用 MindSpore Insight 可视化界面打开,或者直接看文本摘要。我曾经靠这个发现一个算子被重复编译了三次,优化后训练速度提升了 40%。

⚠️ 避坑指南: 我曾经在 profiler 开启时忘了关,结果训练慢了好几倍。记得在正式跑长任务前把 profiler 关掉,或者只在调试时开启。

🧩 3.5 一张表总结:快速上手三板斧

步骤核心操作常用命令/代码
1. 写脚本定义网络、loss、优化器nn.Cell + construct
2. 昇腾运行设置 device_target="Ascend"context.set_context
3. 看日志使用 Callback 或 printLossMonitor, TimeMonitor
4. 性能分析Profiler 采集Profiler(output_path=...)

说白了,快速上手就是这三步:写一个能收敛的脚本,在昇腾上跑通,然后通过日志和数据确认它在高效运行。你只要跑通一次,后面所有章节都会建立在这个基础上。