【CANN训练营第三季】Ascend平台体验Pytorch笔记

news2024/11/18 9:28:16

模型迁移

手册地址:https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/600alpha002/ptmoddevg/ptmigr/ptmigr_000009.html

主要修改:

导入相关库

import torch
import torch_npu  #1.8.1及以上需要

指定NPU设备

通过device()指定

原始代码:

device = torch.device('cuda:0')
torch.cuda.set_device(device)

修改为

device = torch.device('npu:0')
torch.npu.set_device(device)

torch.cuda

原始代码:

torch.cuda.xx()
tensor.to('cuda:0')

修改为

torch.npu.xx()
tensor.to('npu:0')

model.cuda

原始代码

model = model.cuda()

修改为

model = model.npu()

损失函数

原始代码

cirterion = nn.CrossEntropyLoss().cuda()

修改后

cirterion = nn.CrossEntropyLoss().npu()

训练集

原始代码

device = torch.device('cuda:0')
images = images.to(device)
target = target.to(device)

修改后

device = torch.device('npu:0')
images = images.to(device)
target = target.to(device)

开启混合精度

APEX

基于NPU芯片的架构特性,会涉及到混合精度训练,即混合使用float16和float32数据类型的应用场景。使用float16代替float32有如下优点:

  • 对于中间变量的内存占用更少,节省内存的使用。
  • 因内存使用会减少,所以数据传出的时间也会相应减少。
  • float16的计算单元可以提供更高的计算性能。

但是,混合精度训练受限于float16表达的精度范围,单纯将float32转换成float16会影响训练收敛情况。为了保证部分计算使用float16来进行加速的同时能保证训练收敛,这里采用混合精度模块APEX来达到以上效果。混合精度模块APEX是一个集优化性能、精度收敛于一身的综合优化库。

引入库

from apex import amp

初始化AMP

model, optimizer = amp.initialize(model, optimizer, combine_grad=True)

记反向传播.backward()发生的位置,这样AMP就可以进行Loss Scaling并清除每次迭代的状态
原始代码:

loss = criterion() 
loss.backward() 
optimizer.step()

修改后

loss = criterion() 
with amp.scale_loss(loss, optimizer) as scaled_loss:     
    scaled_loss.backward() 
optimizer.step()

切换混合精度模式

model, optimizer = amp.initialize(model, optimizer, opt_level="O2") #配置功能模块参数opt_level

开关分布式训练性能

model, optimizer = amp.initialize(model, optimizer, combine_ddp=True) #配置运算加速参数combine_ddp

AMP

AMP功能在昇腾PyTorch1.8.1版本及以上可用,类似于APEX AMP的O1模式(动态 Loss Scale),也是通过将部分算子的输入转换为FP16类型来实现混合精度的训练。

使用场景

  • 典型场景
  • 梯度累加场景
  • 多Models,Losses,and Optimizers场景
  • DDP场景(one NPU per process)

NPU上使用方法

  1. 模型从GPU适配到NPU时,需要将代码torch.cuda.amp修改为torch_npu.npu.amp。
  2. 当前PyTorch1.8.1 AMP工具中GradScaler增加了dynamic选项(默认为True),设置为False时,AMP能支持静态Loss Scale。

profiling性能调优

文档地址:https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/600alpha002/developmenttools/devtool/atlasprofiling_16_0089.html

PyTorch Profiling

代码段:

# 使用ascend-pytorch适配的Profiling接口,即可获得,推荐只运行一个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()
# 打印Profiling结果信息
print(prof)
# 导出chrome_trace文件到指定路径
output_path = '/home/HwHiAiUser/profile_data.json'
prof.export_chrome_trace(output_path)

数据解析

查看profiling数据
在Chrome浏览器中输入“chrome://tracing”地址,将profile_data.json文件拖到空白处打开,通过键盘上的快捷键(w:放大,s:缩小,a:左移,d:右移)进行查看
image.png
具体性能数据分析步骤如下:

  1. 单击图片中①所示按钮。
  2. 框选图片中②(用户所需数据)所示timeline数据。
  3. 单击图片中③所示按钮,详细数据信息如④所示。
  4. 根据④中selftime数据从大到小排序,可找出TopN耗时算子信息,分析模型中存在的性能问题。

其他功能

获取算子输入tensor的shape信息。

