跳转至

MindSpore动态图精度数据采集快速入门

概述

本文将展示如何在MindSpore动态图模式下使用msProbe工具进行精度数据采集。

环境准备

安装msProbe工具,详情请参见《msProbe工具安装指南》。

操作步骤

  1. 创建配置文件。

请在当前目录下创建一个名为config.json的配置文件,将配置内容拷贝到文件中。

{
    "task": "statistics",
    "dump_path": "./output",
    "rank": [],
    "step": ["0-2"],
    "level": "L1",
    "statistics": {
        "scope": [],
        "list": [],
        "data_mode": [
            "all"
        ],
        "summary_mode": "statistics"
    }
}

以上配置参数详细介绍和使用请参见《配置文件介绍》。

  1. 创建模型脚本。

在当前目录下创建一个Python脚本文件,例如alexnet_model.py,将如下代码拷贝到文件中。

import os
import numpy as np
import mindspore as ms
from mindspore import nn, ops
from mindspore import context, _device, set_deterministic
from mindspore import Tensor
from msprobe.mindspore import PrecisionDebugger, seed_all

# 设置随机种子以确保结果可重现
seed_all(seed=1234, mode=False, rm_dropout=True)

# 配置文件路径
script_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(script_dir, 'config.json')

# 初始化精度调试器
debugger = PrecisionDebugger(config_path=config_path)

# 设置MindSpore设备上下文
context.set_context(mode=ms.PYNATIVE_MODE)

context.set_context(device_target="Ascend", device_id=0)

set_deterministic(True)
print("Context set successfully. Please wait for the training task.")

# 定义卷积层
def conv_layer(in_channels, out_channels, kernel_size, stride=1, padding=0, pad_mode="valid", has_bias=True):
    return nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding,
                     has_bias=has_bias, pad_mode=pad_mode)

# 定义全连接层
def fc_layer(input_channels, out_channels, has_bias=True):
    return nn.Dense(input_channels, out_channels, has_bias=has_bias)


class AlexNet(nn.Cell):
    """
    AlexNet 模型定义

    参数:
    - num_classes: 分类数量
    - channel: 输入通道数(图像的颜色通道数)
    - phase: 模型运行阶段('train' 或 'test')
    - include_top: 是否包含全连接层的顶部(最后的分类层)
    """
    def __init__(self, num_classes=10, channel=3, phase='train', include_top=True):
        super(AlexNet, self).__init__()

        # 卷积层
        self.conv1 = conv_layer(channel, 64, 11, stride=4, pad_mode="same")
        self.conv2 = conv_layer(64, 128, 5, pad_mode="same")
        self.conv3 = conv_layer(128, 192, 3, pad_mode="same")
        self.conv4 = conv_layer(192, 256, 3, pad_mode="same")
        self.conv5 = conv_layer(256, 256, 3, pad_mode="same")

        # 激活函数和池化层
        self.relu = nn.ReLU()
        self.max_pool2d = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='valid')

        # 如果包括顶部(全连接层)
        self.include_top = include_top
        if self.include_top:
            self.flatten = nn.Flatten()
            self.fc1 = fc_layer(256 * 28 * 28, 4096)
            self.fc2 = fc_layer(4096, 4096)
            self.fc3 = fc_layer(4096, num_classes)

        # 数学操作
        self.add = ops.Add()
        self.mul = ops.Mul()

    def construct(self, x):
        """定义前向传播过程"""

        x = self.conv1(x)
        x = self.add(x, 0.1)    # 偏置加法
        x = self.mul(x, 2.0)    # 乘法操作
        x = self.relu(x)    # ReLU激活函数
        x = ops.celu(x) 
        x = x + 2

        # 打印每层输出形状,调试时可使用
        print(f"After Conv1: {x.shape}")

        x = self.max_pool2d(x)    # Max pooling 操作
        print(f"After MaxPool: {x.shape}")    # 打印池化后的形状

        x = self.conv2(x)
        x = self.relu(x)

        x = self.conv3(x)
        x = self.relu(x)

        x = self.conv4(x)
        x = self.relu(x)

        x = self.conv5(x)
        x = self.relu(x)

        # 打印卷积层后的形状,调试时使用
        print(f"After Conv5: {x.shape}")

        # 可选的全连接层部分
        if self.include_top:
            x = self.flatten(x)
            x = self.fc1(x)
            x = self.fc2(x)
            x = self.fc3(x)

        return x

# 前向函数
def forward_fn(data, label):
    out = net(data)
    loss = criterion(out, label)
    return loss

# 训练步骤
def train_step(data, label):
    loss, grads = grad_fn(data, label)
    optimizer(grads)
    return loss

# 测试模型
if __name__ == "__main__":
    net = AlexNet()
    optimizer = nn.SGD(net.trainable_params(), learning_rate=0.01)
    criterion = nn.MSELoss()

    grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters)

    # 生成数据和标签
    batch_size = 1
    num_classes = 10
    data = np.random.normal(1, 1, (batch_size, 3, 227, 227)).astype(np.float32)
    label = np.random.randint(0, num_classes, (batch_size,)).astype(np.float32)    # 注意此处类型应为float32

    # 转换为MindSpore张量
    data = Tensor(data)
    label = Tensor(label)

    steps = 5
    for i in range(steps):
        debugger.start(net)    # 启动调试器
        loss = train_step(data, label)    # 执行训练步骤
        print(f"Step {i}, Loss: {loss}")
        debugger.stop()    # 停止调试器
        debugger.step()    # 计数步数
  1. 运行训练脚本。

在命令行中执行如下命令:

python alexnet_model.py
  1. 查看采集结果。

执行训练命令后,工具会将模型训练过程中的精度数据采集下来。

日志中打印出现如下信息表示数据采集成功,即可手动停止模型训练查看采集数据。

****************************************************************************
*                        msprobe ends successfully.                        *
****************************************************************************
  1. 数据分析。

dump_path参数指定的路径下(本例中为./output),会出现如下目录结构,后续精度数据分析操作可使用msProbe工具的精度预检和精度比对等功能。

output/
└── step0
    └── proc{pid}
        ├── construct.json             # level为L0时,保存Cell的层级关系信息。当前场景为空
        ├── dump.json                  # 保存API前反向输入输出数据的统计量信息
        └── stack.json                 # 保存API的调用栈
    ......