diff --git "a/docs/zh/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225.md" "b/docs/zh/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225.md" deleted file mode 100644 index b2c94fdbf2bd3ab187a2d717a8d16a32b34b2dc2..0000000000000000000000000000000000000000 --- "a/docs/zh/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225/PyTorch API\346\224\257\346\214\201\346\270\205\345\215\225.md" +++ /dev/null @@ -1,8229 +0,0 @@ -# PyTorch API支持清单 -- [Tensors](#Tensorsmd) -- [Generators](#Generatorsmd) -- [Random sampling](#Random-samplingmd) -- [Serialization](#Serializationmd) -- [Math operations](#Math-operationsmd) -- [Utilities](#Utilitiesmd) -- [Other](#Othermd) -- [torch.Tensor](#torch-Tensormd) -- [Layers \(torch.nn\)](#Layers-torch-nnmd) -- [Functions\(torch.nn.functional\)](#Functionstorch-nn-functionalmd) -- [torch.distributed](#torch-distributedmd) -- [NPU和CUDA功能对齐](#NPU和CUDA功能对齐md) -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -- | -
---|---|---|---|
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
- | -- | -- | -- | -
详情请参见模型选取。
+- | -- | -
---|---|
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
---|---|
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- - | -
- | -- | -- | -
---|---|---|
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- | -- | -- | -
- - | -- - | -- | -
- | -- | -- | -
- | -- | -
---|---|
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
- | -- | -
---|---|
- | -- | -
- | -- | -
- | -- | -
- | -- | -
+ | ++ | +
---|---|
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
---|---|
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ | +
+ | ++ + | +
+ | ++ | ++ | +
---|---|---|
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ | ++ | ++ | +
+ + | ++ + | ++ | +
+ | ++ | ++ | +
+
+
混合精度-3. 设置CPU为performance模式。 +**概述** - ``` - cpupower frequency-set -g performance - ``` +基于NPU芯片的架构特性,会涉及到混合精度训练,即混合使用float16和float32数据类型的应用场景。使用float16代替float32有如下好处: -4. 再次执行[步骤1](#li158435131344)查看当前CPU模式是否已设置为performance模式。 +- 对于中间变量的内存占用更少,节省内存的使用。 +- 因内存使用会减少,所以数据传出的时间也会相应减少。 +- float16的计算单元可以提供更快的计算性能。 -修改CPU性能模式(ARM服务器)+但是,混合精度训练受限于float16表达的精度范围,单纯将float32转换成float16会影响训练收敛情况,为了保证部分计算使用float16来进行加速的同时能保证训练收敛,这里采用混合精度模块Apex来达到以上效果。混合精度模块Apex是一个集优化性能、精度收敛于一身的综合优化库。 -**设置电源策略为高性能模式** +适配昇腾AI处理器的混合精度模块Apex除了上述优点外,还能提升运算性能。具体如下: -在某些对Host侧CPU要求较高的模型中,例如目标检测类模型,需要进行较为复杂的图像预处理,开启电源高性能模式能一定程度上提高性能和稳定性。ARM服务器提升网络性能需要在BIOS设置中将电源策略设为高性能模式,具体操作如下。 +- Apex在混合精度运算过程中,会对模型的grad进行运算。开启combine\_grad开关,可以加速这些运算。具体为将amp.initialize\(\)接口参数combine\_grad设置为True; +- 适配后的Apex针对adadelta/adam/sgd/lamb做了昇腾AI处理器亲和性优化,得到的NPU融合优化器与原生算法保持一致,但运算速度更快。使用时只需将原有优化器替换为apex.optimizers.\*(“\*”为优化器名称,例如NpuFusedSGD)。 -1. 登录ibmc界面,启动虚拟控制台,远程控制选择HTML5集成远程控制台,如[图1](#fig15869135420288)。 +**特性支持** - **图 1** 远程登录控制台 -  +混合精度模块功能和优化描述如[表1](#table10717173813332)所示。 -2. 在虚拟界面工具栏中,单击启动项工具,弹出启动项配置界面,如[图2](#fig744814574243)。 +**表 1** 混合精度模块功能 - **图 2** 启动项工具 -  + +
安装高性能pillow库(X86服务器)+ ``` + model, optimizer = amp.initialize(model, optimizer,combine_grad=True) + ``` -1. 安装高性能pillow库相关依赖,命令如下。 +3. 标记反向传播.backward\(\)发生的位置,这样Amp就可以进行Loss Scaling并清除每次迭代的状态,代码如下: - ubuntu/debian: + 原始代码: ``` - apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python3-tk libharfbuzz-dev libfribidi-dev libxcb1-dev + loss = criterion(…) + loss.backward() + optimizer.step() ``` - centos/bclinux/euler: + 修改以支持loss scaling后的代码: ``` - yum install libtiff-devel libjpeg-devel openjpeg2-devel zlib-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel harfbuzz-devel fribidi-devel libraqm-devel libimagequant-devel libxcb-devel + loss = criterion(…) + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() ``` -2. 安装高性能pillow库。 - 1. 执行如下命令卸载原生pillow。 - - ``` - pip3.7 uninstall -y pillow - ``` - 2. 安装SSE4版本pillow-simd。 +模型训练- 使用root用户安装,执行如下命令,若使用非root用户安装,需在命令结尾加上--user。 +训练脚本迁移完成后,需要参见[配置环境变量](#zh-cn_topic_0000001144082004md)设置环境变量,然后执行**python3** _xxx_进行模型训练。具体样例请参考[脚本执行](#脚本执行md)。 - ``` - pip3.7 install pillow-simd - ``` +> **说明:** +>执行“python3 xxx“命令时,须将python3软链接到与当前pytorch适配版本的python安装路径。 - > **说明:** - >如果CPU支持AVX2指令集,可安装AVX2版本pillow-simd,命令如下: - >``` - >CC="cc -mavx2" pip3.7 install -U --force-reinstall pillow-simd - >``` +性能调优和分析-3. 修改torchvision代码解决pillow-simd缺少PILLOW\_VERSION问题。torchvision安装参见[样例获取](#样例获取md)。 +前提条件- 将/usr/local/python3.x.x/lib/python3.x/site-packages/torchvision/transforms/functional.py第5行代码修改如下: +1. 参见[样例说明](#样例说明md)改造开源代码,使模型能够正常运行,包括数据预处理,前向计算,loss计算,混合精度,反向计算,参数更新等。 +2. 模型迁移阶段优先关注模型是否能跑通,现有算子是否能满足,如果遇到不满足的算子需参见《PyTorch算子开发指南》进行算子适配开发。 +3. 优先打通单卡功能,再打通多卡功能。 - ``` - try: - from PIL import Image, ImageOps, ImageEnhance,PILLOW_VERSION - except: - from PIL import Image, ImageOps, ImageEnhance - PILLOW_VERSION="7.0.0" - ``` +调测过程+- **[总体思路](#总体思路md)** -(可选)安装指定版本OpenCV库+- **[采集训练过程相关数据](#采集训练过程相关数据md)** -如模型依赖OpenCV,基于训练性能考虑,建议安装OpenCV-3.4.10版本。 +- **[host侧性能优化](#host侧性能优化md)** -1. 获取源码:[获取地址](https://opencv.org/releases/)。 -2. 安装指导:[获取地址](https://docs.opencv.org/3.4.10/d7/d9f/tutorial_linux_install.html)。 +- **[训练过程性能优化](#训练过程性能优化md)** -训练过程性能优化-**算子瓶颈优化** +总体思路-1. 获取训练过程中的Profiling数据,参见[Profiling数据采集](#采集训练过程相关数据md)。 -2. 分析Profiling数据,得到耗时较大的算子。 -3. 参见[单算子样例编写说明](#单算子样例编写说明md)构建耗时较大算子的单算子样例,通过与CPU或GPU运行单算子样例时间进行对比,若发现性能不足,则有以下两种方案解决。 - - 规避方案:使用同等语义其他高效算子替代。 - - 解决方案:改进算子性能。 +1. 通过训练执行结果,判断吞吐量指标是否达到预期要求。 +2. 当吞吐量指标不达标时,需要找出制约性能瓶颈的原因,主要为以下几个方面: + - 算子瓶颈,在某个算子上执行过慢。 + - copy瓶颈,非连续转连续时进行copy带来的瓶颈。 + - 框架瓶颈,由于算子格式转换带来了额外操作。 + - 编译瓶颈,由于shape或属性来回变化造成反复编译。 -**copy瓶颈优化** +3. 针对以上制约性能瓶颈的原因进行分析与优化。 -1. 获取训练过程中的Profiling数据,参见[Profiling数据采集](#采集训练过程相关数据md)。 -2. 分析Profiling数据分析整网中的D2DCopywithStreamSynchronize/PTCopy/format\_contiguous的耗时。 -3. 若发现耗时较大,则需参照以下两种方案解决。 - - 方案一:(规避方案)PyTorch中View类型框架类算子会导致非连续转连续操作。优化思路为尽量使用计算类算子代替View类框架算子,常见的View类框架算子如View、Permute、Transpose等。更多View类框架算子可参考[https://pytorch.org/docs/stable/tensor\_view.html](https://pytorch.org/docs/stable/tensor_view.html)。 - - 方案二:(解决方案)加速转连续操作。 +采集训练过程相关数据-**框架瓶颈优化** +**Profiling数据采集** -1. 获取训练过程中算子信息OP\_INFO,参见[获取算子信息OP\_INFO](#采集训练过程相关数据md)。 -2. 分析OP\_INFO中算子的规格和调用关系,定位是否插入了多余的算子,重点关注transdata是否合理。 -3. 优化方案:通过指定部分算子初始化格式,对多余的格式转换算子进行消除。 -4. 在pytorch/torch/nn/modules/module.py中,在cast\_weight中指定算子初始化格式,如下图。 +当模型训练过程中吞吐量指标不达标时,可以通过采集训练过程中的profiling数据,分析哪个环节、哪个算子导致的性能消耗。Profiling数据采集分为PyTorch层面和CANN层面的采集,PyTorch层面采集的是PyTorch API的数据,CANN层面采集的是TBE算子的数据。 -  +请参见以下方式进行profiling数据的获取,并根据实际情况选择需要的数据采集方式。 - 格式设置原则可参考如下规则: +- PyTorch层面Profiling数据采集。 + 1. 获取chrome\_trace文件。 - - Conv2D相关:Weight 可设置为FZ格式,如第424行。 - - Linear相关的参数,可设置为NZ格式,如第409行。 + 使用profile接口对原始代码的loss计算和优化过程进行改造。 -**编译瓶颈优化** + ``` + # 使用ascend-pytorch适配的profile接口,即可获得,推荐只运行一个step + with torch.autograd.profiler.profile(use_npu=True) as prof: + out = model(input_tensor) + loss=loss_func(out) + loss.backward() + optimizer.zero_grad() + optimizer.step() + # 打印profiler结果信息 + print(prof) + # 导出chrome_trace文件到指定路径 + output_path = '/home/HwHiAiUser/profile_data.json' + prof.export_chrome_trace(output_path) + ``` -1. 获取训练过程中算子信息OP\_INFO,参见[获取算子信息OP\_INFO](#采集训练过程相关数据md)。 -2. 查看INFO日志,观察第一个step以后的aclopCompile::aclOp关键字,如果后续接了Match op inputs/type failed或To compile op则说明该算子存在动态编译,需要优化。 -3. 需参照以下两种方案解决。 - - 规避方案:在理解模型语义和相关API基础上,使用固定Shape的方式代替动态Shape。 - - 解决方案:减少编译或不需要编译该算子。 - - 优化算子编译配置请参见[编译选项设置](#编译选项设置md)。 + 2. 运行成功后会打印出profiler结果信息。 + 打印结果包含CPU和NPU的耗时等相关信息,详细信息参见表2 。 + + **表2** profiler结果字段表 + + | Name | Self CPU % | Self CPU | CPU total % | CPU total | CPU time avg | Self NPU % | Self NPU | NPU total | NPU time avg | # of Calls | + | ---- | ---------- | -------- | ----------- | --------- | ------------ | ---------- | -------- | --------- | ------------ | :--------: | + + 3. 查看chrome\_trace文件。 -亲和库+ chrome\_trace文件可以通过以下方式打开查看:在Chrome浏览器 中输入“chrome://tracing“地址,然后将落盘文件拖到空白处即可打开文件内容,通过键盘W、A、S、D键,可以对profiler的结果进行缩放和移动。 + 4. profiler其他功能。 + - 获取算子输入tensor的shape信息。 -来源介绍+ ```python + # 添加record_shapes参数,获取算子输入tensor的shape信息 + with torch.autograd.profiler.profile(use_npu=True, record_shapes=True) as prof: + # 添加模型计算过程 + print(prof) + ``` -针对公版模型中常见的网络结构和函数,我们针对性地对其进行了优化,使得运算性能大幅度提升,同时,将其集成到Pytorch框架中,便于模型性能调优中使用。 + 打印结果中增加了每个算子的`Input Shape`信息。 -功能介绍+ - 获取使用NPU的内存信息。 - -
精度调测+ > **说明:** + > + >该功能仅支持PyTorch1.8版本以上。 + - 获取简洁的算子性能信息。 -前提条件+ 该功能只打印每个算子栈最底层的算子信息,使分析结果更简洁。 -优先在同等语义和超参下,跑一定的epoch(推荐完整epoch数的20%),使精度,loss等对齐GPU相应水平,完成后再对齐最终精度。 + ```python + # 添加use_npu_simple参数,获取简洁的算子信息 + with torch.autograd.profiler.profile(use_npu=True, use_npu_simple=True) as prof: + # 添加模型计算过程 + # 导出chrome_trace文件到指定路径 + output_path = '/home/HwHiAiUser/profile_data.json' + prof.export_chrome_trace(output_path) + ``` -调测过程+ 在Chrome浏览器中打开chrome\_trace结果文件,可查看简洁的算子性能信息。 -- **[总体思路](#总体思路-4md)** +- CANN层面Profiling数据采集。 -- **[精度调优方法](#精度调优方法md)** + 1. 获取性能数据文件。 + ``` + profiler_result_path = "/home/profiling_data" # profiling 数据保存的文件夹,需提前手动创建,请根据实际指定。 + with torch.npu.profile(profiler_result_path): + out = model(input_tensor) + loss=loss_func(out,target) + loss.backward() + optimizer.zero_grad() + optimizer.step() + ``` -总体思路+ > **说明:** + >获取性能数据文件时,model、input\_tensor、target需要下发到npu上。 -精度问题排查需要找出是哪一步出现的问题,主要以下几个方面: + 2. 解析性能数据文件。 -1. 模型网络计算错误。 - - 定位思路:在网络中加入hook进行排查判断是哪个地方有较大嫌疑,然后构建[单算子用例](#单算子样例编写说明md)逐渐缩小错误范围,证明该算子在当前网络场景下计算有误,可以对比CPU或GPU结果证明。 + 请参见《CANN 开发辅助工具指南》中“Profiling工具使用指南(训练)”章节。 - - 规避方案:使用同等语义其他算子替代。 - - 解决方案:改进算子精度或功能问题。 -2. loss计算错误。 - - 定位思路:由于Loss的特殊性和可以自定义,在判断Loss计算错误后建议dump网络中的loss的输入来测试而非随机同shape tensor,这样才能更好地复现证明。 +**获取算子信息OP\_INFO** - - 规避方案:使用同等语义其他算子替代。 +网络模型最终是以OP执行的,通过OPInfo日志,我们可以获取实际执行时的算子及其属性。通过get\_ascend\_op\_info.py脚本获取。 - - 解决方案:改进算子精度或功能问题(loss也是由算子构成)。 +1. 编写get\_ascend\_op\_info.py脚本获取算子信息,脚本内容如下。 -3. 参数更新错误。 + ``` + # -*- coding: utf-8 -*- + """用于导出OPINFO + """ + import os + import sys + import argparse + + def func(host_log_folder): + """ + :param host_log_folder: where host_log_folder addr is. + :return: + """ + host_log_files = os.listdir(host_log_folder) + result = {} + + for host_log in host_log_files: + if not host_log.endswith('.log') or host_log.endswith('.out'): + continue + with open(os.path.join(host_log_folder, host_log), 'r')as f: + host_log_lines = f.readlines() + for line in host_log_lines: + if line.startswith('[INFO] ASCENDCL') and "aclopCompile::aclOp" in line: + op_info = line.split('OpType: ')[1][:-2] + op_type = op_info.split(',')[0] + op_param = op_info[len(op_type) + 2:] + if op_type not in result.keys(): + result[op_type] = [op_param] + else: + result[op_type].append(op_param) + + with open('ascend_op_info_summary.txt', 'w')as f: + for k, v in result.items(): + v_set = set(v) + for info in v_set: + f.write(k + " " + info + "\n") + + if __name__ == "__main__": + parser = argparse.ArgumentParser(description='trans the log') + parser.add_argument('--host_log_folder', default="./", + help="input the dir name, trans the current dir with default") + ags = parser.parse_args() + func(ags.host_log_folder) + ``` - - 定位思路:在每个optim.step\(\)前对网络中的参数逐个打印其grad进行排查判断是哪个地方有较大嫌疑,然后构建单算子用例逐渐缩小错误范围,证明该算子在当前网络场景下梯度计算有误,可以对比CPU或GPU结果证明。该项优先级应低于[1.](#li17755175510322)与[2.](#li25281726103316),因为1与2的错误同样可以造成grad异常。 +2. 设置环境变量,将host日志打屏。 - - 规避方案:使用同等语义其他算子替代。 + ``` + export ASCEND_SLOG_PRINT_TO_STDOUT=1 + ``` + +3. 设置日志级别为info,参考《CANN 日志参考》设置日志级别。 +4. 执行训练脚本,进行模型训练,训练完成后获取host侧日志,默认位置为$HOME/ascend/log/plog目录下,$HOME表示Host侧用户根目录。 +5. 解析host侧日志会在当前目录下得到OPInfo信息ascend\_op\_info\_summary.txt。 + + ``` + python3 get_ascend_op_info.py --host_log_folder $HOME/ascend/log/plog + ``` - - 解决方案:改进计算grad的算子精度或功能问题。 +6. 分析TaskInfo中额外的task,尤其关注transdata。 -4. 多卡计算错误。 +host侧性能优化- - 定位思路:在保证单卡精度OK的前提下,稳定复现多卡不收敛。 +- **[概述](#概述-0md)** - - 解决方案:建议联系华为方支撑人员,提供稳定复现的单P和多P脚本。 +- **[修改CPU性能模式(X86服务器)](#修改CPU性能模式X86服务器md)** +- **[修改CPU性能模式(ARM服务器)](#修改CPU性能模式ARM服务器md)** +- **[安装高性能pillow库(X86服务器)](#安装高性能pillow库X86服务器md)** -精度调优方法+- **[(可选)安装指定版本OpenCV库](#可选安装指定版本OpenCV库md)** -模型出现精度问题一般有:因算子溢出导致的训练loss不收敛或者精度不达标问题,整个网络训练引起的性能不达标问题。用户可通过单算子溢出检测和整网调测适度解决模型精度不达标问题。 -- **[单算子溢出检测](#单算子溢出检测md)** +概述-- **[整网调测](#整网调测md)** +在进行PyTorch模型迁移训练时,部分网络模型会出现FPS较低、性能不达标的情况。可以考虑对服务器进行以下优化尝试提高训练性能。 +- 修改CPU性能模式。 +- 安装高性能pillow库。 +- (可选)安装指定版本OpenCV库。 -单算子溢出检测+修改CPU性能模式(X86服务器)-用户通过算子溢出检测功能检测算子是否有溢出,然后采集溢出算子的数据,从而帮助开发人员快速定位并解决算子精度问题。 +**设置电源策略为高性能模式** -约束说明: +提升网络性能需要在X86服务器BIOS设置中将电源策略设为高性能模式,具体操作如下。 -- 需要安装hdf5工具以支持算子dump功能,安装详情请参见[编译安装hdf5](#编译安装hdf5md)。 -- 本功能只提供IR级别的算子溢出检测,且只支持AICORE,不支持Atomic。 -- 须在PyTorch源代码“build.sh“文件中添加“USE\_DUMP=1”字段。 +1. 登录iBMC界面,启动虚拟控制台,远程控制选择HTML5集成远程控制台,如[图1](#fig15869135420288)。 - ``` - 修改前: DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 python3 setup.py build bdist_wheel - 修改后: DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 USE_DUMP=1 python3 setup.py build - ``` + **图 1** 远程登录控制台 +  - 并参见《PyTorch安装指南》的“手动编译安装”章节重新编译并安装PyTorch。 +2. 在虚拟界面工具栏中,单击启动项工具,弹出启动项配置界面,如[图2](#fig744814574243)。 -- 使用单算子溢出检测功能时,请不要同时开启apex的动态loss scale模式和使用tensor融合功能。 + **图 2** 启动项工具 +  -采集溢出算子数据: +3. 在启动项配置界面选择,选择“BIOS设置”,然后在虚拟界面工具栏中单击重启工具,重启服务器。 +4. 系统重启后进入BIOS配置界面,依次选择“Advanced”\>“Socket Configuration”,如[图3](#fig4546303814)所示。 -``` -# check_overflow为溢出检测控制开关 -# dump_path为dump文件保存路径 -with torch.utils.dumper(check_overflow=check_overflow, dump_path=dump_path, load_file_path='') as dump: - # 需要检测算子溢出的代码片段 -``` + **图 3** Socket Configuration +  -运行一个step,模型运行过程中,如果有算子溢出,会打印出相应IR的名字。 +5. 进入Advanced Power Mgmt. Configuration,设置Power Policy为Performance。如[图4](#fig15501111014442)。 -查看Dump数据: + **图 4** 设置电源策略 +  -如果训练过程中采集到了Dump数据,则会在\{dump\_path\}路径下生成dump数据的.h5文件,用户可进入路径自行查看。 +6. 按下“F10”保存配置并重启服务器。 -解决方法: +**将CPU设置为performance模式** -1. 将采集到的.h5文件映射到TBE算子,映射方法请参见[IR与TBE算子映射](#IR与TBE算子映射)。 +请使用root用户执行如下操作。 -2. 请将算子溢出的打印截图及映射后的TBE算子输入输出文件通过Issue附件形式反馈给华为开发人员。 +1. 使用如下命令查看当前CPU模式。 -**IR与TBE算子映射** + ``` + cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + ``` -前提条件: + 执行以上命令会输出当前CPU模式,CPU模式说明请参见[表1](#table354392019384)。如果当前CPU模式不是performance模式,请执行以下操作设置CPU为performance模式。否则请跳过以下步骤。 -- 开启PyTorch框架dump功能。 + **表 1** CPU模式 - 在PyTorch源代码 “build.sh“ 文件中添加“USE\_DUMP=1”字段,编译安装PyTorch框架。 + +
修改CPU性能模式(ARM服务器)- -s 为需要提取的源算子名称及seqid +**设置电源策略为高性能模式** - -d 为需要提取的目的算子名称及seqid +在某些对Host侧CPU要求较高的模型中,例如目标检测类模型,需要进行较为复杂的图像预处理,开启电源高性能模式能一定程度上提高性能和稳定性。ARM服务器提升网络性能需要在BIOS设置中将电源策略设为高性能模式,具体操作如下。 - 若需要提取多个算子,则修改-s、-d参数,多次执行该命令,可以把多算子追加提取到output.h5中。 +1. 登录ibmc界面,启动虚拟控制台,远程控制选择HTML5集成远程控制台,如[图1](#fig15869135420288)。 - 该命令需-s和-d参数相同。 + **图 1** 远程登录控制台 +  - 示例: +2. 在虚拟界面工具栏中,单击启动项工具,弹出启动项配置界面,如[图2](#fig744814574243)。 - ``` - h5copy -pv -i "./dump_npu.h5" -o "./output.h5" -s "/numpy_T/1/" -d "/numpy_T/1/" - ``` + **图 2** 启动项工具 +  - 该示例表示从“./dump_npu.h5”中抽取seqid为1的numpy_T算子的输入、输出数据到"./output.h5"文件中。 +3. 在启动项配置界面选择,选择“BIOS设置”,然后在虚拟界面工具栏中单击重启工具,重启服务器。 +4. 系统重启后进入BIOS配置界面,依次选择“Advanced”\>“ Performance Config”,如[图3](#fig4546303814)所示。 -2. 配置acl.json文件。 + **图 3** Performance Config +  - 在模型目录下创建acl dump功能所需的的配置文件acl.json +5. 进入“Performance Config”,设置Power Policy为Performance。如[图4](#fig15501111014442)。 - ``` - { - "dump": - { - "dump_list":[] - "dump_path":"./output_IR2TBE"# 映射结果输出路径 - "dump_mode":"all" - "dump_op_switch":"on" - } - - } - ``` + **图 4** 设置电源策略 +  - 需将`dump_path`修改为结果输出路径,其他字段不需要修改。 +6. 按下“F10”保存配置并重启服务器。 -3. 修改训练脚本。 +安装高性能pillow库(X86服务器)- 在训练脚本中添加`with`语句开启IR映射TBE功能。 +1. 安装高性能pillow库相关依赖,命令如下。 - ```python - with torch.utils.dumper(use_load=True, dump_path="./",load_file_path="./output.h5", load_with_acl_dump=True) as dump: - # 模型计算代码,需用户自己添加 - # x = model(input_data) - ``` + ubuntu/debian: -4. 模型运行。 + ``` + apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python3-tk libharfbuzz-dev libfribidi-dev libxcb1-dev + ``` - 运行一步完整的模型计算过程,在计算过程中load遇到output.h5中的数据后,自动开启acl dump功能,执行IR,并dump出IR相对应的TBE算子的输入输出数据,IR执行结束,acl dump结束。 + centos/bclinux/euler: -5. 获得映射文件。 + ``` + yum install libtiff-devel libjpeg-devel openjpeg2-devel zlib-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel harfbuzz-devel fribidi-devel libraqm-devel libimagequant-devel libxcb-devel + ``` - 运行成功后,在acl.json配置文件中的`dump_path`路径下查看输出结果文件。 +2. 安装高性能pillow库。 + 1. 执行如下命令卸载原生pillow。 -整网调测+ ``` + pip3.7 uninstall -y pillow + ``` -用户也可通过分析整个网络的方式来进行网络模型的精度调测。 + 2. 安装SSE4版本pillow-simd。 -1. 通过对比CPU和昇腾AI处理器的结果,判断在昇腾AI处理器上计算是否正确。 + 使用root用户安装,执行如下命令,若使用非root用户安装,需在命令结尾加上--user。 - 代码样例(本样例只体现基本方法,禁止直接复制)如下: + ``` + pip3.7 install pillow-simd + ``` - ``` - # 固定入参,保证模型与输入数据在CPU和昇腾AI处理器上相同 - input_tensor_cpu = torch.Tensor() - model_cpu = build_model() - # 将输入数据迁移到昇腾AI处理器上 - input_tensor_npu = input_tensor_cpu.npu() - # 将模型迁移到昇腾AI处理器上 - model_npu = model_cpu.npu() - - # 运算结果对比 - output_cpu = model_cpu(input_tensor_cpu) - output_npu = model_npu(input_tensor_npu) - compute_result = (output_cpu - output_npu).abs().mean()) - print(compute_result) - ``` + > **说明:** + >如果CPU支持AVX2指令集,可安装AVX2版本pillow-simd,命令如下: + >``` + >CC="cc -mavx2" pip3.7 install -U --force-reinstall pillow-simd + >``` - 因昇腾AI处理器硬件架构与cpu不同,计算结果会略有不同。若运算结果较为接近(一般不高于1e-4),则认为运算结果正常。 -2. 通过Pytorch的hook机制来打印正向反向传播中module的输入和输出来分析。 +3. 修改torchvision代码解决pillow-simd缺少PILLOW\_VERSION问题。torchvision安装参见[样例获取](#样例获取md)。 - 代码样例(本样例只体现基本方法,禁止直接复制)如下: + 将/usr/local/python3.x.x/lib/python3.x/site-packages/torchvision/transforms/functional.py第5行代码修改如下: ``` - # 设置hook func - def hook_func(name, module): - def hook_function(module, inputs, outputs): - print(name+' inputs', inputs) - print(name+' outputs', outputs) - return hook_function - - # 注册正反向hook - for name, module in model.named_modules(): - module.register_forward_hook(hook_func('[forward]: '+name, module)) - module.register_backward_hook(hook_func('[backward]: '+name, module)) - - # 运行 - model(input_tensor) + try: + from PIL import Image, ImageOps, ImageEnhance,PILLOW_VERSION + except: + from PIL import Image, ImageOps, ImageEnhance + PILLOW_VERSION="7.0.0" ``` - 通过分析打印正向反向传播中的inputs, outputs来确定。 -3. 通过直接获取module的grad, running\_mean, running\_var等参数来分析更新量。 +(可选)安装指定版本OpenCV库- 代码样例(本样例只体现基本方法,禁止直接复制)如下: +如模型依赖OpenCV,基于训练性能考虑,建议安装OpenCV-3.4.10版本。 - ``` - # 例如获取梯度和BN的均值方法来排查 - for name, module in model.named_modules(): - if isinstance(module, nn._BatchNorm): - print("[BN_buffer]: "+name, module.running_mean, module.running_var) - print("[grad]: "+name, module.grad) - ``` +1. 获取源码:[获取地址](https://opencv.org/releases/)。 +2. 安装指导:[获取地址](https://docs.opencv.org/3.4.10/d7/d9f/tutorial_linux_install.html)。 +训练过程性能优化-模型保存与转换+**算子瓶颈优化** -- **[简介](#简介md)** +1. 获取训练过程中的Profiling数据,参见[Profiling数据采集](#采集训练过程相关数据md)。 +2. 分析Profiling数据,得到耗时较大的算子。 +3. 参见[单算子样例编写说明](#单算子样例编写说明md)构建耗时较大算子的单算子样例,通过与CPU或GPU运行单算子样例时间进行对比,若发现性能不足,则有以下两种方案解决。 + - 规避方案:使用同等语义其他高效算子替代。 + - 解决方案:改进算子性能。 -- **[模型保存](#模型保存md)** +**copy瓶颈优化** -- **[导出ONNX模型](#导出ONNX模型md)** +1. 获取训练过程中的Profiling数据,参见[Profiling数据采集](#采集训练过程相关数据md)。 +2. 分析Profiling数据分析整网中的D2DCopywithStreamSynchronize/PTCopy/format\_contiguous的耗时。 +3. 若发现耗时较大,则需参照以下两种方案解决。 + - 方案一:(规避方案)PyTorch中View类型框架类算子会导致非连续转连续操作。优化思路为尽量使用计算类算子代替View类框架算子,常见的View类框架算子如View、Permute、Transpose等。更多View类框架算子可参考[https://pytorch.org/docs/stable/tensor\_view.html](https://pytorch.org/docs/stable/tensor_view.html)。 + - 方案二:(解决方案)加速转连续操作。 +**框架瓶颈优化** -简介+1. 获取训练过程中算子信息OP\_INFO,参见[获取算子信息OP\_INFO](#采集训练过程相关数据md)。 +2. 分析OP\_INFO中算子的规格和调用关系,定位是否插入了多余的算子,重点关注transdata是否合理。 +3. 优化方案:通过指定部分算子初始化格式,对多余的格式转换算子进行消除。 +4. 在pytorch/torch/nn/modules/module.py中,在cast\_weight中指定算子初始化格式,如下图。 -模型训练完成后,通过Pytorch提供的接口保存模型文件并导出ONNX模型,然后通过ATC工具将其转换为适配昇腾AI处理器的.om文件用于离线推理。 +  -本章主要介绍如何将训练好的pth文件pth.tar文件转换为ONNX模型,将ONNX模型转换为适配昇腾AI处理器的.om文件流程请参考《CANN 开发辅助工具指南》手册中“ATC工具使用指南”章节。 + 格式设置原则可参考如下规则: -如果想使用Auto Tune优化功能,请参考《CANN 开发辅助工具指南》手册中“Auto Tune工具使用指导”章节。 + - Conv2D相关:Weight 可设置为FZ格式,如第424行。 + - Linear相关的参数,可设置为NZ格式,如第409行。 -离线推理应用构建请参考《CANN 应用软件开发指南\(C&C++, 推理\)》。整体流程如下: +**编译瓶颈优化** - +1. 获取训练过程中算子信息OP\_INFO,参见[获取算子信息OP\_INFO](#采集训练过程相关数据md)。 +2. 查看INFO日志,观察第一个step以后的aclopCompile::aclOp关键字,如果后续接了Match op inputs/type failed或To compile op则说明该算子存在动态编译,需要优化。 +3. 需参照以下两种方案解决。 + - 规避方案:在理解模型语义和相关API基础上,使用固定Shape的方式代替动态Shape。 + - 解决方案:减少编译或不需要编译该算子。 + - 优化算子编译配置请参见[编译选项设置](#编译选项设置md)。 -模型保存-Pytorch在训练过程中,通常使用torch.save\(\)来保存Checkpoint文件,根据模型文件的后续用途会保存为两种格式的模型文件: +亲和库-- .pth或.pt扩展名的文件:用于在线推理或导出ONNX格式模型,仅保存模型参数,不保存模型结构,以便压缩文件的体积,可以用Netron等可视化工具打开,一般如[图1 .pth文件](#fig315704722610)所示。 - **图 1** .pth文件 -  +来源介绍- 通过**state\_dict**来保存和加载模型,示例如下: +针对公版模型中常见的网络结构和函数,我们针对性地对其进行了优化,使得运算性能大幅度提升,同时,将其集成到Pytorch框架中,便于模型性能调优中使用。 - 1. 保存模型。 +功能介绍- ``` - # 创建保存路径 - PATH = "state_dict_model.pt" - # 保存模型 - torch.save(net.state_dict(), PATH) - ``` + +
精度调测- > **须知:** - >保存.pth或.pt文件扩展名的文件时要提供模型定义文件,否则无法部署。 -- .pth.tar扩展名的文件:可用于在线推理或重新加载后继续训练。保存多个组件,以字典形式保存,常见的组件包括模型和优化器的state\_dict、停止时的epoch、最新记录的训练损失以及外部的torch.nn.Embedding层等。如果仅用于部署推理模型,推荐只在.pth.tar扩展名的文件中保存权重信息即模型的state\_dict。 +前提条件- 保存和加载模型示例如下: +优先在同等语义和超参下,跑一定的epoch(推荐完整epoch数的20%),使精度,loss等对齐GPU相应水平,完成后再对齐最终精度。 - 1. 保存模型。 +调测过程- ``` - PATH = "checkpoint.pth.tar" - torch.save({ - 'epoch': epoch, - 'loss': loss, - 'state_dict': model.state_dict(), - 'optimizer' : optimizer.state_dict(), - ... - }, PATH) - ``` +- **[总体思路](#总体思路-4md)** - 2. 加载模型用于推理或恢复训练。 +- **[精度调优方法](#精度调优方法md)** - ``` - model = TheModelClass(*args, **kwargs) - optimizer = TheOptimizerClass(*args, **kwargs) - - checkpoint = torch.load(PATH) - model.load_state_dict(checkpoint['model_state_dict']) - optimizer.load_state_dict(checkpoint['optimizer_state_dict']) - epoch = checkpoint['epoch'] - loss = checkpoint['loss'] - - model.eval() - # - or - - model.train() - ``` +总体思路+精度问题排查需要找出是哪一步出现的问题,主要以下几个方面: -> **须知:** ->通常情况下,训练图和推理图中对同一个算子处理方式不同(例如BatchNorm和dropout等算子),在输入格式上也有差别,因此在运行推理或导出ONNX模型之前,必须调用model.eval\(\) 来将dropout和batch normalization层设置为推理模式。 +1. 模型网络计算错误。 + - 定位思路:在网络中加入hook进行排查判断是哪个地方有较大嫌疑,然后构建[单算子用例](#单算子样例编写说明md)逐渐缩小错误范围,证明该算子在当前网络场景下计算有误,可以对比CPU或GPU结果证明。 -导出ONNX模型+ - 规避方案:使用同等语义其他算子替代。 -**简介** + - 解决方案:改进算子精度或功能问题。 -昇腾AI处理器Pytorch模型的部署策略是基于Pytorch官方支持的ONNX模块实现的。ONNX是业内目前比较主流的模型格式,广泛用于模型交流及部署。本节主要介绍如何将Checkpoint文件通过torch.onnx.export\(\)接口导出为ONNX模型。 +2. loss计算错误。 + - 定位思路:由于Loss的特殊性和可以自定义,在判断Loss计算错误后建议dump网络中的loss的输入来测试而非随机同shape tensor,这样才能更好地复现证明。 -**.pth或.pt文件导出ONNX模型** + - 规避方案:使用同等语义其他算子替代。 -保存的.pth或.pt文件可以通过Pytorch构建模型再加载权重的方法恢复,然后导出ONNX模型,样例如下。 + - 解决方案:改进算子精度或功能问题(loss也是由算子构成)。 -``` -import torch -import torch.onnx -import torchvision.models as models -# 设置使用CPU导出模型 -device = torch.device("cpu") - -def convert(): - # 模型定义来自于torchvision,样例生成的模型文件是基于resnet50模型 - model = models.resnet50(pretrained = False) - resnet50_model = torch.load('resnet50.pth', map_location='cpu') - model.load_state_dict(resnet50_model) - - batch_size = 1 #批处理大小 - input_shape = (3, 224, 224) #输入数据,改成自己的输入shape +3. 参数更新错误。 - # 模型设置为推理模式 - model.eval() + - 定位思路:在每个optim.step\(\)前对网络中的参数逐个打印其grad进行排查判断是哪个地方有较大嫌疑,然后构建单算子用例逐渐缩小错误范围,证明该算子在当前网络场景下梯度计算有误,可以对比CPU或GPU结果证明。该项优先级应低于[1.](#li17755175510322)与[2.](#li25281726103316),因为1与2的错误同样可以造成grad异常。 - dummy_input = torch.randn(batch_size, *input_shape) # 定义输入shape - torch.onnx.export(model, - dummy_input, - "resnet50_official.onnx", - input_names = ["input"], # 构造输入名 - output_names = ["output"], # 构造输出名 - opset_version=11, # ATC工具目前仅支持opset_version=11 - dynamic_axes={"input":{0:"batch_size"}, "output":{0:"batch_size"}}) #支持输出动态轴 - ) - -if __name__ == "__main__": - convert() -``` + - 规避方案:使用同等语义其他算子替代。 -> **说明:** ->- 在导出ONNX模型之前,必须调用model.eval\(\) 来将dropout和batch normalization层设置为推理模式。 ->- 样例脚本中的model来自于torchvision模块中的定义,用户使用自己的模型时需自行指定。 ->- 构造输入输出需要对应训练时的输入输出,否则无法正常推理。 + - 解决方案:改进计算grad的算子精度或功能问题。 -**.pth.tar文件导出ONNX模型** +4. 多卡计算错误。 -.pth.tar在导出ONNX模型时需要先确定保存时的信息,有时保存的节点名称和模型定义中的节点会有差异,例如会多出前缀和后缀。在进行转换的时候,可以对节点名称进行修改。转换代码样例如下。 + - 定位思路:在保证单卡精度OK的前提下,稳定复现多卡不收敛。 -``` -import torch -import torch.onnx -from collections import OrderedDict -import mobilenet + - 解决方案:建议联系华为方支撑人员,提供稳定复现的单P和多P脚本。 -# 本样例中的pth.tar文件保存时节点名加了前缀module,通过遍历删除 -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for key, value in checkpoint[AttrName].items(): - if key == "module.features.0.0.weight": - print(value) - if(key[0:7] == "module."): - name = key[7:] - else: - name = key[0:] +精度调优方法- new_state_dict[name] = value - return new_state_dict +模型出现精度问题一般有:因算子溢出导致的训练loss不收敛或者精度不达标问题,整个网络训练引起的性能不达标问题。用户可通过单算子溢出检测和整网调测适度解决模型精度不达标问题。 -def convert(): - checkpoint = torch.load("./mobilenet_cpu.pth.tar", map_location=torch.device('cpu')) - checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') - model = mobilenet.mobilenet_v2(pretrained = False) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, "mobilenetV2_npu.onnx", input_names = input_names, output_names = output_names, opset_version=11) +- **[环境准备](#环境准备md)** +- **[模型算子精度对比](模型算子精度对比)** +- **[单算子溢出检测](#单算子溢出检测md)** +- **[IR与TBE算子映射](IR与TBE算子映射)** +- **[NPU与GPU算子映射](NPU与GPU算子映射)** +- **[整网调测](#整网调测md)** -if __name__ == "__main__": - convert() -``` +##### 环境准备 + +- 安装hdf5工具以支持算子dump功能,安装详情请参见[编译安装hdf5](#编译安装hdf5md)。 + + 若使用模型算子精度对比功能,需要同时在NPU和GPU环境安装hdf5。否则,仅在NPU环境安装hdf5即可。 -样例说明+- 安装支持dump功能的Ascend PyTorch框架,编译前请修改build.sh脚本,其余操作请参见《PyTorch安装指南》。 -- **[ResNet50模型迁移示例](#ResNet50模型迁移示例md)** + - 在NPU环境PyTorch安装 -- **[ShuffleNet模型调优示例](#ShuffleNet模型调优示例md)** + 编译前修改build.sh脚本,在脚本中增加`USE_DUMP=1`字段。 + ```bash + DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=1 USE_MKLDNN=0 USE_CUDA=0 USE_NPU=1 BUILD_TEST=0 USE_NNPACK=0 USE_DUMP=1 python"${PY_VERSION}" setup.py build bdist_wheel + ``` + + - (可选)在GPU环境PyTorch安装,若对模型算子精度对比,请执行此操作,否则请忽略。 -ResNet50模型迁移示例+ 编译前修改build.sh,在脚本中增加`USE_DUMP=1`、`USE_NCCL=0`字段,将 `USE_HCCL`、`USE_NPU`字段的值修改为0,将`USE_CUDA`字段的值修改为1。 + + ```bash + DEBUG=0 USE_DISTRIBUTED=1 USE_HCCL=0 USE_NCCL=0 USE_MKLDNN=0 USE_CUDA=1 USE_NPU=0 BUILD_TEST=0 USE_NNPACK=0 USE_DUMP=1 python"${PY_VERSION}" setup.py build bdist_wheel + ``` -- **[样例获取](#样例获取md)** +##### 模型算子精度对比 -- **[训练脚本迁移](#训练脚本迁移md)** +用户使用精度对比工具,在相同输入的情况下,获取模型在GPU和NPU进行训练时模型内算子输出的精度差异,从而帮助开发者实现算子精度问题定位。 -- **[脚本执行](#脚本执行md)** +约束说明: +- 建议使用小batchsize,一般设置为8及以下。 -样例获取+ 由于每个算子输入、输出数据会存储在硬盘中,会占用较大空间,故建议使用小batchsize节省硬盘空间。 -样例获取 +- 建议仅dump一个step的数据进行精度对比。 -1. 本样例基于PyTorch官网提供的Imagenet数据集训练模型进行适配昇腾910 AI处理器的迁移改造,样例获取路径为[https://github.com/pytorch/examples/tree/master/imagenet](https://github.com/pytorch/examples/tree/master/imagenet)。 -2. 本样例依赖torchvision,需要安装torchvision依赖,如果使用非root用户安装, 则需在命令末尾加上**--user**。 +- 目前支持精度为fp32、O1或O2训练过程的算子精度对比。 - 当服务器运行环境为X86架构时,安装命令如下: +对比模式: - ``` - pip3.7 install torchvision==0.6.0 --no-deps - ``` +- GPU的输入和输出为已知数据,将GPU的输入数据加载到NPU上执行得到输出数据,NPU与GPU输出数据对比。 +- NPU的输入和输出为已知数据,将NPU的输入数据加载到GPU上执行得到输出数据,NPU与GPU输出数据对比。 - 当服务器运行环境为ARM架构时,安装命令如下: +操作步骤: - ``` - pip3.7 install torchvision==0.2.2.post3 --no-deps - ``` +1. 在GPU或NPU环境,使用dumper工具获取GPU或NPU的模型输入和算子输出数据。 -3. Resnet50模型参考PyTorch官网模型[https://pytorch.org/hub/pytorch\_vision\_resnet/](https://pytorch.org/hub/pytorch_vision_resnet/),实际使用有如下两种方式。 - 1. 直接调用对应接口,例如: + 修改训练代码,增加数据dump功能。在模型训练代码的正向、反向计算位置使用`with`语句增加`torch.utils.dumper()`方法dump数据。例如,在GPU环境下修改示例: - ``` - import torchvision.models as models - model = models.resnet50() - ``` + ```python + for i, data in enumerate(dataloader): + with torch.utils.dumper(use_dump=True, dump_path="./model_gpu.h5") as dump: + # 模型训练代码 + xxx # forward code + xxx # backward code + exit() + xxx # optimizer code + ``` - > **说明:** - >Resnet50为PyTorch内置模型,了解更多内置模型请前往[Pytorch官网](https://pytorch.org/)。 + dump_path参数为dump数据保存文件路径及名称。建议仅dump一个step的数据用于精度对比,同时参数更新代码放在with语句外。 - 2. 在脚本执行中直接指定参数arch为resnet50,内容如下,本样例迁移采用该种方式,请参见[脚本执行](#脚本执行md)。 +2. 将在GPU(NPU)环境dump的数据model_gpu.h5拷贝到NPU(GPU)环境。 - ``` - --arch resnet50 - ``` +3. 在NPU或NPU环境,使用dumper工具加载已经dump出的数据,并获取算子输出数据。 + 修改训练代码,增加数据load、dump功能。在模型训练代码的正向、反向计算位置使用`with`语句增加`torch.utils.dumper()`方法load、dump数据。例如,在NPU环境下修改示例: + ```python + for i, data in enumerate(dataloader): + with torch.utils.dumper(use_dump=True, load_file_path="./model_gpu.h5", dump_path="./model_npu.h5") as dump: + # 模型训练代码 + xxx # forward code + xxx # backward code + exit() + xxx # optimizer code + ``` -目录结构 + load_file_path参数为从GPU或NPU获取的dump数据路径,dump_path参数为dump数据保存文件路径及名称。建议仅dump一个step的数据用于精度对比,同时参数更新代码放在with语句外。 -主要文件目录结构如下所示: +4. 使用msaccucmp.py对算子输出数据对比。 -``` -├──main.py -``` + 1. ascend-toolkit提供了msaccucmp.py工具脚本用具精度对比。 -训练脚本迁移+ - 该脚本路径为:"/user/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py", -- **[单P训练修改](#单P训练修改md)** + 路径仅供参考,请以ascend-toolkit实际安装路径为准。 -- **[分布式训练修改](#分布式训练修改md)** + - 也可以使用如下命令查找msaccucmp.py路径。 + ```linux + find / -name msaccucmp.py + ``` -单P训练修改+ 2. 执行msaccucmp.py脚本,进行精度对比。 -1. main.py增加头文件以支持基于PyTorch框架的模型在昇腾910 AI处理器上训练: + ``` + python3 /user/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py compare -m ./model_npu.h5 -g ./model_gpu.h5 + ``` - ``` - import torch.npu - ``` + 参数说明: -2. 在main.py文件中头文件后添加参数以指定使用昇腾910 AI处理器进行训练: + `-g`参数传入使用GPU获得的dump数据文件路径。 - ``` - CALCULATE_DEVICE = "npu:1" - ``` + `-m`参数传入使用NPU获得的dump数据文件路径。 -3. 修改参数以及判断选项,使其只在昇腾910 AI处理器上进行训练。 - 代码位置:main.py文件中的main\_worker\(\)函数(修改部分为字体加粗部分): +单算子溢出检测- ``` - def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - # 原代码为使用GPU进行训练,原代码如下: - # args.gpu = gpu - ############## npu modify begin ############# - args.gpu = None - ############## npu modify end ############# - if args.gpu is not None: - print("Use GPU: {} for training".format(args.gpu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = models.__dict__[args.arch](pretrained=True) - else: - print("=> creating model '{}'".format(args.arch)) - model = models.__dict__[args.arch]() - # 原代码中需要判断是否在GPU上进行训练,原代码如下: - # if not torch.cuda.is_available(): - # print('using CPU, this will be slow') - # elif args.distributed: - ############## npu modify begin ############# - # 迁移后为直接判断是否进行分布式训练,去掉判断是否在GPU上进行训练 - if args.distributed: - ############## npu modify end ############# - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - ...... - ``` +用户通过算子溢出检测功能检测算子是否有溢出,然后采集溢出算子的数据,从而帮助开发人员快速定位并解决算子精度问题。 -4. 将模型以及损失函数迁移到昇腾910 AI处理器上进行计算。 +约束说明: - 代码位置:main.py文件中的main\_worker\(\)函数(修改部分为字体加粗部分): +- 本功能只提供IR级别的算子溢出检测,且只支持AICORE,不支持Atomic。 +- 使用单算子溢出检测功能时,请不要同时开启apex的动态loss scale模式和使用tensor融合功能。 - ``` - elif args.gpu is not None: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - else: - # DataParallel will divide and allocate batch_size to all available GPUs - if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): - model.features = torch.nn.DataParallel(model.features) - model.cuda() - else: - # 原代码使用torch.nn.DataParallel()类来用多个GPU加速训练 - # model = torch.nn.DataParallel(model).cuda() - ############## npu modify begin ############# - # 将模型迁移到NPU上进行训练。 - model = model.to(CALCULATE_DEVICE) - ############## npu modify end ############# - # 原代码中损失函数是在GPU上进行计算 - # # define loss function (criterion) and optimizer - # criterion = nn.CrossEntropyLoss().cuda(args.gpu) - ############## npu modify begin ############# - # 将损失函数迁移到NPU上进行计算。 - criterion = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) - ############## npu modify end ############# - ``` +采集溢出算子数据: -5. 将数据集目标结果target修改成int32类型解决算子报错问题;将数据集迁移到昇腾910 AI处理器上进行计算。 - - 代码位置:main.py文件中的train\(\)函数(修改部分为字体加粗部分): +``` +# check_overflow为溢出检测控制开关 +# dump_path为dump文件保存路径 +with torch.utils.dumper(check_overflow=check_overflow, dump_path=dump_path, load_file_path='') as dump: + # 需要检测算子溢出的代码片段 +``` - ``` - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.gpu is not None: - images = images.cuda(args.gpu, non_blocking=True) - # 原代码中训练数据集在GPU上进行加载计算,原代码如下: - # if torch.cuda.is_available(): - # target = target.cuda(args.gpu, non_blocking=True) - ############## npu modify begin ############# - # 将数据集迁移到NPU上进行计算并修改target数据类型,以提升性能 - if 'npu' in CALCULATE_DEVICE: - target = target.to(torch.int32) - images, target = images.to(CALCULATE_DEVICE, non_blocking=True), target.to(CALCULATE_DEVICE, non_blocking=True) - ############## npu modify end ############# - ``` +运行一个step,模型运行过程中,如果有算子溢出,会打印出相应IR的名字。 - - 代码位置:main.py文件中的validate\(\)函数(修改部分为字体加粗部分): +查看Dump数据: - ``` - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - images = images.cuda(args.gpu, non_blocking=True) - # 原代码中训练数据集在GPU上进行加载计算,原代码如下: - # if torch.cuda.is_available(): - # target = target.cuda(args.gpu, non_blocking=True) - ############## npu modify begin ############# - # 将数据集迁移到NPU上进行计算并修改target数据类型 - if 'npu' in CALCULATE_DEVICE: - target = target.to(torch.int32) - images, target = images.to(CALCULATE_DEVICE, non_blocking=True), target.to(CALCULATE_DEVICE, non_blocking=True) - ############## npu modify end ############# - ``` +如果训练过程中采集到了Dump数据,则会在\{dump\_path\}路径下生成dump数据的.h5文件,用户可进入路径自行查看。 -6. 设置当前正在使用的device。 +解决方法: - 代码位置:main.py文件中的主函数入口(修改部分为字体加粗部分): +1. 将采集到的.h5文件映射到TBE算子,映射方法请参见[IR与TBE算子映射](#IR与TBE算子映射)。 - ``` - if __name__ == '__main__': - ############## npu modify begin ############# - if 'npu' in CALCULATE_DEVICE: - torch.npu.set_device(CALCULATE_DEVICE) - ############## npu modify begin ############# - main() - ``` +2. 请将算子溢出的打印截图及映射后的TBE算子输入输出文件通过Issue附件形式反馈给华为开发人员。 +##### IR与TBE算子映射 -分布式训练修改+前提条件: -1. main.py增加头文件以支持基于PyTorch框架的模型在昇腾910 AI处理器上训练及进行混合精度训练。 +- 设置环境变量`export ACL_DUMP_DATA=0`。 +- 在脚本中避免使用`torch.npu.init.dump()`和`torch.npu.set.dump()`接口。 - ``` - import torch.npu - from apex import amp - ``` +操作步骤: -2. 参数设置增加以下参数,包括指定参与训练的昇腾910 AI处理器以及进行混合精度训练需要的参数。 +1. 准备好需要映射的算子.h5文件。 - ``` - parser.add_argument('--device', default='npu', type=str, help='npu or gpu') - parser.add_argument('--addr', default='10.136.181.115', type=str, help='master addr') - parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') - parser.add_argument('--amp', default=False, action='store_true', help='use amp to train the model') - parser.add_argument('--loss-scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') - parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') - ``` + - 算子溢出检测场景下,单算子溢出检测已生成需要映射的算子.h5文件。 -3. 创建由device\_id到process\_id的映射函数,指定device进行训练。在main.py函数中增加以下接口。 + - 精度对比场景下,需根据精度对比结果,参照下面命令提取需要映射的算子.h5文件。 - ``` - def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - ``` + ``` + h5copy -pv -i "./input.h5" -o "./output.h5" -s "/op1/seqid/" -d "/op1/seqid/" + ``` -4. 指定训练服务器的ip和端口。 + -i 为输入精度对比文件 - 代码位置:main.py文件中的主函数main\(\)(修改部分为字体加粗部分)。 + -o 为输出需要映射的算子.h5文件路径 - ``` - def main(): - args = parser.parse_args() - ############## npu modify begin ############# - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - ############## npu modify end ############# - ``` + -s 为需要提取的源算子名称及seqid -5. 创建由device\_id到process\_id的映射参数,获取单节点昇腾910 AI处理器数量。 + -d 为需要提取的目的算子名称及seqid - 代码位置:main.py文件中的主函数main\(\)(修改部分为字体加粗部分)。 + 若需要提取多个算子,则修改-s、-d参数,多次执行该命令,可以把多算子追加提取到output.h5中。 - ``` - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - ############## npu modify begin ############# - args.process_device_map = device_id_to_process_device_map(args.device_list) - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - ngpus_per_node = torch.cuda.device_count() - ############## npu modify end ############# - # 原代码如下: - # ngpus_per_node = torch.cuda.device_count() - ``` + 该命令需-s和-d参数相同。 -6. 获取进程process\_id对应的昇腾910 AI处理器编号,指定在对应的昇腾910 AI处理器上进行训练。 + 示例: - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 + ``` + h5copy -pv -i "./dump_npu.h5" -o "./output.h5" -s "/numpy_T/1/" -d "/numpy_T/1/" + ``` - ``` - def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - ############## npu modify begin ############# - args.gpu = args.process_device_map[gpu] - ############## npu modify end ############# - # 原代码如下: - # args.gpu = gpu - ``` + 该示例表示从“./dump_npu.h5”中抽取seqid为1的numpy_T算子的输入、输出数据到"./output.h5"文件中。 -7. 初始化进程组,屏蔽掉初始化方式。 +2. 配置acl.json文件。 - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 + 在模型目录下创建acl dump功能所需的的配置文件acl.json - ``` - ############## npu modify begin ############# - if args.device == 'npu': - dist.init_process_group(backend=args.dist_backend, #init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - else: - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - ############## npu modify begin ############# - # 原代码如下: - # dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - ``` + ``` + { + "dump": + { + "dump_list":[] + "dump_path":"./output_IR2TBE"# 映射结果输出路径 + "dump_mode":"all" + "dump_op_switch":"on" + } + + } + ``` -8. 要进行分布式训练且需要引入混合精度模块,并且需要将模型迁移到昇腾AI处理器上,因此需要屏蔽掉原始代码中判断是否为分布式训练以及模型是否在GPU上进行训练的代码部分。 + 需将`dump_path`修改为结果输出路径,其他字段不需要修改。 - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 +3. 修改训练脚本。 - ``` - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = models.__dict__[args.arch](pretrained=True) - else: - print("=> creating model '{}'".format(args.arch)) - model = models.__dict__[args.arch]() - ############## npu modify begin ############# - # 代码中添加如下内容 - # 指定训练设备为昇腾AI处理器 - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(loc) - # 计算用于训练的batch_size和workers - args.batch_size = int(args.batch_size / ngpus_per_node) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - ############## npu modify end ############# - # 原始代码如下,需屏蔽掉,已注释 - # if not torch.cuda.is_available(): - # print('using CPU, this will be slow') - # elif args.distributed: - # # For multiprocessing distributed, DistributedDataParallel constructor - # # should always set the single device scope, otherwise, - # # DistributedDataParallel will use all available devices. - # if args.gpu is not None: - # torch.cuda.set_device(args.gpu) - # model.cuda(args.gpu) - # # When using a single GPU per process and per - # # DistributedDataParallel, we need to divide the batch size - # # ourselves based on the total number of GPUs we have - # args.batch_size = int(args.batch_size / ngpus_per_node) - # args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - # model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) - # else: - # model.cuda() - # # DistributedDataParallel will divide and allocate batch_size to all - # # available GPUs if device_ids are not set - # model = torch.nn.parallel.DistributedDataParallel(model) - # elif args.gpu is not None: - # torch.cuda.set_device(args.gpu) - # model = model.cuda(args.gpu) - # else: - # # DataParallel will divide and allocate batch_size to all available GPUs - # if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): - # model.features = torch.nn.DataParallel(model.features) - # model.cuda() - # else: - # model = torch.nn.DataParallel(model).cuda() - ``` + 在训练脚本中添加`with`语句开启IR映射TBE功能。 -9. 屏蔽掉损失函数、优化器和断点训练部分,将这部分在后面与混合精度训练结合起来。 + ```python + with torch.utils.dumper(use_load=True, dump_path="./",load_file_path="./output.h5", load_with_acl_dump=True) as dump: + # 模型计算代码,需用户自己添加 + # x = model(input_data) + ``` - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 +4. 模型运行。 - ``` - # 屏蔽掉原始代码,已注释 - # # define loss function (criterion) and optimizer - # criterion = nn.CrossEntropyLoss().cuda(args.gpu) - # - # optimizer = torch.optim.SGD(model.parameters(), args.lr, - # momentum=args.momentum, - # weight_decay=args.weight_decay) - # - # # optionally resume from a checkpoint - # if args.resume: - # if os.path.isfile(args.resume): - # print("=> loading checkpoint '{}'".format(args.resume)) - # if args.gpu is None: - # checkpoint = torch.load(args.resume) - # else: - # # Map model to be loaded to specified single gpu. - # loc = 'cuda:{}'.format(args.gpu) - # checkpoint = torch.load(args.resume, map_location=loc) - # args.start_epoch = checkpoint['epoch'] - # best_acc1 = checkpoint['best_acc1'] - # if args.gpu is not None: - # # best_acc1 may be from a checkpoint from a different GPU - # best_acc1 = best_acc1.to(args.gpu) - # model.load_state_dict(checkpoint['state_dict']) - # optimizer.load_state_dict(checkpoint['optimizer']) - # print("=> loaded checkpoint '{}' (epoch {})" - # .format(args.resume, checkpoint['epoch'])) - # else: - # print("=> no checkpoint found at '{}'".format(args.resume)) - # - # cudnn.benchmark = True - ``` + 运行一步完整的模型计算过程,在计算过程中load遇到output.h5中的数据后,自动开启acl dump功能,执行IR,并dump出IR相对应的TBE算子的输入输出数据,IR执行结束,acl dump结束。 -10. 数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集。使用昇腾AI处理器进行训练,需要将**pin\_memory**设置为**False**;由于当前仅支持固定shape下的训练,数据流中剩余的样本数可能小于batch大小,因此需要将**drop\_last**设置为**True**;另外需要将验证部分数据集**shuffle**设置为**True**。 +5. 获得映射文件。 - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 + 运行成功后,在acl.json配置文件中的`dump_path`路径下查看输出结果文件。 - ``` - ############## npu modify begin ############# - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - ############## npu modify end ############# - ``` +##### NPU与GPU算子映射 -11. 进行损失函数及优化器构建,将模型、损失函数迁移到昇腾AI处理器上;将优化器、模型与混合精度模块进行结合以支持混合精度训练;将断点训练部分与混合精度模块结合以支持混合精度训练。 +请参见《开发辅助工具指南》中 ”精度对比工具使用指南(训练)“中 “数据准备章节” 中的 “[准备以PyTorch为原始训练网络的精度比对数据文件](https://support.huawei.com/enterprise/zh/doc/EDOC1100219269/2324edc8#ZH-CN_TOPIC_0000001162580808)”。 - 代码位置:main.py文件中的main\_worker\(\)中验证数据加载**后**(修改部分为字体加粗部分)。 +整网调测- ``` - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - - ############## npu modify begin ############# - model = model.to(loc) - # define loss function (criterion) and optimizer - criterion = nn.CrossEntropyLoss().to(loc) - optimizer = torch.optim.SGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.amp: - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - ############## npu modify end ############# - ``` +用户也可通过分析整个网络的方式来进行网络模型的精度调测。 -12. 断点checkpoint保存需要与混合精度训练结合,修改如下。 +1. 通过对比CPU和昇腾AI处理器的结果,判断在昇腾AI处理器上计算是否正确。 - 代码位置:main.py文件中的main\_worker\(\)(修改部分为字体加粗部分)。 + 代码样例(本样例只体现基本方法,禁止直接复制)如下: ``` - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) + # 固定入参,保证模型与输入数据在CPU和昇腾AI处理器上相同 + input_tensor_cpu = torch.Tensor() + model_cpu = build_model() + # 将输入数据迁移到昇腾AI处理器上 + input_tensor_npu = input_tensor_cpu.npu() + # 将模型迁移到昇腾AI处理器上 + model_npu = model_cpu.npu() - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - ############## npu modify begin ############# - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer' : optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer' : optimizer.state_dict(), - }, is_best) - ############## npu modify end ############# + # 运算结果对比 + output_cpu = model_cpu(input_tensor_cpu) + output_npu = model_npu(input_tensor_npu) + compute_result = (output_cpu - output_npu).abs().mean()) + print(compute_result) ``` -13. 训练时,需要将数据集迁移到昇腾AI处理器上,修改如下: + 因昇腾AI处理器硬件架构与cpu不同,计算结果会略有不同。若运算结果较为接近(一般不高于1e-4),则认为运算结果正常。 + +2. 通过Pytorch的hook机制来打印正向反向传播中module的输入和输出来分析。 - 代码位置:main.py文件中的train\(\)(修改部分为字体加粗部分)。 + 代码样例(本样例只体现基本方法,禁止直接复制)如下: ``` - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - ############## npu modify begin ############# - loc = 'npu:{}'.format(args.gpu) - target = target.to(torch.int32) - images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) - ############## npu modify end ############# - # 原模型代码如下: - # if args.gpu is not None: - # images = images.cuda(args.gpu, non_blocking=True) - # if torch.cuda.is_available(): - # target = target.cuda(args.gpu, non_blocking=True) + # 设置hook func + def hook_func(name, module): + def hook_function(module, inputs, outputs): + print(name+' inputs', inputs) + print(name+' outputs', outputs) + return hook_function + + # 注册正反向hook + for name, module in model.named_modules(): + module.register_forward_hook(hook_func('[forward]: '+name, module)) + module.register_backward_hook(hook_func('[backward]: '+name, module)) + + # 运行 + model(input_tensor) ``` -14. 标记反向传播.backward\(\)发生的位置,这样混合精度模块就可以进行Loss Scaling并清除每次迭代的状态,代码如下: + 通过分析打印正向反向传播中的inputs, outputs来确定。 - 代码位置:main.py文件中的train\(\)(修改部分为字体加粗部分)。 +3. 通过直接获取module的grad, running\_mean, running\_var等参数来分析更新量。 + + 代码样例(本样例只体现基本方法,禁止直接复制)如下: ``` - optimizer.zero_grad() - ############## npu modify begin ############# - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - # 原代码如下注释部分: - # loss.backward() - ############## npu modify end ############# - optimizer.step() + # 例如获取梯度和BN的均值方法来排查 + for name, module in model.named_modules(): + if isinstance(module, nn._BatchNorm): + print("[BN_buffer]: "+name, module.running_mean, module.running_var) + print("[grad]: "+name, module.grad) ``` -15. 验证时,需要将验证数据集迁移到昇腾AI处理器上,修改如下: - 代码位置:main.py文件中的validate\(\)(修改部分为字体加粗部分)。 +模型保存与转换- ``` - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - ############## npu modify begin ############# - loc = 'npu:{}'.format(args.gpu) - target = target.to(torch.int32) - images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) - ############## npu modify end ############# - # 原模型代码如下注释部分: - # if args.gpu is not None: - # images = images.cuda(args.gpu, non_blocking=True) - # if torch.cuda.is_available(): - # target = target.cuda(args.gpu, non_blocking=True) - ``` +- **[简介](#简介md)** + +- **[模型保存](#模型保存md)** + +- **[导出ONNX模型](#导出ONNX模型md)** + + +简介+ +模型训练完成后,通过Pytorch提供的接口保存模型文件并导出ONNX模型,然后通过ATC工具将其转换为适配昇腾AI处理器的.om文件用于离线推理。 + +本章主要介绍如何将训练好的pth文件pth.tar文件转换为ONNX模型,将ONNX模型转换为适配昇腾AI处理器的.om文件流程请参考《CANN 开发辅助工具指南》手册中“ATC工具使用指南”章节。 + +如果想使用Auto Tune优化功能,请参考《CANN 开发辅助工具指南》手册中“Auto Tune工具使用指导”章节。 + +离线推理应用构建请参考《CANN 应用软件开发指南\(C&C++, 推理\)》。整体流程如下: + + + +模型保存+ +Pytorch在训练过程中,通常使用torch.save\(\)来保存Checkpoint文件,根据模型文件的后续用途会保存为两种格式的模型文件: + +- .pth或.pt扩展名的文件:用于在线推理或导出ONNX格式模型,仅保存模型参数,不保存模型结构,以便压缩文件的体积,可以用Netron等可视化工具打开,一般如[图1 .pth文件](#fig315704722610)所示。 + + **图 1** .pth文件 +  + + 通过**state\_dict**来保存和加载模型,示例如下: + + 1. 保存模型。 + + ``` + # 创建保存路径 + PATH = "state_dict_model.pt" + # 保存模型 + torch.save(net.state_dict(), PATH) + ``` + + 2. 加载模型以用于在线推理,示例如下,详情请参见《PyTorch在线推理指南》。 + + ``` + # 模型文件保存路径 + PATH = "state_dict_model.pt" + model = TheModelClass(*args, **kwargs) + # 加载模型 + model.load_state_dict(torch.load(PATH)) + model.eval() + ``` + + > **须知:** + >保存.pth或.pt文件扩展名的文件时要提供模型定义文件,否则无法部署。 + +- .pth.tar扩展名的文件:可用于在线推理或重新加载后继续训练。保存多个组件,以字典形式保存,常见的组件包括模型和优化器的state\_dict、停止时的epoch、最新记录的训练损失以及外部的torch.nn.Embedding层等。如果仅用于部署推理模型,推荐只在.pth.tar扩展名的文件中保存权重信息即模型的state\_dict。 + + 保存和加载模型示例如下: + + 1. 保存模型。 + + ``` + PATH = "checkpoint.pth.tar" + torch.save({ + 'epoch': epoch, + 'loss': loss, + 'state_dict': model.state_dict(), + 'optimizer' : optimizer.state_dict(), + ... + }, PATH) + ``` + + 2. 加载模型用于推理或恢复训练。 + ``` + model = TheModelClass(*args, **kwargs) + optimizer = TheOptimizerClass(*args, **kwargs) + + checkpoint = torch.load(PATH) + model.load_state_dict(checkpoint['model_state_dict']) + optimizer.load_state_dict(checkpoint['optimizer_state_dict']) + epoch = checkpoint['epoch'] + loss = checkpoint['loss'] + + model.eval() + # - or - + model.train() + ``` -脚本执行-**准备数据集** -准备数据集并上传到运行环境的目录下,例如:/home/data/resnet50/imagenet +> **须知:** +>通常情况下,训练图和推理图中对同一个算子处理方式不同(例如BatchNorm和dropout等算子),在输入格式上也有差别,因此在运行推理或导出ONNX模型之前,必须调用model.eval\(\) 来将dropout和batch normalization层设置为推理模式。 -**配置环境变量** +导出ONNX模型-请参考[配置环境变量](#zh-cn_topic_0000001144082004md)配置环境变量。 +**简介** -**执行命令** +昇腾AI处理器Pytorch模型的部署策略是基于Pytorch官方支持的ONNX模块实现的。ONNX是业内目前比较主流的模型格式,广泛用于模型交流及部署。本节主要介绍如何将Checkpoint文件通过torch.onnx.export\(\)接口导出为ONNX模型。 -例如: +**.pth或.pt文件导出ONNX模型** -单卡: +保存的.pth或.pt文件可以通过Pytorch构建模型再加载权重的方法恢复,然后导出ONNX模型,样例如下。 ``` -python3 main.py /home/data/resnet50/imagenet --batch-size 128 \ # 训练批次大小 - --lr 0.1 \ # 学习率 - --epochs 90 \ # 训练迭代轮数 - --arch resnet50 \ # 模型架构 - --world-size 1 \ - --rank 0 \ - --workers 40 \ # 加载数据进程数 - --momentum 0.9 \ # 动量 - --weight-decay 1e-4 # 权重衰减 +import torch +import torch.onnx +import torchvision.models as models +# 设置使用CPU导出模型 +device = torch.device("cpu") + +def convert(): + # 模型定义来自于torchvision,样例生成的模型文件是基于resnet50模型 + model = models.resnet50(pretrained = False) + resnet50_model = torch.load('resnet50.pth', map_location='cpu') + model.load_state_dict(resnet50_model) + + batch_size = 1 #批处理大小 + input_shape = (3, 224, 224) #输入数据,改成自己的输入shape + + # 模型设置为推理模式 + model.eval() + + dummy_input = torch.randn(batch_size, *input_shape) # 定义输入shape + torch.onnx.export(model, + dummy_input, + "resnet50_official.onnx", + input_names = ["input"], # 构造输入名 + output_names = ["output"], # 构造输出名 + opset_version=11, # ATC工具目前仅支持opset_version=11 + dynamic_axes={"input":{0:"batch_size"}, "output":{0:"batch_size"}}) #支持输出动态轴 + ) + +if __name__ == "__main__": + convert() ``` -分布式: +> **说明:** +>- 在导出ONNX模型之前,必须调用model.eval\(\) 来将dropout和batch normalization层设置为推理模式。 +>- 样例脚本中的model来自于torchvision模块中的定义,用户使用自己的模型时需自行指定。 +>- 构造输入输出需要对应训练时的输入输出,否则无法正常推理。 + +**.pth.tar文件导出ONNX模型** + +.pth.tar在导出ONNX模型时需要先确定保存时的信息,有时保存的节点名称和模型定义中的节点会有差异,例如会多出前缀和后缀。在进行转换的时候,可以对节点名称进行修改。转换代码样例如下。 ``` -python3 main.py /home/data/resnet50/imagenet --addr='1.1.1.1' \ # 示例IP地址,请根据实际修改 - --seed 49 \ # 随机种子 - --workers 160 \ # 加载数据进程数 - --lr 0.8 \ - --print-freq 1 \ - --arch resnet50 \ # 模型架构 - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ # 使用多卡训练 - --world-size 1 \ - --batch-size 2048 \ # 训练批次大小 - --epochs 90 \ # 训练迭代轮数 - --rank 0 \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp # 使用混合精度训练 +import torch +import torch.onnx +from collections import OrderedDict +import mobilenet + +# 本样例中的pth.tar文件保存时节点名加了前缀module,通过遍历删除 +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for key, value in checkpoint[AttrName].items(): + if key == "module.features.0.0.weight": + print(value) + if(key[0:7] == "module."): + name = key[7:] + else: + name = key[0:] + + new_state_dict[name] = value + return new_state_dict + +def convert(): + checkpoint = torch.load("./mobilenet_cpu.pth.tar", map_location=torch.device('cpu')) + checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') + model = mobilenet.mobilenet_v2(pretrained = False) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, "mobilenetV2_npu.onnx", input_names = input_names, output_names = output_names, opset_version=11) + +if __name__ == "__main__": + convert() ``` -> **说明:** ->dist-backend需配置成hccl以支持在昇腾AI设备上进行分布式训练。 +模型调优样例ShuffleNet模型调优示例 |
---|