# 添加record_shapes参数,获取算子输入tensor的shape信息
with torch.autograd.profiler.profile(use_npu=True, record_shapes=True) as prof:
    # 添加模型计算过程
print(prof)

获取使用NPU的内存信息。

# 添加Profiling参数,获取算子内存占用信息
with torch.autograd.profiler.profile(use_npu=True, profile_memory=True) as prof:
    # 添加模型计算过程
print(prof)

获取简洁的算子性能信息

# 添加use_npu_simple参数,获取简洁的算子信息
with torch.autograd.profiler.profile(use_npu=True, use_npu_simple=True) as prof:
# 添加模型计算过程
output_path = '/home/HwHiAiUser/profile_data.json'
# 导出chrome_trace文件到指定路径
prof.export_chrome_trace(output_path)

CANN Profiling

代码段

cann_profiling_path = './cann_profiling'
if not os.path.exists(cann_profiling_path):
    os.makedirs(cann_profiling_path)
with torch.npu.profile(cann_profiling_path):
    out = model(input_tensor)
    loss = loss_func(out,target)
    loss.backward()
    optimizer.zero_grad()
    optimizer.step()
exit()

数据解析与导出参考手册:https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/600alpha002/developmenttools/devtool/atlasprofiling_16_0095.html

代码示例

原始代码

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
 
 
lr = 0.01 #学习率
momentum = 0.5
log_interval = 10 #跑多少次batch进行一次日志记录
epochs = 10
batch_size = 64
test_batch_size = 1000
 
 
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Sequential(  # input_size=(1*28*28)
            nn.Conv2d(1, 6, 5, 1, 2),  # padding=2保证输入输出尺寸相同
            nn.ReLU(),  # input_size=(6*28*28)
            nn.MaxPool2d(kernel_size=2, stride=2),  # output_size=(6*14*14)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),  # input_size=(16*10*10)
            nn.MaxPool2d(2, 2)  # output_size=(16*5*5)
        )
        self.fc1 = nn.Sequential(
            nn.Linear(16 * 5 * 5, 120),
            nn.ReLU()
        )
        self.fc2 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )
        self.fc3 = nn.Linear(84, 10)
 
    # 定义前向传播过程,输入为x
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # nn.Linear()的输入输出都是维度为一的值,所以要把多维度的tensor展平成一维
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x #F.softmax(x, dim=1)
 
 
 
def train(epoch):  # 定义每个epoch的训练细节
    model.train()  # 设置为trainning模式
    for batch_idx, (data, target) in enumerate(train_loader):
        data = data.to(device)
        target = target.to(device)
        data, target = Variable(data), Variable(target)  # 把数据转换成Variable
        optimizer.zero_grad()  # 优化器梯度初始化为零
        output = model(data)  # 把数据输入网络并得到输出,即进行前向传播
        loss = F.cross_entropy(output,target)  #交叉熵损失函数
        loss.backward()  # 反向传播梯度
        optimizer.step()  # 结束一次前传+反传之后,更新参数
        if batch_idx % log_interval == 0:  # 准备打印相关信息
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))
 
 
def test():
    model.eval()  # 设置为test模式
    test_loss = 0  # 初始化测试损失值为0
    correct = 0  # 初始化预测正确的数据个数为0
    for data, target in test_loader:
 
        data = data.to(device)
        target = target.to(device)
        data, target = Variable(data), Variable(target)  #计算前要把变量变成Variable形式,因为这样子才有梯度
 
        output = model(data)
        test_loss += F.cross_entropy(output, target, size_average=False).item()  # sum up batch loss 把所有loss值进行累加
        pred = output.data.max(1, keepdim=True)[1]  # get the index of the max log-probability
        correct += pred.eq(target.data.view_as(pred)).cpu().sum()  # 对预测正确的数据个数进行累加
 
    test_loss /= len(test_loader.dataset)  # 因为把所有loss值进行过累加,所以最后要除以总得数据长度才得平均loss
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))
 
 
 
