基于弹性云服务器的昇腾AI应用开发随笔【与云原生的故事】

举报
Tianyi_Li 发表于 2022/04/24 10:19:11 2022/04/24
【摘要】 什么是弹性云服务器?先来说说云服务器(Elastic Cloud Server),云服务器是具有完整硬件、操作系统、网络功能,并且运行在一个完全隔离环境中的计算机系统。云服务器具有弹性、按需获取的特点。简单来说,就是能够弹性获得资源的云服务器。而我选择使用的是华为云提供的弹性云服务器,规格如下图所示,是用来做基于Ascend 310的应用开发的,得益于云服务的方便和快捷,我通过接收官方共享的...

什么是弹性云服务器?

先来说说云服务器(Elastic Cloud Server),云服务器是具有完整硬件、操作系统、网络功能,并且运行在一个完全隔离环境中的计算机系统。云服务器具有弹性、按需获取的特点。简单来说,就是能够弹性获得资源的云服务器。而我选择使用的是华为云提供的弹性云服务器,规格如下图所示,是用来做基于Ascend 310的应用开发的,得益于云服务的方便和快捷,我通过接收官方共享的镜像,可以快速创建应用开发环境,进行我自己的开发,很方便,更重要的是极大克服了时间和空间的限制,随时随地,有网路,有浏览器就能开发了,对本地硬件要求大大降低。从生产的角度讲,还很方便进行扩容、传输和分享。
 
 
 
 
这里,我很感兴趣的是,弹性云服务器的隔离和独立性,个人认为这应该是基于容器之类的的服务,隔离底层硬件,直接向上提供给用户服务,使得用户无需关心底层硬件,我了解到容器使应用程序不仅彼此隔离,而且与底层系统隔离。这不仅使软件栈更干净,而且更容易使容器化应用程序使用系统资源,例如CPU、GPU、内存、I/O、网络等,此外,还可以确保数据和代码保持独立。这些在开发中有了体会,比如如果当前系统崩溃或出现问题,我一般直接再创建一个弹性云服务器就好了,又是一个全新的环境。
 

下面来介绍下我在弹性云服务器上基于Ascend 310的应用开发,这其实是在参加CANN训练营,这里推荐一下,硬核AI技术 · 新手+进阶定制化课程 更有无人机等超级大奖等你来!!感兴趣的同学,可以来参加一下,小白亦可,有新手班,还是不错的!

课表.jpg

昇腾AI应用开发

这里主要是基于Ascend 310处理器的弹性云服务器做应用开发,偏向于媒体数据处理,并最终应用于AI模型推理,更多详情,可参考媒体数据处理精讲与实战

应用第一弹

前情提要

1. 按照官方B站视频介绍,接收镜像,并创建云服务器;如果不想看视频,可以参照其他开发者的教程配置环境,推荐教程【CANN训练营进阶班应用课笔记】大作业1实战趟坑记录

2. ssh登录服务器,可以用MobaXterm,也可以直接用Visual Studio Code,这里选择前者,因为MobaXterm支持X server,简单来说,就是支持图形界面,方便我们后续查看yuv文件,如果有朋友不熟悉,推荐教程【CANN训练营进阶班应用课笔记】大作业1实战趟坑记录

准备工作

1. 安装ffmepg。方便通过ffplay查看yuv文件。在root用户下执行如下命令即可:

sudo apt-get install ffmpeg

 2. 切换到用户HwHiAiUser。因为默认是root用户登陆,但是运行代码用HwHiAiUser用户才行,否则报错。

具体操作

1. 将jpeg图片解码成yuv格式(输入文件是dog1_1024_683.dog,尺寸为1024 x 683)先来看看输入jpg文件

  接下来操作!

# 确保已经切换到HwHiAiUser用户
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpegd/scripts
# 注意下面命令运行时,会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86,如下图所示
bash sample_build.sh
bash sample_run.sh

image.png

最终程序运行成功截图:
image.png
我们到这个目录下可以看到生成的.yuv文件:

/home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpegd/out/output

如下图所示:
image.png
接下来,我们查看图片,在root用户下执行命令:

# 注意在root用户下执行,如果不是root用户,可执行su root进行切换
ffplay -f rawvideo -video_size 1024x683 dvpp_output.yuv

可以看到,如下图片,注意这是依赖了MobaXterm的X Server

此时程序运行截图:

可以看到yuv格式的文件上方有一条黄边,在使用ffplay查看时,需要设置图像大小,这里设置的是解码之前的jpeg文件大小,即1024 x 683,而得到的yuv文件,要符合DVPP的宽128对齐,高16对齐要求,原文件宽度没问题,高度要调整对齐,则应为1024 x 688(688是16的倍数),即高度增加了,接下来,我们运行如下代码试试:

ffplay -f rawvideo -video_size 1024x688 dvpp_output.yuv

得到如下图片:

上方的黄边没了,但是下方多了一条绿边,应该就是因为高度对齐带来的吧,正如作业文档提到的那样:

 

  2. 对yuv格式进行resize(输入是上一步得到的yuv格式文件)

# 注意之前可能是root用户,这里我们通过su HwHiAiUser切换为HwHiAiUser用户
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/scripts
# 注意下面命令运行时,仍然会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86,如下图所示
bash sample_build.sh

我们希望resize第一步生成的yuv文件,并设置resize大小,所以先将之前生成的yuv文件拷贝到当前程序的输入目录

cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpegd/out/output/dvpp_output.yuv /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/data/

接下来,修改运行脚本sample_run.sh,主要是输入图片的路径和resize的分辨率:

cd ../scripts/
vim sample_run.sh

# 将sample_run.sh的第10行,替换为如下,表示输入yuv文件路径是../data/dvpp_output.yuv,大小是1024 x 688,resize后大小是224 224
running_command="./main ../data/dvpp_output.yuv 1024 688 ./output/output.yuv 224 224 "

# 运行程序
bash sample_run.sh

我们来看下运行成功截图:

下面看看resize后的yuv文件

# 查看yuv文件要root用户,所以先切换
su root

# 切换到输出的yuv文件目录
cd ../out/output

# 查看yuv文件
ffplay -f rawvideo -video_size 224x224 output.yuv

可以看到明显变小了,而且没有绿边或黄边,这应该是因为DVPP的输入是符合前面提到的宽高对齐要求的。但要注意的是我们设置的resize大小224 x 224的宽度是不符合128对齐的。

 3. resize后的yuv文件编码成jpg图片(输入是上一步得到的resize后的yuv格式文件)

# 注意之前可能是root用户,这里我们通过su HwHiAiUser切换为HwHiAiUser用户
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/scripts

# 修改main.cpp文件,执行输入yuv文件路径和大小
# 切换到main.cpp所在文件夹
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/src
# 修改文件
vim main.cpp
# 在第242行,将该行替换为如下:
PicDesc testPic = {"../data/output.yuv", 224, 224};

# 注意下面命令运行时,仍然会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86
bash sample_build.sh

# 接下来,我们要将上一步得到的resize后的yuv文件拷贝过来作为输入
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/out/output/output.yuv /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/data/dvpp_output.yuv 

# 运行程序
bash sample_run.sh

最终运行成功截图:

最终得到编码后的图片

至此,我们完成了全部流程,对于输入文件是dog1_1024_683.dog,尺寸为1024 x 683的jpg文件——> 解码为YUV文件——>resize到224 x 224 大小——>编码为jpg文件,最终得到了编码后的,如上图所示的jpg文件。

应用第二弹

这是在前一步的基础上的延伸和拓展,一脉相承

前情提要

1. 按照官方B站视频介绍,接收镜像,并创建云服务器;如果不想看视频,可以参照其他开发者的教程配置环境,推荐教程【CANN训练营进阶班应用课笔记】大作业1实战趟坑记录

2. ssh登录服务器,可以用MobaXterm,也可以直接用Visual Studio Code,这里选择前者,因为MobaXterm支持X server,简单来说,就是支持图形界面,方便我们后续查看yuv文件,如果有朋友不熟悉,推荐教程【CANN训练营进阶班应用课笔记】大作业1实战趟坑记录

准备工作

1. 安装ffmepg。方便做视频解码和通过ffplay查看yuv文件。在root用户下执行如下命令即可:

sudo apt-get install ffmpeg

 2. 切换到用户HwHiAiUser。因为默认是root用户登陆,但是运行代码用HwHiAiUser用户才行,否则报错。

 3. 任务要求。从开发手册可以看到

     首先,明确输入是一段.mp4封装的视频,输出是jpeg图片(注意,图片的“分辨率”与输入视频不同),具体来说,整个过程是

     本地.mp4封装的视频(无法直接对mp4格式封装的视频做解码,需要先转换为H.264/H.265视频流)------>硬解码为H.264/H.265视频流——>解码得到YUV图片(一张或多张))——>缩放(修改分辨率,一张或多张)——>硬编码为jpeg文件(一张或多张)

     这里提供一段mp4格式封装的视频,分辨率为1920 x 1080(1080P),帧率为25,编码为AVC(H.264),下载链接为:

     链接:https://pan.baidu.com/s/10b3x15HfGHRmam16M1sGrw 
     提取码:fo6c

     预览一下视频!这是一段经典的视频,一般用于展示行人检测或跟踪的应用效果。

 

具体操作

1. 将输入的mp4文件解码为H.264或H.265视频流

 接下来操作!因为昇腾处理器中的视频编解码专用硬件电路无法直接对mp4格式封装的视频操作,要求输入是H.264/H.265视频流,所以我们先对输入的mp4视频做“拆装”,可以通过ffmpeg来做:

# 注意,我们要先将视频文件TownCentreXVID_1920_1080_25_AVC_H264.mp4上传到
# /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/data/下
# 上传操作也很简单,直接在MobaXterm上打开到上述目录,点击上传即可

ffmpeg -i TownCentreXVID_1920_1080_25_AVC_H264.mp4 -vcodec h264 TownCentreXVID_1920_1080_25_AVC_H264.h264

运行过程截图:

运行结果截图:

好了,我们现在得到想到的H.264视频流了(即 TownCentreXVID_1920_1080_25_AVC_H264.h264),下面要开始解码了,得到YUV格式文件:

首先要修改下main.cpp中的一些参数设置:

# 进入main.cpp所在目录
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/src

# vim修改文件
vim main.cpp

# 首先,修改输入文件路径和名称,将第22行的std::string filePath= "../data/vdec_h265_1frame_rabbit_1280x720.h265"; 修改为
std::string filePath= "../data/TownCentreXVID_1920_1080_25_AVC_H264.h264";

# 其次,修改输入视频大小
# 将第23行的const int inputWidth = 1280; 修改为
const int inputWidth = 1920;
# 将第24行的const int inputHeight = 720; 修改为
const int inputHeight = 1080;
# 这样才和我们的输入视频大小相匹配

# 最后修改解码设定,将第 40行的int32_t enType_ =0 ; 改为
int32_t enType_ =3 ;
# 参照注释,可知这对应H.264
/* 0:H265 main level
 * 1:H264 baseline level
 * 2:H264 main level
 * 3:H264 high level
 */

接下来,来运行试试!

# 确保已经切换到HwHiAiUser用户
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/scripts
# 注意下面命令运行时,会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86,如下图所示
bash sample_build.sh
bash sample_run.sh

最终程序运行成功截图:

运行速度很快,体验不错!我们到这个目录下可以看到生成的.yuv文件:

cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output

如下图所示,可以看到我们得到的10张图片

接下来,我们查看图片,在root用户下执行命令:

# 注意在root用户下执行,如果不是root用户,可执行su root进行切换
ffplay -f rawvideo -video_size 1920x1080 image1.yuv

可以看到,如下图片,注意这是依赖了MobaXterm的X Server

此时程序运行截图:

我们还可以查看其他yuv图片,注意到展示的图片有些色彩疑似有问题,暂时先不管了。

 2. 对yuv格式进行resize(输入是上一步得到的yuv格式文件)

 其实到这一步的话,就和第一次大作业的过程基本一致了,这也是此次作业的目的之一,巩固上次的学习成果,连续性还是很不错的,可见老师设计的时候也是经过深思熟虑和精心安排的,同时这种视频编解码、resize和图片编解码的操作是在计算机操作中很常见的,在AI推理和训练中也常用,非常有学习价值和意义,更重要的是,一般来说,都会配有专门的硬件电路来加速,这也是DVPP的作用。

  那这里,就选择image1.yuv来操作吧!

# 注意之前可能是root用户,这里我们通过su HwHiAiUser切换为HwHiAiUser用户
# 首先将image1.yuv拷贝到我们resize操作的数据输入目录
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output/image1.yuv /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/data

# 接下来修改运行脚本sample_run.sh,主要是输入图片的路径和resize的分辨率:
# 首先进入脚本所在路径
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/scripts

