|
- MindSpore(昇思)是华为开源的一款全场景深度学习框架
- https://www.mindspore.cn/install
- https://www.mindspore.cn/tutorials/zh-CN/stable/index.html
```
# Linux/macOS
python -m venv mindspore_env
source mindspore_env/bin/activate
# Windows
python -m venv mindspore_env
mindspore_env\Scripts\activate
micromamba create -n mdsp python=3.12 -y
micromamba activate mdsp
pip install mindspore==2.9.0 -i https://repo.mindspore.cn/pypi/simple --trusted-host repo.mindspore.cn --extra-index-url https://repo.huaweicloud.com/repository/pypi/simple
```
```
import mindspore
print("MindSpore版本:", mindspore.__version__)
# 预期输出:无报错且显示版本号
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## MindSpore框架概述
### 什么是MindSpore
MindSpore是华为开源的**新一代深度学习框架**,旨在实现**高效、易用、灵活**的AI开发体验。
### 核心特性
| 特性 | 说明 |
|-----|------|
| **全场景协同** | 云边端统一架构,支持多种部署场景 |
| **自动微分** | 基于源码变换的自动微分机制 |
| **函数式编程** | 支持函数式和面向对象混合编程 |
| **自动并行** | 自动优化分布式训练性能 |
| **原生Ascend支持** | 深度适配华为昇腾芯片 |
### 框架定位
```
MindSpore
├── 训练推理一体化
├── 全场景协同(云/边/端)
├── 自动并行优化
└── Ascend原生加速
```
### 与其他框架对比
| 框架 | 优势 | 适用场景 |
|-----|------|---------|
| MindSpore | 全场景协同、Ascend优化 | 华为生态、端云协同 |
| PyTorch | 灵活、易用 | 研究、快速原型 |
| TensorFlow | 生产部署 | 工业应用 |
| PaddlePaddle | 国产化、中文友好 | 国内企业 |
### 应用场景
- **计算机视觉**:图像分类、目标检测、图像分割
- **自然语言处理**:文本分类、机器翻译、对话系统
- **推荐系统**:CTR预测、召回排序
- **科学计算**:分子模拟、气象预测
### 版本与生态
```
MindSpore
├── MindSpore (主框架)
├── MindSpore Lite (端侧推理)
├── MindSpore Lite (端侧训练)
├── MindSpore Serving (模型服务)
└── MindInsight (可视化调试)
```
|
|
## 设计理念
### 核心设计原则
MindSpore遵循以下设计理念:
**1. 自动微分(Automatic Differentiation)**
- 基于源码变换的自动微分
- 支持函数式和命令式混合编程
- 自动生成反向传播代码
**2. 统一架构(Unified Architecture)**
- 训练推理一体化的模型定义
- 动态图和静态图统一
- 云边端协同部署
**3. 自动并行(Auto Parallel)**
- 自动数据并行
- 自动模型并行
- 自动混合并行
### 编程范式
MindSpore支持两种编程范式:
**函数式编程(Functional)**
```python
import mindspore as ms
from mindspore import nn, ops
@ms.jit # Just-In-Time编译
def forward_fn(x, y):
z = x + y
return z * 2
```
**面向对象编程(OOP)**
```python
class MyNet(nn.Cell):
def __init__(self):
super().__init__()
self.fc = nn.Dense(10, 1)
def construct(self, x):
return self.fc(x)
```
### 高阶自动微分
MindSpore支持**高阶自动微分**(高阶导数):
```python
grad_fn = ms.grad(fn)
grad_grad_fn = ms.grad(grad_fn) # 二阶导数
```
### 数据流图
MindSpore采用**数据流图**(Dataflow Graph)进行优化:
```
用户代码
↓ (JIT编译)
计算图
↓ (图优化)
优化后的计算图
↓ (自动微分)
训练图
↓ (编译执行)
Ascend/CPU/GPU
```
### 模块化设计
```
mindspore
├── common (公共API)
├── nn (神经网络层)
├── ops (算子库)
├── train (训练组件)
├── dataset (数据处理)
└── context (运行配置)
```
|
|
## 自动微分
### 自动微分原理
MindSpore使用**符号微分**(Symbolic Differentiation)实现自动求导。
### grad函数
`mindspore.grad` 用于计算函数的梯度:
```python
import mindspore as ms
def f(x, y):
return x * x + y * y
# 计算f关于x的梯度
grad_f = ms.grad(f, grad_position=0) # grad_position=0表示对第一个参数求导
x = ms.Tensor(2.0)
y = ms.Tensor(3.0)
grad_x = grad_f(x, y) # 2x = 4
```
### value_and_grad
同时返回函数值和梯度:
```python
def loss_fn(params, x, y):
pred = model(x)
loss = ops.mse_loss(pred, y)
return loss
loss_and_grad = ms.value_and_grad(loss_fn)
loss_value, gradients = loss_and_grad(params, x, y)
```
### 高阶导数
计算二阶及更高阶导数:
```python
# 一阶导数
first_grad = ms.grad(f)
# 二阶导数
second_grad = ms.grad(first_grad)
# 三阶导数
third_grad = ms.grad(second_grad)
```
### 自定义求导
使用`@ms.jit`装饰器启用自动微分:
```python
@ms.jit
def train_step(model, inputs, labels):
# 前向传播
logits = model(inputs)
loss = ops.cross_entropy(logits, labels)
# 反向传播
grads = ms.grad(loss, model.parameters())
# 参数更新
optimizer(grads)
return loss
```
### 梯度累积
累积梯度用于模拟大batch:
```python
accumulation_steps = 4
for i, (data, label) in enumerate(dataset):
logits = model(data)
loss = loss_fn(logits, label)
loss = loss / accumulation_steps # 缩放loss
grads = grad_fn(model.parameters())
# 累积梯度
if (i + 1) % accumulation_steps == 0:
optimizer(grads) # 实际更新参数
model.set_grad() # 清空梯度
```
|
|
## 数据管理
### Dataset API
MindSpore提供`mindspore.dataset`模块处理数据:
```python
import mindspore.dataset as ds
# 创建数据集
dataset = ds.ImageFolderDataset("/path/to/images")
# 数据增强
transform = [
vision.Resize((224, 224)),
vision.ToTensor(),
vision.Normalize(mean=[0.5], std=[0.5])
]
dataset = dataset.map(operations=transform, input_columns="image")
# 批处理
dataset = dataset.batch(batch_size=32)
# 数据迭代
for data, label in dataset:
# 训练代码
pass
```
### GeneratorDataset
从Python生成器创建数据集:
```python
def data_generator():
for i in range(100):
yield np.random.rand(28, 28).astype(np.float32), np.int32(i % 10)
dataset = ds.GeneratorDataset(data_generator, ["data", "label"])
dataset = dataset.batch(32)
```
### 常用数据集
```python
# CIFAR-10
dataset = ds.Cifar10Dataset("/path/to/cifar10")
# MNIST
dataset = ds.MnistDataset("/path/to/mnist")
# ImageNet
dataset = ds.ImageFolderDataset("/path/to/imagenet")
# 自定义数据集
dataset = ds.TextFileDataset(["data.txt"])
```
### 数据增强
```python
from mindspore.dataset.vision import c_transforms as vision
transforms = [
vision.RandomCrop((32, 32), padding=4),
vision.RandomHorizontalFlip(),
vision.Resize((224, 224)),
vision.ToTensor(),
vision.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
]
```
### 数据迭代器
```python
# 创建迭代器
iterator = dataset.create_dict_iterator()
# 获取数据
for batch in iterator:
images = batch["image"]
labels = batch["label"]
```
|
|
## 基础API
### 张量(Tensor)
```python
import mindspore as ms
from mindspore import Tensor
# 创建张量
x = Tensor([1, 2, 3], dtype=ms.float32)
y = Tensor(np.ones((3, 3)), dtype=ms.float32)
# 基本运算
z = x + y
result = ops.matmul(x, y)
```
### 神经网络层
```python
from mindspore import nn
# 全连接层
fc = nn.Dense(in_channels=784, out_channels=10)
# 卷积层
conv = nn.Conv2d(in_channels=3, out_channels=64,
kernel_size=3, padding=1)
# 池化层
pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 批归一化
bn = nn.BatchNorm2d(num_features=64)
# Dropout
dropout = nn.Dropout(keep_prob=0.5)
# 激活函数
relu = nn.ReLU()
```
### 损失函数
```python
# 交叉熵损失
loss_fn = nn.CrossEntropyLoss()
# MSE损失
loss_fn = nn.MSELoss()
# L1损失
loss_fn = nn.L1Loss()
# Smooth L1损失
loss_fn = nn.SmoothL1Loss()
```
### 优化器
```python
from mindspore import nn
# SGD
optimizer = nn.SGD(params=model.trainable_params(),
learning_rate=0.01,
momentum=0.9)
# Adam
optimizer = nn.Adam(params=model.trainable_params(),
learning_rate=0.001)
# AdamW
optimizer = nn.AdamWeightDecay(params=model.trainable_params(),
learning_rate=0.001,
weight_decay=0.01)
```
### 学习率调度
```python
from mindspore import nn
# 固定学习率
lr = 0.01
# 余弦退火
lr_scheduler = nn.CosineDecayLR(min_lr=0.0, max_lr=0.1,
decay_steps=1000)
# 指数衰减
lr_scheduler = nn.ExponentialDecayLR(learning_rate=0.1,
decay_rate=0.9,
decay_steps=100)
# 阶梯衰减
lr_scheduler = nn.dynamic_lr.piecewise_constant_lr(
milestone=[50, 100],
learning_rates=[0.1, 0.01, 0.001]
)
```
### Model训练接口
```python
from mindspore import Model
model = Model(network=net,
loss_fn=loss_fn,
optimizer=optimizer,
metrics={"accuracy"})
# 训练
model.train(epoch=10,
train_dataset=train_dataset,
callbacks=[LossMonitor()])
# 评估
result = model.eval(eval_dataset)
print(result)
```
|
|
# MindSpore 相关概念简练总结
## 1. Just-In-Time (JIT) 编译是什么?
- **核心思想**:运行时将“热点代码”(反复执行的代码)动态编译为高度优化的本地机器码。
- **优点**:兼顾解释执行的**启动快**和提前编译的**运行效率高**。
- **应用**:Java JVM、.NET CLR、JavaScript 引擎(V8)、MindSpore 等。
## 2. MindSpore 中不加 `@ms.jit` 就不能自动求导吗?
- **不是**。自动求导(`ms.grad`)是框架基础功能,**不依赖 `@ms.jit`**。
- **动态图模式(`PYNATIVE_MODE`)** 下无需 `@ms.jit` 即可正常求导,适合调试。
- `@ms.jit` 的作用是**将训练步骤编译为静态图以提升性能**,而非启用求导。
## 3. `ms.grad(loss, model.parameters())` 为什么需要两个参数?
- **原因**:`ms.grad` 是**函数式接口**,必须**显式指定对谁求导**。
- `loss` 只是目标标量,未指明自变量时无法计算偏导数。
- 第二个参数 `model.parameters()` 告诉框架:“请计算 `loss` 关于这些模型参数的梯度”。
- 这与 PyTorch 隐式积累到 `.grad` 的设计不同,体现 MindSpore 的**显式、函数式自动微分**哲学。
|
|
|
|
## ResNet网络结构
### ResNet简介
ResNet(残差网络)通过**残差连接**解决深层网络训练困难问题。
### 核心思想
**残差块**:学习残差映射 F(x) = H(x) - x
```
输入 x
↓
[卷积 → BN → ReLU → 卷积 → BN]
↓
+ (x) ← 残差连接
↓
ReLU
↓
输出
```
### ResNet50结构
```
输入 (3×224×224)
↓
Conv1: 7×7, 64, stride=2
↓
MaxPool: 3×3, stride=2
↓
Conv2_x: [1×1,64] [3×3,64] [1×1,256] × 3
↓
Conv3_x: [1×1,128] [3×3,128] [1×1,512] × 4
↓
Conv4_x: [1×1,256] [3×3,256] [1×1,1024] × 6
↓
Conv5_x: [1×1,512] [3×3,512] [1×1,2048] × 3
↓
GlobalAvgPool
↓
FC: 2048 → num_classes
```
### Bottleneck结构
```
输入 (256通道)
↓
1×1 Conv: 256 → 64 (降维)
↓
3×3 Conv: 64 → 64
↓
1×1 Conv: 64 → 256 (升维)
↓
与输入相加 (残差连接)
```
### 参数量
| 模型 | 层数 | 参数量 |
|-----|------|--------|
| ResNet18 | 18 | 11.7M |
| ResNet34 | 34 | 21.8M |
| ResNet50 | 50 | 25.6M |
| ResNet101 | 101 | 44.5M |
| ResNet152 | 152 | 60.2M |
|
|
## ResNet50完整代码
```python
import mindspore as ms
from mindspore import nn, ops
from mindspore.common.initializer import Normal
class ResidualBlock(nn.Cell):
"""残差块"""
expansion = 4
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels,
kernel_size=1, stride=1,
padding=0, pad_mode='pad')
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels,
kernel_size=3, stride=stride,
padding=1, pad_mode='pad')
self.bn2 = nn.BatchNorm2d(out_channels)
self.conv3 = nn.Conv2d(out_channels, out_channels * self.expansion,
kernel_size=1, stride=1,
padding=0, pad_mode='pad')
self.bn3 = nn.BatchNorm2d(out_channels * self.expansion)
self.relu = nn.ReLU()
# 快捷连接
self.shortcut = nn.SequentialCell()
if stride != 1 or in_channels != out_channels * self.expansion:
self.shortcut = nn.SequentialCell([
nn.Conv2d(in_channels, out_channels * self.expansion,
kernel_size=1, stride=stride,
padding=0, pad_mode='pad'),
nn.BatchNorm2d(out_channels * self.expansion)
])
def construct(self, x):
out = self.relu(self.bn1(self.conv1(x)))
out = self.relu(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
out += self.shortcut(x)
out = self.relu(out)
return out
class ResNet50(nn.Cell):
"""ResNet50网络"""
def __init__(self, num_classes=1000):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2,
padding=3, pad_mode='pad')
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')
self.layer1 = self._make_layer(64, 64, 3)
self.layer2 = self._make_layer(256, 128, 4, stride=2)
self.layer3 = self._make_layer(512, 256, 6, stride=2)
self.layer4 = self._make_layer(1024, 512, 3, stride=2)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Dense(512 * 4, num_classes)
def _make_layer(self, in_channels, out_channels, blocks, stride=1):
layers = []
layers.append(ResidualBlock(in_channels, out_channels, stride))
for _ in range(1, blocks):
layers.append(ResidualBlock(out_channels * 4, out_channels))
return nn.SequentialCell(layers)
def construct(self, x):
x = self.relu(self.bn1(self.conv1(x)))
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = ops.reshape(x, (x.shape[0], -1))
x = self.fc(x)
return x
```
### 模型实例化
```python
# 创建模型
model = ResNet50(num_classes=10)
# 打印网络结构
print(model)
# 统计参数量
total_params = sum([param.size for param in model.trainable_params()])
print(f"Total parameters: {total_params:,}")
```
|
|
## 训练流程
### 数据准备
```python
import mindspore.dataset as ds
from mindspore.dataset.vision import c_transforms as vision
from mindspore import context
# 设置运行模式
context.set_context(mode=context.GRAPH_MODE, device_target="GPU")
# 数据增强
def create_dataset(data_path, batch_size=32):
dataset = ds.ImageFolderDataset(data_path)
transform = [
vision.Resize((224, 224)),
vision.RandomHorizontalFlip(),
vision.ToTensor(),
vision.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
]
dataset = dataset.map(operations=transform,
input_columns="image")
dataset = dataset.batch(batch_size)
return dataset
train_dataset = create_dataset("/path/to/train", batch_size=32)
eval_dataset = create_dataset("/path/to/eval", batch_size=32)
```
### 训练配置
```python
from mindspore import nn, Model, LossMonitor
from mindspore.train.callback import ModelCheckpoint, CheckpointConfig
# 损失函数
loss_fn = nn.CrossEntropyLoss(sparse=True, reduction='mean')
# 优化器
optimizer = nn.Momentum(params=model.trainable_params(),
learning_rate=0.01,
momentum=0.9)
# 学习率调度
lr_scheduler = nn.CosineDecayLR(min_lr=0.0, max_lr=0.1,
decay_steps=10000)
# 模型封装
model = Model(net=model,
loss_fn=loss_fn,
optimizer=optimizer,
metrics={"accuracy"})
# Checkpoint配置
config_ck = CheckpointConfig(save_checkpoint_steps=100,
keep_checkpoint_max=10)
ckpoint_cb = ModelCheckpoint(prefix='resnet50',
directory='./checkpoint',
config=config_ck)
```
### 模型训练
```python
# 训练模型
model.train(epoch=10,
train_dataset=train_dataset,
callbacks=[LossMonitor(per_print_times=100),
ckpoint_cb],
dataset_sink_mode=True) # 数据下沉加速
# 模型评估
result = model.eval(eval_dataset)
print(f"Eval Accuracy: {result['accuracy']:.4f}")
```
### 自定义训练循环
```python
from mindspore import ms_function
@ms_function
def train_step(network, data, label):
"""单步训练"""
logits = network(data)
loss = loss_fn(logits, label)
grads = ms.grad(loss_fn, network.trainable_params())
optimizer(grads)
return loss
# 训练循环
for epoch in range(10):
for step, (data, label) in enumerate(train_dataset):
loss = train_step(model, data, label)
if step % 100 == 0:
print(f"Epoch: {epoch}, Step: {step}, Loss: {loss}")
```
### 分布式训练
```python
from mindspore import context
# 设置分布式模式
context.set_context(mode=context.GRAPH_MODE,
device_target="Ascend",
device_id=0)
# 初始化分布式环境
init("hccl")
# 设置并行策略
context.set_auto_parallel_context(
parallel_mode=context.ParallelMode.DATA_PARALLEL,
gradients_mean=True,
parallel_optimizer=True
)
# 模型训练(自动数据并行)
model.train(epoch=10, train_dataset=train_dataset,
callbacks=[LossMonitor()])
```
|
|
## 模型导出
### 导出MINDIR格式
```python
import mindspore as ms
# 设置为导出模式
context.set_context(mode=context.GRAPH_MODE)
# 加载Checkpoint
param_dict = ms.load_checkpoint("resnet50-10_100.ckpt")
ms.load_param_into_net(model, param_dict)
# 导出模型
input_data = ms.Tensor(np.random.rand(1, 3, 224, 224), ms.float32)
ms.export(model, input_data, file_name='resnet50',
file_format='MINDIR')
```
### 导出ONNX格式
```python
# 导出为ONNX格式
ms.export(model, input_data, file_name='resnet50',
file_format='ONNX')
```
### 导出AIR格式(Ascend)
```python
# 导出为AIR格式
ms.export(model, input_data, file_name='resnet50',
file_format='AIR')
```
### 格式对比
| 格式 | 说明 | 用途 |
|-----|------|------|
| MINDIR | MindSpore原生格式 | MindSpore推理 |
| ONNX | 开放格式 | 跨框架推理 |
| AIR | Ascend推理格式 | Ascend芯片加速 |
| GE | 图引擎格式 | 内部优化 |
### Checkpoint管理
```python
# 保存Checkpoint
ms.save_checkpoint(model, "resnet50.ckpt")
# 保存参数字典
param_dict = {}
for param in model.get_parameters():
param_dict[param.name] = param.data
ms.save_checkpoint(param_dict, "resnet50_dict.ckpt")
# 加载Checkpoint
param_dict = ms.load_checkpoint("resnet50.ckpt")
ms.load_param_into_net(model, param_dict)
# 仅加载部分参数
ms.load_param_into_net(model, param_dict, strict_load=False)
```
|
|
## 模型推理
### 加载模型进行推理
```python
import mindspore as ms
from mindspore import Tensor
import numpy as np
# 设置推理模式
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
# 加载模型
model = ResNet50(num_classes=10)
param_dict = ms.load_checkpoint("resnet50.ckpt")
ms.load_param_into_net(model, param_dict)
model.set_train(False) # 设置为评估模式
# 准备输入
image = np.random.rand(1, 3, 224, 224).astype(np.float32)
input_tensor = Tensor(image)
# 推理
output = model(input_tensor)
pred = output.asnumpy()
print(f"Prediction: {pred.argmax()}")
```
### 使用MindSpore Lite推理
```python
from mindspore_lite import LiteSession
# 创建Session
session = LiteSession()
session.run_context("resnet50.mindir")
# 设置输入
input_data = np.random.rand(1, 3, 224, 224).astype(np.float32)
inputs = session.get_inputs()
inputs[0].set_data(input_data)
# 执行推理
session.run_graph()
# 获取输出
outputs = session.get_outputs()
result = outputs[0].get_data()
```
### 批量推理
```python
def batch_inference(model, images, batch_size=32):
"""批量推理"""
results = []
for i in range(0, len(images), batch_size):
batch = images[i:i+batch_size]
batch_tensor = Tensor(batch, ms.float32)
output = model(batch_tensor)
pred = output.asnumpy()
results.extend(pred.argmax(axis=1))
return results
```
### 后处理
```python
def postprocess(output, top_k=5):
"""后处理:Top-K预测"""
prob = ms.ops.Softmax(axis=1)(output)
top_k_prob, top_k_idx = ms.ops.TopK(prob, top_k)
results = []
for i in range(top_k_prob.shape[0]):
results.append({
'top_k': top_k_idx[i].asnumpy().tolist(),
'probabilities': top_k_prob[i].asnumpy().tolist()
})
return results
```
### 模型评估
```python
from mindspore import Model
# 定义评估指标
metrics = {
'accuracy': nn.Accuracy(),
'top_5_accuracy': nn.TopKCategoricalAccuracy(k=5)
}
# 创建评估模型
eval_model = Model(model, metrics=metrics, loss_fn=None)
# 评估
result = eval_model.eval(eval_dataset)
print(f"Accuracy: {result['accuracy']:.4f}")
print(f"Top-5 Accuracy: {result['top_5_accuracy']:.4f}")
```
|
MindSpore官网
MindSpore文档
MindSpore GitHub
MindSpore教程
ResNet论文