if __name__ == '__main__':
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') #启用GPU
 
    train_loader = torch.utils.data.DataLoader(  # 加载训练数据
        datasets.MNIST('./mnist_data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))  #数据集给出的均值和标准差系数,每个数据集都不同的,都数据集提供方给出的
                       ])),
        batch_size=batch_size, shuffle=True)
 
    test_loader = torch.utils.data.DataLoader(  # 加载训练数据,详细用法参考我的Pytorch打怪路(一)系列-(1)
        datasets.MNIST('./mnist_data', train=False, transform=transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.1307,), (0.3081,)) #数据集给出的均值和标准差系数,每个数据集都不同的,都数据集提供方给出的
        ])),
        batch_size=test_batch_size, shuffle=True)
 
    model = LeNet()  # 实例化一个网络对象
    model = model.to(device)
    optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)  # 初始化优化器
 
    for epoch in range(1, epochs + 1):  # 以epoch为单位进行循环
        train(epoch)
        test()
 
    torch.save(model, 'model.pth') #保存模型

修改后代码

import torch
import torch_npu
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable

import os

from apex import amp
 
lr = 0.01 #学习率
momentum = 0.5
log_interval = 10 #跑多少次batch进行一次日志记录
epochs = 1
batch_size = 64
test_batch_size = 1000
 
 
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Sequential(  # input_size=(1*28*28)
            nn.Conv2d(1, 6, 5, 1, 2),  # padding=2保证输入输出尺寸相同
            nn.ReLU(),  # input_size=(6*28*28)
            nn.MaxPool2d(kernel_size=2, stride=2),  # output_size=(6*14*14)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),  # input_size=(16*10*10)
            nn.MaxPool2d(2, 2)  # output_size=(16*5*5)
        )
        self.fc1 = nn.Sequential(
            nn.Linear(16 * 5 * 5, 120),
            nn.ReLU()
        )
        self.fc2 = nn.Sequential(
            nn.Linear(120, 84),
            nn.ReLU()
        )
        self.fc3 = nn.Linear(84, 10)
 
    # 定义前向传播过程,输入为x
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # nn.Linear()的输入输出都是维度为一的值,所以要把多维度的tensor展平成一维
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x #F.softmax(x, dim=1)
 
 
 
def train(epoch):  # 定义每个epoch的训练细节
    model.train()  # 设置为trainning模式
    for batch_idx, (data, target) in enumerate(train_loader):
        data = data.to(device)
        target = target.to(device)
        data, target = Variable(data), Variable(target)  # 把数据转换成Variable
        #optimizer.zero_grad()  # 优化器梯度初始化为零
        #output = model(data)  # 把数据输入网络并得到输出,即进行前向传播
        #loss = F.cross_entropy(output,target)  #交叉熵损失函数
        #loss.backward()  # 反向传播梯度
        #with amp.scale_loss(loss, optimizer) as scaled_loss:     
        #    scaled_loss.backward() 
        #optimizer.step()  # 结束一次前传+反传之后,更新参数
        
        # pytorch_profiling代码段
        with torch.autograd.profiler.profile(use_npu=True) as prof:
            out = model(data)
            loss = F.cross_entropy(out,target)
            retain_graph=True
            with amp.scale_loss(loss, optimizer) as scaled_loss:
                scaled_loss.backward() 
            optimizer.zero_grad()
            optimizer.step()
        
        # CANN profiling代码片段
        cann_profiling_path = './cann_profiling'
        if not os.path.exists(cann_profiling_path):
            os.makedirs(cann_profiling_path)
        with torch.npu.profile(cann_profiling_path):
            out = model(data)
            loss = F.cross_entropy(out,target)
            with amp.scale_loss(loss, optimizer) as scaled_loss:
                scaled_loss.backward() 
            optimizer.zero_grad()
            optimizer.step()
        exit()
        
        if batch_idx % log_interval == 0:  # 准备打印相关信息
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))
    # 打印Profiling结果信息
    #print(prof)
    ## 导出chrome_trace文件到指定路径
    #output_path = './profile_data.json'
    #prof.export_chrome_trace(output_path)
 
 
def test():
    model.eval()  # 设置为test模式
    test_loss = 0  # 初始化测试损失值为0
    correct = 0  # 初始化预测正确的数据个数为0
    for data, target in test_loader:
 
        data = data.to(device)
        target = target.to(device)
        data, target = Variable(data), Variable(target)  #计算前要把变量变成Variable形式,因为这样子才有梯度
 
        output = model(data)
        test_loss += F.cross_entropy(output, target, size_average=False).item()  # sum up batch loss 把所有loss值进行累加
        pred = output.data.max(1, keepdim=True)[1]  # get the index of the max log-probability
        correct += pred.eq(target.data.view_as(pred)).cpu().sum()  # 对预测正确的数据个数进行累加
 
    test_loss /= len(test_loader.dataset)  # 因为把所有loss值进行过累加,所以最后要除以总得数据长度才得平均loss
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))
 
 
 