# vim修改文件第10行,修改为
running_command="./main ../data/image1.yuv 1920 1080 ./output/output.yuv 224 224 "
# 这表示我们处理的是./main ../data/image1.yuv文件,该文件尺寸为1920 x 1080,设置输出路径是./output/output.yuv ,输出文件outpu.yuv的大小是224 x 224

# 注意下面命令运行时,仍然会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86,如下图所示
bash sample_build.sh

bash sample_run.sh

resize后的文件为output.yuv,我们来看看

# 来到output.yuv保存路径
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/out/output

# 注意在root用户下执行,如果不是root用户,可执行su root进行切换
ffplay -f rawvideo -video_size 224x224 output.yuv

可以看到图片尺寸确实缩小了,而且没有绿边或黄边,这应该是因为DVPP的输入是符合前面提到的宽高对齐要求的。但要注意的是我们设置的resize大小224 x 224的宽度是不符合128对齐的。

应该没啥问题,接着来吧!

 3. resize后的yuv文件编码成jpg图片(输入是上一步得到的resize后的yuv格式文件)

# 注意之前可能是root用户,这里我们通过su HwHiAiUser切换为HwHiAiUser用户
# 将上一步生成的output.yuv拷贝到指定路径,方便后续jpeg编码
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/out/output/output.yuv /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/data


# 进行路径
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/scripts

# 修改main.cpp文件,执行输入yuv文件路径和大小
# 切换到main.cpp所在文件夹
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/src
# 修改文件
vim main.cpp
# 在第242行,将该行替换为如下:
PicDesc testPic = {"../data/output.yuv", 224, 224};

# 注意下面命令运行时,仍然会弹出架构选项,因为我们的CPU是x86架构的,所以这里选择x86
bash sample_build.sh

# 接下来,我们要将上一步得到的resize后的yuv文件拷贝过来作为输入
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/out/output/output.yuv /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/data/dvpp_output.yuv 

# 运行程序
bash sample_run.sh

接下来,到输出路径看看,之后下载到本地查看即可。因为MobaXterm很好的文件交互性和可视化,我们可以直接双击该输出文件,就能自动下载查看了

最终得到编码后的图片

至此,我们完成了全部流程,最终得到了编码后的,如上图所示的jpg文件。

应用第三弹

首先来看下要求

简单来说,就是利用所学,完成YOLOv3完整的推理过程!下面来逐步操作吧。

1. 完成模型转换

注意,模型转换要涉及处理模型输入数据的大小和格式,这一点要明确。这里先参照开发手册上提供的模型和配套教程走一遍,验证下流程。

先建一个文件夹用来保存整个过程的文件

mkdir yolov3_detection

# 接下来建立model文件夹,保存模型
mkdir model

# 接下来,下载模型和配置文件
wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/Yolov3/yolov3.caffemodel
wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/Yolov3/yolov3.prototxt
wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/Yolov3/aipp_nv12.cfg

运行截图:

接下来,参照指导,进行模型转换:

# 注意,这里使用的是官方给的命令,会导致转换的模型后缀为.om.om,不建议使用
atc --model=yolov3.prototxt --weight=yolov3.caffemodel --framework=0 --output=yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32.om --soc_version=Ascend310 --insert_op_conf=aipp_nv12.cfg

# 建议使用本命令,这样转换得到的模型是.om后缀
atc --model=yolov3.prototxt --weight=yolov3.caffemodel --framework=0 --output=yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32 --soc_version=Ascend310 --insert_op_conf=aipp_nv12.cfg

注意,参照教程这里的--output是以.om结尾,但是发现这会导致生成的模型是 yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32.om.om,即是以.om.om结尾,有点奇怪,不过不影响运行,毕竟只是个名字,但是这会影响到后续的执行,因为教程后续用的是

yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32.om

而我们实际生成的是

yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32.om.om

这在系统看来完全是两个不同的模型,因此,要注意统一名称,只要保持先后一致即可,这里我选择的是直接用实际生成的.om.om模型吧!

再次需要注意的是这里仅仅是对样例说明,如果将模型用于推理,则一定要用.om模型,如果再用.om.om模型就会报错(当然,也可能是权限不够,因为我们运行时,使用的是HwHiAiUser用户),因此,从规范和长远角度来说,应该用.om模型,我这里的选择用.om.om模型是不明智的,有些糟糕,建议大家直接用上方转换模型的第二条命令,直接得到.om模型,推荐!推荐!推荐!

这个模型转换过程资源消耗较大,需要稍等一下,运行成功截图:

