## 常见问题 **Q. 目前支持了哪些接口的功能呢?** A: 可以在[torch接口支持列表](SupportedList.md)和[TorchVision接口支持列表](TorchVision_SupportedList.md)中查看接口支持情况。 **Q:设置mindspore.set_context(mode=context.GRAPH_MODE)后运行出现类似问题:** > "Tensor.add\_" is an in-place operation and "x.add\_()" is not encouraged to use in MindSpore static graph mode. Please use "x = x.add()" or other API instead。 A:目前在设置GRAPH模式下不支持原地操作相关的接口,需要按照提示信息进行修改。需要注意的是,即使在动态图(PyNative)模式下,原地操作相关接口也是不鼓励使用的,因为目前在MindTorch不会带来内存收益,而且会给反向梯度计算带来不确定性。建议将原地操作接口替换成非原地操作接口。 **Q:运行代码出现mindtorch无某个接口的相关报错信息:** > AttributeError: module 'mindtorch.torch' has no attribute 'xxx'。 A:首先确定'xxx'是否为torch 1.12版本支持的接口,PyTorch官网明确已废弃或者即将废弃的接口和参数,MindTorch不会兼容支持,请使用其他同等功能的接口代替。如果是PyTorch对应版本支持,而MindTorch中暂时没有,欢迎参与[MindTorch项目](https://openi.pcl.ac.cn/OpenI/MSAdapter)贡献你的代码,也可以通过[创建任务(New issue)](https://openi.pcl.ac.cn/OpenI/MSAdapter/issues/new)反馈需求。 **Q:为什么TensorDataset返回值为`numpy.ndarray`类型?** A:为了加速数据处理流程以及避免在GPU/Ascend中SyncDeviceToHost失败,TensorDataset返回值会被转换为`numpy.ndarray`类型。如果您结合DataLoader使用则无需关注返回值类型,如果您单独调用该接口则需要手动将输出转换为Tensor类型。 ```python dataset = TensorDataset(all_input_ids) for data in dataset: data = torch.tensor(data) ``` **Q:`mindtorch.torch.__version__`对应版本是多少?具体怎么使用?** A:和MindTorch接口对标的策略相同,`mindtorch.torch.__version__`当前对应于`1.12.1`。使用方法上,在动态图(PyNative)模式下, 保持与PyTorch一样的使用方法及功能;在静态图(Graph)模式下,需要在图外(`@ms.jit`的作用域之外或者`nn.module.forward`之外)使用,才能保证功能的正确性。 **Q:静态图模式下不支持torch.dtype的is_floating_point/is_complex/is_signed方法?** ``` E # 1 In file testing/ut/pytorch/torch/test_dtype.py:15 E if x_dtype.is_floating_point: E ^ E E ---------------------------------------------------- E - C++ Call Stack: (For framework developers) E ---------------------------------------------------- E mindspore/ccsrc/pipeline/jit/ps/static_analysis/prim.cc:1590 GetEvaluatedValueForNameSpace ``` A:当前图模式下暂不支持取dtype属性方法,可以用以下写法替代: ```python from mindtorch.torch.common.dtype import all_float_type, all_signed_type, all_complex_type # Replace x_dtype.is_floating_point if x_dtype in all_float_type: ... # Replace x_dtype.is_signed if x_dtype in all_signed_type: ... # Replace x_dtype.is_complex if x_dtype in all_complex_type: ... ``` **Q: `torch.set_default_dtype`和`torch.set_default_tensor_type`设置的dtype类型会影响哪些接口的输出类型?** A:目前对函数式接口`arange`,`bartlett_window`, `empty`, `empty_strided`, `eye`, `full`, `hamming_window`, `hann_window`, `kaiser_window`, `linspace`, `logspace`, `ones`, `rand`, `randn`, `range`, `zeros`的结果类型会产生影响,以及使用这些接口的其他数据,例如,`nn.Conv2d`的weight;暂不支持对复数类型的影响。 **Q: 项目更名为MindTorch后,之前已迁移至MSAdapter的网络脚本,怎么快速地迁移到MindTorch上?** A:项目更名之后,使用上主要的改变,是从`import msadapter.pytorch`变更为`import mindtorch.torch`,以及从`import msadapter.torchvision`变更为`import mindtorch.torchvision`。对于该变更,在mindtorch/tools目录下,提供了replace_import_msadapter_to_mindtorch.sh自动化脚本,可以一键化地将相关的import从msadapter切换成mindtorch。 例如有目录文件 /mynet, 执行以下命令即可进行自动替换: ``` bash replace_import_msadapter_to_mindtorch.sh /mynet ``` **Q: 原始脚本中调用Apex相关接口实现混合精度报错,该怎么适配迁移到MindTorch上?** ``` from apex import amp model, optimizer = amp.initialize(model, optimizer, opt_level="O1") with amp.scale_loss(loss, optimizer) as scaled_loss: scaled_loss.backward() ``` A:Apex是基于PyTorch开发的混合精度训练加速库,未适配其他框架,如果用户想实现混合精度加速,可参考[使用混合精度加速训练](User_Guide_Mixed.md) 章节,调用`mindspore.amp.auto_mixed_precision`接口实现混合精度训练。 **Q: 接口迁移时报错没有某些关键字属性,出现类似报错信息:** > TypeError: mean() got an unexpected keyword argument 'keepdims' A:PyTorch部分接口的入参有别名的情况。如`mean`接口,用户指定`keepdim`与`keepdims`可以实现等价效果;`sort`接口,用户指定`dim`或`axis`均可以指定轴。针对这类场景当前需要用户修改使用PyTorch官方文档中呈现的关键字属性进行赋值。 **Q: 接口迁移时报错入参个数与位置参数个数不一致,出现类似报错信息:** > TypeError: addmm_() takes 3 positional arguments but 5 were given A:PyTorch新版本中存在一些接口和老版本的入参个数不一致的现象,如`add`, `addcmul`, `addmm`等接口,这类老版本的用法在新版本中已废弃。针对这类场景当前需要用户修改使用PyTorch官方文档(`1.12.1`版本)中呈现的用法。 **Q: 自定义Module执行时报错AttributeError:cells?** A:Module继承于mindspore.nn.Cell,有些方法名或属性名已被使用,因此在Module的子类中不能定义名为’cast’的方法,不能定义名为’phase’和’cells’的属性,否则会报错。如该报错示例,在自定义Module中重新定义了`cells`属性导致报错,用户在自定义子类中使用其他名字即可正常执行。 **Q:自定义Module执行时出现类似报错信息:** > TypeError: 'NoneType' object does not support item assignment A:请检查自定义Module中是否存在张量对象赋值为类属性的情况,如`self.xxx=torch.Tensor(xxx)`,请确保`super().__init__()`在此之前被调用。 **Q:当使用运行时自动替换导入模块,如何使能一些原生PyTorch的模块功能?** A:可以调用`from mindtorch.tools import pytorch_enable`接口临时使能原生PyTorch的模块功能,示例如下: ```python from mindtorch.tools import mstorch_enable import torch from mindtorch.tools import pytorch_enable import torch as pytorch from mindtorch.tools import mstorch_enable pytorch.xxx # 调用pytroch原生功能模块 torch.xxx # 调用mindtorch相应模块 ``` **Q:程序并未在`torch.cuda.set_device`指定的卡上执行?:** A:如[手动适配-3.1指定执行硬件](User_Guide_Adapter.md)所示,若mindtorch期望在特定后端(卡)上执行时,需通过`mindspore.set_context`接口显示指定设备,且暂不支持计算过程中在不同设备间转移Tensor。因此下列PyTorch接口的指定执行设备的功能均暂不生效: ``` torch.cuda.set_device(device) module.cuda(device) tensor.cuda(device) tensor.to(device) torch.set_default_device(device) ``` 如果期望实现异构执行功能,可调用`Primitive.set_device`接口实现,详情请参考[Host&Device异构](https://www.mindspore.cn/tutorials/experts/zh-CN/r2.3/parallel/host_device_training.html)。 **Q:`Generator`相关功能是否支持?:** A:由于框架随机数机制差异,当前暂不支持`Generator`相关功能,需删除`Generator`相关接口和参数调用。该功能已经在开发中,下个版本可支持,敬请期待! **Q:自定义算子是否支持自动迁移?:** A: 由于涉及硬件区别,目前自定义操作需适配Ascend硬件自定义算子方式,以及MindSpore自定义算子接入方式。请参阅[手动适配-4 自定义操作](User_Guide_Adapter.md)章节详细描述。 **Q:mindtorch 0.3版本之前如何加载PyTorch的权重文件?:** A: 分为两种场景: - 场景一: 若执行环境有PyTorch库可直接加载pth。 - 场景二: 如果最终执行环境无法安装PyTorch库,可参考则需要借助其他已安装PyTorch的环境上进行离线模型转换。可参考下图流程将PyTorch权重加载至MindTorch迁移模型中: ![pth_trans](pic/pth_trans.png) 首先在同时安装有PyTorch和MindTorch的环境上执行离线模型转换: ```python import mindtorch.torch as torch ... net.load_state_dict(torch.load('pytorch.pth')) torch.save(net.state_dict(), 'mindtorch.pth') ``` 保存MindTorch对应的pth文件后,可在最终执行环境中加载: ```python import mindtorch.torch as torch ... net.load_state_dict(torch.load('mindtorch.pth')) ``` **Q:两个Tensor配置同一个Storage对象,修改其中一个后,另一个并未同步修改?:** A: 由于张量存储机制差异,张量/Storage/共享Storage的张量之间并不真实共享存储区,当前通过Storage和张量对象之间建立一一映射关系,来模拟原地修改操作,当对其中一个对象数据进行修改时同步更新映射对象。Storage仅保留对最新相关的张量的映射,所以无法做到一个张量修改,另一个也同时被修改。 如下示例,注意下面用例中Storage与张量之间的映射关系: ```python from mindtorch.tools import mstorch_enable import torch import numpy as np a = torch.tensor(np.array([1., 2., 3.])) storage1 = a.storage() # 此时张量a和storage1相互映射: # 1) 若原地修改storage1,张量a的取值也被更新; storage1[2] = 2 assert storage1[2] == a[2] == 2 # 2) 若原地修改张量a,storage1的取值也被更新; a[2] = 4 a.numpy() #更新后调用a.numpy()或打印等同步操作,确保数据完成同步; assert storage1[2] == a[2] == 4 b = torch.tensor([], dtype=storage1.dtype) b.set_(storage1) # 此时张量a和storage1不再相互映射, 张量b和storage1相互映射: # 1) 若原地修改storage1,张量b的取值也被更新,但a的取值不会更新; storage1[2] = 5 assert storage1[2] == b[2] == 5 assert a[2] == 4 # 2) 若原地修改张量b,storage1的取值也被更新,但a的取值不会更新; b[2] = 6 b.numpy() #更新后调用a.numpy()或打印等同步操作,确保数据完成同步; assert storage1[2] == b[2] == 6 assert a[2] == 4 # 3) 若原地修改张量a,则storage1和b的取值不会更新; a[2] == 7 assert storage1[2] == b[2] == 6 # 若期望a的数据也更新为storage1,可手动调用set_方式更新,此时张量a和storage1相互映射, 张量b和storage1不再相互映射:: a.set_(storage1) assert storage1[2] == a[2] == b[2] == 6 ``` **Q:切片等场景不支持numpy数组作为入参?:** A: PyTorch数据存储和numpy数组一致,所以有些场景下可能出现两个库接口相互调用的情况,但MindSpore张量和numpy数组并不共享数据存储,所以在调用numpy接口前需要先调用`Tensor.numpy()`接口,将张量转换为 ndarray后再调用numpy接口。同理,在调用MindTorch接口前需要先把ndarray类型数组转换为接口官方支持的类型或张量。如: ``` >>> import torch >>> import numpy as np >>> import mindtorch.torch as mstorch >>> a = np.array([1,2]) >>> b = torch.Tensor(3,4) >>> b[:,a] tensor([[ 3.0845e-41, -2.0170e-23], [ 3.0845e-41, 9.1084e-44], [ 3.0845e-41, -1.6864e-23]]) >>> c = mstorch.Tensor(3,4) >>> c[:,a] # 直接传入ndarray类型数组会报错 TypeError: For tuple index, the types only support 'Slice', 'Ellipsis', 'None', 'Tensor', 'int', 'List', 'Tuple', 'bool', but got type 'Array', value: [1 2] >>> c[:,list(a)] # ndarray类型数组转换为list后可正常执行 Tensor(shape=[3, 2], dtype=Float32, value= [[ 0.00000000e+00, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00]]) ``` **Q:报错不支持``类型的入参?:** A: 当切片或创建Tensor时,传入Python的range对象可能报以下错误: ``` >>> import mindtorch.torch as mstorch >>> mstorch.Tensor(range(10)) # 传入range对象会报错 TypeError: For Tensor, data must be a sequence, got >>> mstorch.Tensor(list(range(10))) # 转为list类型后可正常执行 Tensor(shape=[10], dtype=Float32, value= [ 0.00000000e+00, 1.00000000e+00, 2.00000000e+00, 3.00000000e+00, 4.00000000e+00, 5.00000000e+00, 6.00000000e+00, 7.00000000e+00, 8.00000000e+00, 9.00000000e+00]) ``` **Q:Scalar张量和高维张量运算后数据类型与PyTorch不一致?:** A: 如下用例所示,PyTorch中Scalar张量和高维张量运算后数据类型以高维张量数据类型为准。由于机制差异,MindTorch中Scalar张量和高维张量运算后数据类型向上转换: ``` >>> import torch >>> import mindtorch.torch as mstorch >>> a = torch.tensor(1).to(torch.float32) >>> b = torch.tensor([2., 3.]).to(torch.float16) >>> a + b tensor([3., 4.], dtype=torch.float16) >>> c = mstorch.tensor(1).to(mstorch.float32) >>> d = mstorch.tensor([2., 3.]).to(mstorch.float16) >>> c + d Tensor(shape=[2], dtype=Float32, value= [ 3.00000000e+00, 4.00000000e+00]) ``` **Q: 接口报错不支持list入参类型:** A:PyTorch部分接口的入参在官网中显示只支持tuple类型,但实际部分场景用户传入list也能正常处理。针对这类隐藏用法,MindTorch已识别并适配部分接口,但可能存在遗漏情况,用户可自行转换成tuple后传入,或通过issue反馈给我们。