关于mindspore
记录一些关于mindspore代码的东西。
算子调用流程
例如GPU算子Argmax,他的调用顺序是:
Argmax<-Primitive.Argmax<-ccsrc/backend/kernel_compiler/gpu/arrays/argmax_gpu_kernel.cc<-ccsrc/backend/kernel_compiler/gpu/cuda_impl/argmax_impl.cu
对于batchnorm这类操作,因为cudnn中有预先写好的,因此可以不用手动写GPU
impl。
batchnorm
batchnorm属实比较复杂,我看了一下ccsrc里面有4种batchnorm:[batchnorm,fused_batch_norm_ex,fused_batch_norm,batchnorm_fold,batchnorm_fold_2]。其中batchnorm_fold,batchnorm_fold_2是量化时使用的。batchnorm,fused_batch_norm_ex,fused_batch_norm是根据当前的运行模式决定的,如果是graph_mode执行P.FusedBatchNormEx进行训练,而测试时均用P.BatchNorm。
目前的问题是P.FusedBatchNormEx和P.BatchNorm的GPU后端都不支持2D输入。。但我看代码其实也不复杂,因为对于GPU后端其实都是调用的cudnn库,因此需要看看为何cudnn不支持2D输入,先看看pytorch的底层是怎么搞的。
pytorch的batchnorm实现
- 因为
pytorch时间久,因此aten/src/ATen/native/cudnn/BatchNorm.cpp中包含了很多版本适配。看起来比较复杂。 - 对于
2D的输入他默认的mode=CUDNN_BATCHNORM_PER_ACTIVATION,介绍里写的是bnScale, bnBias tensor dims are 1xCxHxWx.. (one value per CHW...-slice, normalized over N slice),然后:
TensorDescriptor idesc{ *input, 4 }; // input descriptor |
我认为他的想法应该是将2D输入扩展为4D然后调用cudnn的batchnorm。然后做了下测试,发现他们的梯度的确是相同的:
import torch
import torch.nn.modules as m
import numpy as np
n1 = m.BatchNorm1d(100).to('cuda')
n1.train(True)
x = torch.randn(32, 100, device='cuda', requires_grad=True)
y = torch.randn(32, 100, device='cuda', requires_grad=True)
criterion = m.MSELoss()
y_pred = n1(x)
loss = criterion(y_pred, y)
loss.backward()
xg_1 = x.grad.cpu().numpy().copy()
x.grad.zero_()
print(xg_1)
n2 = m.BatchNorm2d(100).to('cuda')
n2.train(True)
nx = torch.unsqueeze(torch.unsqueeze(x, -1), -1)
ny = torch.unsqueeze(torch.unsqueeze(y, -1), -1)
y_pred = n2(nx)
loss = criterion(y_pred, ny)
loss.backward()
xg_2 = x.grad.cpu().numpy().copy()
x.grad.zero_()
print(xg_2)
print(np.allclose(xg_1, xg_2))
编译代码
编译代码首先需要按官方配置设置docker,属实麻烦,因为需要下载很多依赖,必须得有vpn不然不行。
- 配置
docker使用主机的代理:我用的是vscode,因此在devcontainer中添加:
"runArgs": [ |
然后dockerfile添加代理地址,或者手动在终端设置:
RUN echo -e "\nexport https_proxy=http://127.0.0.1:8888\nexport http_proxy=http://127.0.0.1:8889" >> ~/.bashrc && source ~/.bashrc
- 开始编译,icu4j校验不匹配
我切换到0.7.0版本,然后./build.sh -e gpu -j 8,一开始构建很正常,到icu4j就奇怪了,这个包我下载了不下5次,然后看了一下mindspore的源码记录:https://gitee.com/mindspore/mindspore/commit/094bdbe253a328baee394922aeb54389ca07d563,发现他的md5写错了。。。按他的更新即可。
- 出现
No rule to make target '/usr/local/cuda/lib64/libcudnn.so', needed by 'mindspore/ccsrc/CMakeFiles/_c_expression.dir/cmake_device_link.o'. Stop.
这个原因是官方给的devel与release版的镜像配置不太一样,导致libcudnn.so没有在正确位置,执行:
ln -s /usr/lib/x86_64-linux-gnu/libcudnn.so.7.6.5 /usr/local/cuda/lib64/libcudnn.so
ln -s /usr/include/x86_64-linux-gnu/cudnn_v7.h /usr/local/cuda/include/cudnn.h