接下来,使用使用msame工具推理,先来准备一下,这里官方提供了较为详细的教程,跟着做就行了:

git clone https://gitee.com/ascend/tools.git

export DDK_PATH=/home/HwHiAiUser/Ascend/ascend-toolkit/latest
export NPU_HOST_LIB=/home/HwHiAiUser/Ascend/ascend-toolkit/latest/acllib/lib64/stub

cd $HOME/tools/msame/
chmod +x build.sh

./build.sh g++ $HOME/tools/msame/out

cd out
# 注意,这里的--model和--output路径根据实际模型存放路径和你想输出的路径填写
./msame --model /home/HwHiAiUser/yolov3_detection/model/yolov3_framework_caffe_aipp_1_batch_1_input_int8_output_FP32.om.om --output /home/HwHiAiUser/yolov3_detection/model/msame_infer --outfmt TXT --loop 100

 

程序运行成功的部分截图:

可以到我们指定的输出路径下看到生成的结果文件

至此的整个过程按照开发文档中提供的教程操作即可,还是比较简单的。

2. 结合所学,完成模型推理

这里参考了官仓的样例,基于上述得到的模型进行推理,完整代码会提交在作业帖中,并附有README,分为模型准备和转换、编译和运行三部分,正常运行推理后可得到结果

至此,基本应用开发就完成了,算是初识,如果日后用到,算是有个印象,但想深入研究的话,还是要多看看文档,了解底层硬件,特别是这种应用,根据硬件特性做针对性加速很重要。

与ModelArts相关的一些

这里主要是在ModelArts平台,基于华为Ascend 910解决训练网络精度调优的问题,可参见训练网络精度调优精讲与实战获取更多详情。

前情提要

1. PyCharm常用操作和配置ModelArts插件使用,官方文档和介绍较为详细,这里不在叙述

2. 需要说明的是,我是用的插件版本是3.3.5,比教程中的应该是新一些,所以有些配置不同,主要是两点:(1)Image Path按照教程设置无效,导致无法启动训练作业,直接不设置就行了;(2)Data Path,即数据集存放路径,必须是本人账号的桶路径才行(也可能是因为教程中的桶区域不是北京四),所以无法按照教程设置,我下载数据集后,上传到自己的桶中,并指定路径即可。

具体操作

1. 直接运行,可以得到:

性能指标约为sec / step: 0.01,即每训练一步耗费的时间约为0.01秒,这应该是在纯CPU运行的情况下,即全部跑在鲲鹏处理器上。从负载图上,也能看到基本都是CPU在承担任务:

进行NPU迁移

参照社区文档和老师的讲解,可以较好完成模型迁移,迁移后运行:

可以看到性能约为sec / step :0.002,提升了5倍,NPU果然效果显著,我想这还不是极限,因为目前仅迁移,还没有做性能调优,从系统负载图,也能看到NPU在承担计算任务了,但利用率不是很高,有很大提升空间。

大约15分40秒的时间,模型训练完成,如图所示:

性能和精度还是不错的。

2. 验证完成NPU迁移

这里要说明一下: 因不习惯使用ModelArts插件,所以我下载了数据集和代码,并进行了修改,已适配ModelArts的NoteBook的Ascend环境,故以下操作都是在ModelArts的NoteBook运行,而非训练作业。ModelArts的NoteBook的规格为

 

notebook.png

 

运行日志保存在./test/output//train_.log中,可以查看信息,我们来看看Ascend 910运行情况:

 

 

npu-smi.png我们可以看到NPU的AI Core的利用率、Memory-Usage,这都显示已经运行在NPU上了,这里的利用率过低是因为同时进行了溢出检测等操作,而且这是同时在跑两个程序。如果不进行溢出检测,仅运行一个程序就好多了,如下图所示

npu-smi-no-overflow.png

3. 混合精度 + Loss Scale 使能

这里,我使用了静态Loss Scale,设置loss_scale = 1024,方便后续附加作业打印

4. 完成溢出检测使能

可以到overflow文件夹下查看信息,大体如图所示:

overflow.png

5. 附加题,使能 lossscale 后,打印出 loss scale 的具体值

查看./test/output//train_.log,可以看到打印的loss scale数值

loss_scale.png

至此,基本完成了。还是挺有意思的!

好了,到这里就要结束了,如果有问题,可联系tjulitianyi@163.com或在下方评论,谢谢。

 

【与云原生的故事】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/345260

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。