if __name__ == '__main__':
    #启用NPU
    device = torch.device('npu:0')
    torch.npu.set_device(device)
 
    train_loader = torch.utils.data.DataLoader(  # 加载训练数据
        datasets.MNIST('./mnist_data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))  #数据集给出的均值和标准差系数,每个数据集都不同的,都数据集提供方给出的
                       ])),
        batch_size=batch_size, shuffle=True)
 
    test_loader = torch.utils.data.DataLoader(  # 加载训练数据,详细用法参考我的Pytorch打怪路(一)系列-(1)
        datasets.MNIST('./mnist_data', train=False, transform=transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.1307,), (0.3081,)) #数据集给出的均值和标准差系数,每个数据集都不同的,都数据集提供方给出的
        ])),
        batch_size=test_batch_size, shuffle=True)
 
    model = LeNet()  # 实例化一个网络对象
    model = model.to(device)
    optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)  # 初始化优化器
    
    model, optimizer = amp.initialize(model, optimizer, combine_grad=True) #初始化amp
 
    for epoch in range(1, epochs + 1):  # 以epoch为单位进行循环
        train(epoch)
        test()
 
    torch.save(model, 'model.pth') #保存模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107284.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDBC编程步骤、JDBC API详解和数据库连接池

前言: JDBC 就是使用Java语言操作关系型数据库的一套API ,全称:( Java DataBase Connectivity ) Java 数据库连接。官方(sun公司)定义的一套操作所有关系型数据库的规则,即 接口各个数据库厂商去实现这套…

工具及方法 - Process Explorer以及类似工具,用来获取系统运行的进程信息

下载Process explorer: Process Explorer - Sysinternals | Microsoft Learn Process explorer简介 有没有想过哪个程序打开了一个特定的文件或目录?现在你可以找到了。Process Explorer向你显示关于进程打开或加载的句柄和DLL的信息。 Process Explore…

[Python图像处理] 使用 HSV 色彩空间检测病毒对象

使用 HSV 色彩空间检测病毒对象前言检测病毒对象相关链接前言 在本节中,我们将学习如何使用 OpenCV 在 HSV 色彩空间中使用特定颜色检测感兴趣对象。我们需要通过指定颜色值范围识别和提取感兴趣的对象,使用具有病毒的血细胞图像,我们的目标…

Python 自动化测试(五): Pytest 结合 Allure 生成测试报告

本文节选自霍格沃玆测试学院测试开发内部教材,进阶学习文末加群! 测试报告在项目中是至关重要的角色,一个好的测试报告: 可以体现测试人员的工作量; 开发人员可以从测试报告中了解缺陷的情况; 测试经理可…

7.Linux实用操作(2)

文章目录零、学习目标一、进程管理1、概念2、查看进程3、查看指定进程4、关闭进程二、主机状态1、查看系统资源占用2、top命令内容详解3、top命令选项4、top交互式选项5、磁盘信息监控三、上传、下载1、上传、下载2、rz、sz命令四、压缩、解压1、压缩格式3、tar命令4、tar 命令…

后端开发浅学react

博客笔记来自于学习 柴柴老师在b站分享的react学习视频,仅供学习参考,学习视频是来自于b站的:柴柴_前端教书匠,视频链接:React入门到实战(2022全网最新)_哔哩哔哩_bilibili 和 react官网 开始 – React …

谁会嫌钱多啊,最适合学生党的Python兼职攻略以及接私活经验

大家好,我是小八 这次我想谈谈一个非常热门的话题,就是如何在学习python的同时去赚钱。在这篇文章中,你会学习到如何通过学习python来赚取副业收入。 相信大家都对钱感兴趣吧,如果你和马云爸爸对钱不敢兴趣的话,那这…

Lambda表达式从用到底层原理

文章目录前言一、lambda函数基本使用参数列表返回类型函数体捕获列表值捕获引用捕获隐式捕获混合方式捕获修改值捕获变量的值异常说明二、lambda表达式使用的注意事项避免默认捕获模式三、lambda表达式底层实现原理采用值捕获采用引用捕获前言 lambda式作为一种创建函数对象的…

