MindSpore安装
- 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 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 的**显式、函数式自动微分**哲学。
ResNet50实战
## 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论文