diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/constraints.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/constraints.md new file mode 100755 index 0000000000000000000000000000000000000000..92845a2d395ed8c797f7c5f9f1d68d5d8c5af5bd --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/constraints.md @@ -0,0 +1,141 @@ +# MSAadpter机制性约束 + +本文介绍MindSpore和PyTorch实现上的主要区别: + +1. 微分机制 +2. Dispatch机制 +3. Storage机制 +4. 静态编译机制 + +这些机制的不同,导致用户需要手动修改代码,或者部分功能暂时不支持。 + +## 微分机制 + +PyTorch 使用的是动态计算图,运算在代码执行时立即计算,正反向计算图在每次前向传播时动态构建。PyTorch微分为命令式反向微分,更符合面对对象编程的使用习惯。 + +MindSpore使用函数式自动微分的设计理念,提供更接近于数学语义的自动微分接口。MindSpore的微分可以简单理解为函数包装了一个模型,接口是一个函数,而PyTorch的接口是模型。 + +详情参考[MindSpore函数式微分](https://www.mindspore.cn/tutorials/zh-CN/master/beginner/autograd.html)。 + +由于两者底层设计的不同,MSAdapter不支持以下相关接口: + +- torch.Tensor.backward() +- torch.autograd.* + +部分相关接口PyTorch原始用法如下: + +```python +loss.backward() +``` + +```python +loss.backward(gradient_tensor) +``` + + +由于计算图的实现差异(包含命令式微分与函数式微分的差异),**反向计算以及正向计算需要用户手动进行如下修改**: + +原始PyTorch写法: + +```python +outputs = model(inputs) +loss = criterion(outputs, labels) +loss.backward() +``` + +MSAdapter修改后的写法: + +```python +import mindspore +def forward_fn(inputs, labels): + outputs = model(inputs) + loss = criterion(outputs, labels) + return loss +grad_fn = mindspore.value_and_grad(forward_fn, None, weights=model.trainable_params()) + +loss, grads = grad_fn(inputs, labels) +optimzer(grads) +``` + +## Dispatch机制 + +`torch.dispatch` 是 PyTorch 中用于拦截和自定义张量操作的机制。它允许开发者在张量运算被调用时插入自己的逻辑,无论是为了调试、性能优化,还是实现特定领域的功能增强。这个特性是在 PyTorch 1.7中引入的,并且为高级用户提供了强大的能力来扩展PyTorch的功能。 + +- Dispatch机制:当用户执行任何张量操作(例如加法、乘法等)时,实际上都是通过PyTorch的dispatch机制进行的。该机制决定了哪个具体实现(CPU、CUDA等)应该被执行。 +- torch.Tensor的子类化:通过创建一个继承自torch.Tensor的新类,并使用@torch_dispatch装饰器,用户可以自定义这些操作的行为。 + +当前MindSpore Storage机制在规划设计中,未来会支持。当前MSAdatper暂时不支持以下相关接口: + +1. torch.Tensor.to() +2. torch自定义算子涉及dispatch部分 + +**以上接口需要用户手动修改,参考[快速入门](quick_start.md#torchtensorto)。** + +## Storage机制 + +`torch.Storage` 是 PyTorch 中用于存储和管理张量数据的基础类。它是单一类型的数据连续存储区域,是构成 torch.Tensor 的底层组件。每个 Tensor 都有一个对应的 Storage,它实际保存了张量中的元素。 + +- 单一数据类型:一个 Storage 只能包含一种数据类型(例如 float、int 等)。这有助于优化内存使用和计算效率。 +- 连续存储:所有元素在 Storage 中都是按顺序连续存放的,这样有利于高效访问和操作。 +- 共享数据:多个 Tensor 可以共享同一个 Storage,这对于需要视图(view)或切片(slice)操作时特别有用,因为它们可以避免数据的重复拷贝。 + +由于MindSpore暂时不支持storage特性,MSAdapter不支持以下相关接口: + +1. torch.TypedStorage +2. torch.untypedStorage +3. torch序列化反序列化(ckpt保存加载,包括safetensors) + +部分相关接口PyTorch原始用法如下: + +```python +torch.save(x, 'tensor.pt') # 保存张量 +torch.save(model, 'full_model.pt') # 保存模型结构和参数 +torch.save(model.state_dict(), 'model_params.pt') # 仅保存参数(轻量级) +``` + +```python +x_loaded = torch.load('tensor.pt') # 加载张量 +model.load_state_dict(torch.load('model_params.pt')) # 加载参数 +``` + +**MSAdapter已经支持torch.load,使用MindSpore 2.7.0后,MSAdapter将支持torch.save相关功能。** + +## 静态编译机制 + +### TorchDynamo机制的介绍 + +PyTorch 在其发展历程中引入了多种机制以提升性能和开发者的体验,其中 TorchDynamo 是一项旨在通过非侵入式的方法捕获 PyTorch 程序的图表示(graph representation),以便于优化和加速执行的技术。它是在 PyTorch 2.0中引入的一项重要特性,致力于提供一种更加高效、灵活的方式来优化模型训练和推理过程。 + +- 无侵入式的图捕捉:TorchDynamo 能够在不修改用户代码的情况下自动捕捉 PyTorch 模型的计算图。这意味着开发者无需手动重写或注解他们的代码来利用图捕捉的好处。 +- 动态形状支持:与传统的静态图捕捉不同,TorchDynamo 支持动态形状,这使得它非常适合处理输入尺寸变化的任务,如自然语言处理(NLP)和图像处理等领域的应用。 +- 后端灵活性:TorchDynamo 不仅限于生成一种特定类型的图。它可以将捕捉到的图传递给不同的后端进行进一步优化和执行,例如 TOSA、TVM 和 NNC 等。 +- 性能优化:通过图捕捉和后续的优化步骤,TorchDynamo 可以显著提高模型的执行效率,减少内存使用,并加速训练和推理速度。 + +### MindSpore动静统一的编程介绍 + +传统AI框架主要有两种编程执行形态,静态图模式和动态图模式。 + +- 动态图模式,能有效解决静态图的编程门槛高问题,由于程序是按照代码的编写顺序执行,不做整图编译优化,相对性能优化空间较少,特别是面向DSA等专有硬件的优化具有较大挑战。 +- 静态图模式,能有效感知神经网络各层算子间的关系,基于编译技术进行有效的编译优化以提升性能。但传统静态图需要开发者感知构图接口,组建或调试网络比较复杂,且难于与常用Python库、自定义Python函数进行穿插使用。 + +MindSpore基于Python构建神经网络的图结构,相比于传统的静态图模式,能有更易用、更灵活的表达能力。MindSpore创新性的构建源码转换能力,基于Python语句提取AST进行计算图构建,因此可以支持开发者使用的Python原生语法(条件/循环等)和其他操作,如元组(Tuple)、列表(List)以及Lambda表达来构建计算图,并对计算图进行自动微分。所以MindSpore能更好地兼容动态图和静态图的编程接口,在代码层面保持一致,如控制流写法等。 + +原生Python表达可基于Python控制流关键字,直接使能静态图模式的执行,使得动静态图的编程统一性更高。同时开发者基于MindSpore的接口,可以灵活的对Python代码片段进行动静态图模式控制。即可以将程序局部函数以静态图模式执行(mindspore.jit)而同时其他函数按照动态图模式执行。从而使得在与常用Python库、自定义Python函数进行穿插执行使用时,开发者可以灵活指定函数片段进行静态图优化加速,而不牺牲穿插执行的编程易用性。 + +由于两者设计上的不同,MSAdapter不支持以下相关接口: + +1. torch.fx相关 +2. torch.dynamo +3. torch.compile + +部分相关接口PyTorch原始用法如下: + +```python +compiled_model = torch.compile(model) +``` + +```python +traced_model = torch.fx.symbolic_trace(model) # 使用 fx.symbolic_trace 追踪计算图 +``` + +**此类接口由于MindSpore与PyTorch底层实现不同,MSAdapter暂不支持。** diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/faq.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/faq.md new file mode 100755 index 0000000000000000000000000000000000000000..32cce9075d6bdc38f5389e97b109b8163e31b622 --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/faq.md @@ -0,0 +1 @@ +# FAQ \ No newline at end of file diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/compare.png b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/compare.png new file mode 100755 index 0000000000000000000000000000000000000000..d4b6ef8a436ae120635ac5978718b11df85c9703 Binary files /dev/null and b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/compare.png differ diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/image.png b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/image.png new file mode 100755 index 0000000000000000000000000000000000000000..53bfadb49620eff9c5d55c55648fba68b44b4182 Binary files /dev/null and b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/images/image.png differ diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/install.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/install.md new file mode 100755 index 0000000000000000000000000000000000000000..2df08aae952c6f50fae17fbe2f05113f469acc45 --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/install.md @@ -0,0 +1,36 @@ +# 安装 + +在昇腾NPU设备上,完成[昇腾固件](https://www.hiascend.com/document/detail/zh/canncommercial/80RC3/softwareinst/instg/instg_0003.html?Mode=PmIns&OS=Ubuntu&Software=cannToolKit)的安装后,执行以下步骤完成PyTorch、MindSpore和MSAdapter的安装: + +1. 安装PyTorch和MindSpore: + + ``` bash + pip install torch==2.1.0 + pip install mindspore + ``` + +2. 下载MSAdapter源码: + + ``` bash + git clone https://openi.pcl.ac.cn/Openl/MSAdapter + ``` + +3. 安装MSAdapter: + + 1. 如果用户希望直接使用源码,设置如下环境环境变量: + + ``` bash + export $PYTHONPATH=your_workspace/MSAdapter/mindtorch + ``` + + 其中,your_workspace是git clone下载的目录。此方法不会影响用户的PyTorch使用。 + + 2. 如果用户希望以Python安装包的形式使用,进入MSAdapter目录,进行如下操作: + + ```bash + pip install . + ``` + + 直接安装会覆盖原始PyTorch的使用,如果希望使用两者,可以考虑直接使用源码。 + +安装完成后,PyTorch的实际执行将替换为MSAdapter,后端则为MindSpore动态图模式。 \ No newline at end of file diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/intro.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/intro.md new file mode 100755 index 0000000000000000000000000000000000000000..a30a1c357507a529c1b8d61610321e31fcc22bc0 --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/intro.md @@ -0,0 +1,35 @@ +# MSAdapter使用文档 + +本文档为MSAdapter的使用文档说明,旨在帮助用户将PyTorch适配至MSAdapter,或者直接使用MSAdapter进行开发。 + +## MSAdapter介绍 + +MSAdapter是鹏城实验室开发的兼容PyTorch生态的兼容层。在不改变用户原有的使用习惯下,经过MSAdapter与MindSpore对昇腾平台的适配,现已支持在昇腾平台上使用PyTorch前端脚本在MindSpore后端上高效运行。 + +MSAdapter目前支持大部分PyTorch常用接口适配,参考[API文档](https://gitee.com/mindspore/docs/tree/master/docs/msadapter/docs/source_zh_cn/note)。用户代码可以在接口使用方式不变的情况下,基于MindSpore动态图模式,直接执行在昇腾算力平台上。可以在[PyTorch接口支持列表](https://gitee.com/mindspore/docs/blob/master/docs/msadapter/docs/source_zh_cn/note/pytorch_api_supporting_torch.md)中查看接口支持情况。 + +![](images/image.png) + +## MSAdapter能提供什么能力 + +- 与PyTorch相同的计算接口 +- 与PyTorch相同数据类型 +- 使用PyTorch checkpoint + +## MSAdapter使用核心与目标 + +用户安装MSAdapter之后,根据分析结果,修改少量代码/或不修改后,即可在NPU调用后端MindSpore运行。 + +用户在进行安装后,无缝运行MindSpore是我们的核心目的。目前复杂代码仍有一些限制,但功能会逐渐补齐。 + +## 使用流程 + +1. [安装](install.md) +2. [MSAdapter机制性约束](constraints.md) +3. 运行 + - 配置环境变量`export $PYTHONPATH=workspace/msadapter/mindtorch`后,运行与原始方式一致 +4. 报错与修改 + 1. 通过报错信息,判断是否为[MSAdapter机制性约束](constraints.md) + 2. 如果不是机制性约束,查看[API文档](https://gitee.com/mindspore/docs/tree/master/docs/msadapter/docs/source_zh_cn/note)进行修改 + 3. 重复步骤3(运行)和步骤4(报错与修改) + diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/llm.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/llm.md new file mode 100755 index 0000000000000000000000000000000000000000..6ed5619b0a8dee5da47db74a12aeba580fc4b503 --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/llm.md @@ -0,0 +1,6 @@ +# LLM适配与使用 + +如果希望基于MSAdapter开发大模型相关代码,参考以下两种方式: + +1. 直接使用MSAdapter进行LLM开发,请参考 [MindSpeed-LLM](https://gitee.com/ascend/MindSpeed-LLM)。 +2. 希望使用MSAdpter进行PyTorch的大模型适配,请参考 [Torch大模型适配指南-MSAdapter](../msadapter_compatibility/intro.md)。 \ No newline at end of file diff --git a/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/quick_start.md b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/quick_start.md new file mode 100755 index 0000000000000000000000000000000000000000..c5f9a0564e707102e50492b9949960419eda57a7 --- /dev/null +++ b/docs/msadapter/docs/source_zh_cn/msadapter_user_guide/quick_start.md @@ -0,0 +1,313 @@ +# 快速入门 + +本文将为用户提供快速指引,以一个MNIST手写数字识别任务的完整流程为例,说明如何使用MSAdatper。并将一个完整的PyTorch代码用例适配至MSAdapter。若用户想直接运行MSAdapter的例子,可参考[MSAdapter用例](#msadapter适配后代码)。 + +模型适配详细步骤如下: + +1. 导入依赖包 +2. 模型定义 +3. 参数解析 +4. 数据下载与预处理 +5. 模型构建 +6. 定义损失函数 +7. 训练 + - 前向计算 + - 反向微分计算 + +## PyTorch用例 + +以下为一个基础MNIST手写数字识别的PyTorch用例,步骤与上述相同。 + +```python +import argparse +import torch +import torch.nn as nn +import torch.optim as optim +from torch.utils.data import DataLoader +from torchvision import datasets, transforms + +class ToyModel(nn.Module): + def __init__(self): + super(ToyModel, self).__init__() + self.net1 = nn.Linear(784, 64) + self.relu = nn.ReLU() + self.net2 = nn.Linear(64, 10) + + def forward(self, x): + return self.net2(self.relu(self.net1(x))) + +def parse_args(): + parser = argparse.ArgumentParser(description="command line arguments") + parser.add_argument('--batch_size', type=int, default=64) + parser.add_argument('--epochs', type=int, default=10) + parser.add_argument('--learning_rate', type=float, default=0.0001) + return parser.parse_args() + +def data_process(inputs, labels): + inputs = inputs.view(inputs.size(0), -1) + return inputs, labels + +def main(): + # 获取传参 + args = parse_args() + transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.5,), (0.5,)) + ]) + train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) + # 加载数据集 + train_loader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True) + model = ToyModel().to('cuda') + # 定义损失函数 + criterion = nn.CrossEntropyLoss() + optimizer = optim.Adam(model.parameters(), lr=args.learning_rate) + step = 0 + + for epoch in range(args.epochs): + model.train() + for inputs, labels in train_loader: + inputs, labels = data_process(inputs, labels) + inputs, labels = inputs.to('cuda'), labels.to('cuda') + optimizer.zero_grad() + outputs = model(inputs) + loss = criterion(outputs, labels).to('cuda') + loss.backward() + optimizer.step() + # 添加每个step的打印,用户可自行修改 + print(type(loss)) + print(f"step == {step}") + step += 1 + +if __name__ == "__main__": + main() +``` + +## MSAdapter详细适配步骤 + +接下来,对应PyTorch的完整流程,说明如何使用MSAdapter完成相同的任务。 + +### 1. 导入依赖包 + +MSAdapter已经兼容PyTorch的各类子模块,无需修改。 + +```python +import torch +import torch.nn as nn +import torch.optim as optim +from torch.utils.data import DataLoader +from torchvision import datasets, transforms +``` + +### 2. 模型定义 + +MSAdapter已经兼容torch.nn.Module,无需修改。 + +```python +class ToyModel(nn.Module): + def __init__(self): + super(ToyModel, self).__init__() + self.net1 = nn.Linear(784, 64) + self.relu = nn.ReLU() + self.net2 = nn.Linear(64, 10) + def forward(self, x): + return self.net2(self.relu(self.net1(x))) +``` + +### 3. 参数解析 + +argparse是常规Python,与深度学习无关,无需修改。 + +### 4. 数据下载与预处理 + +MSAdapter已经兼容基础数据集相关接口,无需修改。 + +```python +def data_process(inputs, labels): + inputs = inputs.view(inputs.size(0), -1) + return inputs, labels + +# 预处理函数 +transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.5,), (0.5,)) +]) +train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) +# 加载数据集 +train_loader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True) +``` + +### 5. 模型构建 + +#### torch.nn.Module.to() + +MSAdapter在torch.nn.Module.to()调用上与PyTorch有差别。 + +```python +model = ToyModel().to('cuda') +``` + +由于MSAdapter暂时不支持torch.nn.Module.to接口,需要转换为如下方式,MSAdapter默认将模型放置于NPU上。 + +修改如下: + +```python +model = ToyModel() +``` + +### 6. 定义损失函数 + +MSAdapter的损失函数使用方式与PyTorch一致,无需修改。 + +```python +criterion = nn.CrossEntropyLoss() +optimizer = optim.Adam(model.parameters(), lr=args.learning_rate) +``` + +### 7. 训练 + +MSAdapter在torch.Tensor.to()、正向计算、反向微分计算的调用上与PyTorch有差别,需要修改代码。 + +```python +for epoch in range(args.epochs): + model.train() + for inputs, labels in train_loader: + inputs, labels = data_process(inputs, labels) + inputs, labels = inputs.to('cuda'), labels.to('cuda') # Tensor.to()问题 + optimizer.zero_grad() + outputs = model(inputs) # 前向调用不同 + loss = criterion(outputs, labels).to('cuda') # Tensor.to()问题 + loss.backward() # 反向调用不同 + optimizer.step() # 优化器调用不同 + step += 1 +``` + +#### torch.Tensor.to() + +与步骤5类似,由于MSAdapter暂时不支持torch.nn.Tensor.to接口,需要转换为如下方式。注意:MSAdapter默认将模型放置于NPU上。 + +```python +inputs, labels = inputs.to('cuda'), labels.to('cuda') +loss = criterion(outputs, labels).to('cuda') +``` + +修改如下: + +```python +# inputs, labels无需显示指定NPU +loss = criterion(outputs, labels) +``` + +#### 前向与反向计算 + +由于MSAdapter需要调用显式的计算图,除了修改代码,还需要导入MindSpore。 + +```python +outputs = model(inputs) # 前向调用不同 +loss = criterion(outputs, labels).to('cuda') # Tensor.to()问题不在此重述 +loss.backward() # 反向调用不同 +optimizer.step() +``` + +修改如下: + +先预定义增反向计算函数 + +```python +import mindspore +def forward_fn(inputs, labels): + outputs = model(inputs) + loss = criterion(outputs, labels) + return loss +grad_fn = mindspore.value_and_grad(forward_fn, None, weights=model.trainable_params()) +``` + +然后替换原始的PyTorch计算过程 + +```python +loss, grads = grad_fn(inputs, labels) +optimizer(grads) +``` + +### MSAdapter适配后代码 + +此处提供MSAdapter可运行的代码: + +```python +import argparse +import torch +import torch_npu +import torch.nn as nn +import torch.optim as optim +from torch.utils.data import DataLoader +from torchvision import datasets, transforms +import mindspore + +class ToyModel(nn.Module): + def __init__(self): + super(ToyModel, self).__init__() + self.net1 = nn.Linear(784, 64) + self.relu = nn.ReLU() + self.net2 = nn.Linear(64, 10) + + def forward(self, x): + return self.net2(self.relu(self.net1(x))) + +def parse_args(): + parser = argparse.ArgumentParser(description="command line arguments") + parser.add_argument('--batch_size', type=int, default=64) + parser.add_argument('--epochs', type=int, default=1) + parser.add_argument('--learning_rate', type=float, default=0.0001) + return parser.parse_args() + +def data_process(inputs, labels): + inputs = inputs.view(inputs.size(0), -1) + return inputs, labels + +def main(): + # 获取传参 + args = parse_args() + transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.5,), (0.5,)) + ]) + train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) + # 加载数据集 + train_loader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True) + # 将模型转移到NPU上 + model = ToyModel() + # 定义损失函数 + criterion = nn.CrossEntropyLoss() + optimizer = optim.Adam(model.parameters(), lr=args.learning_rate) + step = 0 + + def forward_fn(inputs, labels): + outputs = model(inputs) + loss = criterion(outputs, labels) + return loss + grad_fn = mindspore.value_and_grad(forward_fn, None, weights=model.trainable_params()) + + for epoch in range(args.epochs): + model.train() + for inputs, labels in train_loader: + # 数据预处理,将数据集的数据转成需要的shape + inputs, labels = data_process(inputs, labels) + + optimizer.zero_grad() + loss, grads = grad_fn(inputs, labels) + optimizer(grads) + + # 添加每个step的打印,用户可自行修改 + print(f"step == {step}") + step += 1 + +if __name__ == "__main__": + main() +``` + +## PyTorch与MSAdapter同用例代码对比 + +代码对比如下: + +![](images/compare.png) + +由于硬件不同的原因,两者实际的运行结果(如模型参数、loss等)会有出入。详情参考[跨硬件精度分析](../msadapter_compatibility/precision/computation.md)。 \ No newline at end of file