Python tkinter -- 第18章 画布控件之多边形

18.2.19 create_polygon(coords, **options) 根据 coords 给定的坐标,在画布上绘制一个多边形。 (1)coords:给定多边形的坐标 (2)options:选项的具体含义: 选项含义activedash当鼠标…

JavaEE- JVM八股文(JVM垃圾回收机制GC)

JVM垃圾回收的目标:主要针对内存中的堆空间进行垃圾回收。 Java中,大量的内存都在堆中。 程序计数器:固定大小,不涉及释放 栈:函数执行完毕,对应栈的空间就自动释放了,不需要垃圾回收 方法区&…

07-Golang中标识符的命名规则

Golang中标识符的命名规则标识符概念标识符的命名规则保留关键字介绍预定义标识符介绍标识符命名注意事项标识符概念 1.Golang对各种变量、方法等命名时使用的字符序列称为标识符 2.凡是自己可以起名字的地方都叫标识符 标识符的命名规则 1.由26个英文字母大小写&#xff0…

华为云桌面之下的“冰山”:技术底座x繁荣生态加速模式进化

在新兴技术迭代升级持续加速的背景下,很多产品类别的内涵和外延都在不断演进——虽然名字没什么变化,但实际所指已有云泥之别。 “云桌面”即是如此。从早期的无盘工作站,到VDI、IDV和VOI等技术流派的群雄并起,云桌面的江湖总是“…

linux第七章---管道、环境变量、常用命令

1.管道 1.1概念: 管道类似于文件重定向,可以将前一个命令的stdout重定向到下一个命令的stdin。 1.2要点: 管道命令仅处理stdout,会忽略stdeer。管道右边的命令必须要能接受stdin.多个管道命令可以串联。 1.3与文件重定向的区…

Java平衡树之查找树的详解(1)

1.平衡树 之前我们学习过二叉查找树,发现它的查询效率比单纯的链表和数组的查询效率要高很多,大部分情况下,确实是这样的,但不幸的是,在最坏情况下,二叉查找树的性能还是很糟糕。例如我们依次往二叉查找树中…

c语言预处理(万字解析)

预处理一.总体概述1.注释去除2.宏替换二.宏定义(宏替换类型)1.数值宏常量2.字符串宏常量3.用宏定义注释符号4.用宏定义表达式(难点)1.第一种情况2.第二种情况5.#undef(宏的有效范围)1.两个问题2.#undef的使…

FLStudio2023水果软件哪个版本好用?功能区别对比

FL Studio是一款功能非常强大的音乐创作编辑软件它就是FL Studio(水果软件)。使用FL Studio中文版可以轻松帮我们制作自己的音乐唱片,拥有强大且专业的编曲混音创作工具,有需要的朋友不要错过。 水果,全称Fruity Loop Studio,简称…

量子计算(十六):其他类型体系的量子计算体系

文章目录 其他类型体系的量子计算体系 一、离子阴量子计算 二、原子量子计算 三、核自旋量子计算 四、拓扑量子计算 其他类型体系的量子计算体系 一、离子阴量子计算 离子研量子计算在影响范围方面仅次于超导量子计算。早在2003年,基于离子阴就可以演示两比特…

“转行做程序员”很难?这里有4个重要建议

近几年来,传统行业多处于经济下行,加上互联网行业的赚钱效应,想要转行到这一行的人越来越多,其中程序员这个行业更是很多人梦寐以求的。 但另一方面,我们也发现,这些想要转行的同学们往往会遇到很多困扰。…

推荐今日 火火火火 的开源项目

本期推荐开源项目目录:1. coding-interview-university2. 前端后台管理模板3. 钉钉聊天机器人4. 基于 ChatGPT 的 Neovim 插件5. 开源的分布式社交网络平台6. 分析社交媒体内容7. 用于绘制流程图的库01coding-interview-university这是一个汇集了软件工程师面试中常…

2023跨年代码(烟花+背景音乐)

文章目录前言效果展示使用方法源码学习HTML代码CSS代码前言 时光荏苒,白驹过隙。2022这一年又在忙碌中度过了,过去的一年,我们同努力,我们共欢笑,每一次成功都蕴藏着我们辛勤的劳动。 新的一年即将来到,我…