PyTorch常用代码

简介

之前提到过PyTorch进行深度训练是一套总的来说较为固定的流程,因此学习一些常用的代码段是很有必要的,本文整理了一些常用的代码段,当然最合适的参考资料依然是官方文档。

框架配置

包导入与信息查看

这部分主要是PyTorch的版本查看、本机是否可以使用GPU训练、可用的GPU数目等,具体如下代码,已经备注详细。

import torch# PyTorch版本
print(torch.__version__)
# 是否可用GPU
print(torch.cuda.is_available())
# 可用的GPU数目
print(torch.cuda.device_count())
# 可用的第一个GPU(默认从0编号开始)
print(torch.cuda.get_device_name(0) if torch.cuda.device_count() > 0 else "no gpu")

固定随机数种子

在硬件设备不同的情况下,完整的复现是比较困难的,但是同一个设备上应该尽可能保证可复现性,主要做法就是在程序开始之前固定随机数种子,包括Numpy、Torch的随机数种子。

import numpy as np
import torchnp.random.seed(0)
torch.manual_seed(0)
torch.cuda.manual_seed_all(0)

显卡设置

单显卡设置如下。

import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

指定多张显卡设置(下面代码示例指定0和1号显卡)。

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'

张量运算

PyTorch总共提供了9种CPU张量类型以及对应的GPU张量类型,这部分主要是张量的一些常用操作,不包括基本的张量创建之类的API。

张量信息

对于一个张量,有时代码调试时关注其基本信息如维度、数据类型。

import torcht = torch.randn(2, 3, 4, 4)
# 张量的数据类型
print(t.type())
# 张量的维度信息
print(t.size())
# 张量的维度数量
print(t.dim())

数据类型转换

PyTorch经常涉及到不同数据类型之间的转换,尤其是CPU数据转为GPU数据,有时候为了方便运行也需要设置默认的数据类型(在PyTorch中Float类型远超Double类型的速度)。

import torch# 设置默认数据类型
torch.set_default_tensor_type(torch.FloatTensor)t = torch.randn(1)
print(t.type())
# 转为GPU数据类型
t = t.cuda()
# 转为CPU数据类型
t = t.cpu()
t = t.float()
t = t.long()

Numpy转换

除了字符类型,其他类型的张量都支持转换为Numpy的数组,也支持Numpy的数组转为PyTorch的张量。

import torcht = torch.randn(1, 2, 3)
# Tensor转ndarray
t = t.cpu().numpy()
# ndarray转tensor
t = torch.from_numpy(t).float()

PIL转换

PyTorch中图片采用[N,C,H,W]的顺序存放,且数值在[0,1]之间,其他任何图像库读取的图片要在PyTorch中使用必须规范为该格式。这个转换可以自己通过张量变换完成,也可以直接调用torchvision封装好的函数。

import torch
import torchvision
import numpy as np
from PIL import Image# tensor转pil image
t = torch.randn(32, 3, 224, 224)
image = Image.fromarray(torch.clamp(t*255, min=0, max=255).byte().permute(1, 2, 0).cpu().numpy())
image = torchvision.transforms.functional.to_pil_image(t)# pil image转tensor
path = 'test.jpg'
tensor = torch.from_numpy(np.asarray(Image.open(path).convert('RGB'))).permute(2, 0, 1).float() / 255
tensor = torchvision.transforms.functional.to_tensor(Image.open(path))

单元素张量值获取

有时候对于loss这些值虽然结果是一个张量,但是这个张量其实就只含有一个值,这种张量通过item方法取出这个值。

import torcha = torch.randn(1)
print(a)
print(a.item())

模型操作

模型定义

主要的注意点就是继承自nn.Module类且需要定义前向传播运算,下面是个简单的示例,具体可以查看我之前关于模型的文章。

import torch
import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=(3, 3))self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3)self.pool2 = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(64*54*54, 256)self.fc2 = nn.Linear(256, 128)self.fc3 = nn.Linear(128, 101)def forward(self, x):x = self.pool1(F.relu(self.conv1(x)))x = self.pool2(F.relu(self.conv2(x)))x = x.view(-1, 64*54*54)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x

模型总参数量

对所有层参数数目求和即可。

model = Net()
num_parameters = sum(torch.numel(parameter) for parameter in model.parameters())
print(num_parameters)

模型参数查看

通过model.state_dict()或者model.named_parameters()查看所有可训练参数,包括父类参数。

params = list(model.named_parameters())
(name, param) = params[0]
print(name)
print(param.grad)

模型可视化

通过pytorchviz或者pytorch-summary两个工具进行结构可视化。

模型权重初始化

这方面我在之前的博客中提到过,一般区分不同的层进行不同的初始化,例如模型中定义如下的成员函数。尤其注意,model.modules()和model.children()都会返回模型的成员层,但是model.modules()会迭代地遍历模型的所有子层,而model.children()只会遍历模型下的一层。

def init_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.xavier_normal_(m.weight.data)if m.bias is not None:m.bias.data.zero_()elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()elif isinstance(m, nn.Linear):nn.init.normal_(m.weight.data, 0, 0.01)m.bias.data.zero_()

提取模型某层

model.modules()会返回模型中所有模块的迭代器,它能够访问到最内层。

new_model = nn.Sequential()
for layer in model.named_modules():if isinstance(layer[1],nn.Conv2d):new_model.add_module(layer[0],layer[1])

使用预训练模型参数

使用预训练模型一般是加载模型训练好的参数,大多时候训练到部署还会涉及到GPU模型参数加载到CPU模型上。

model.load_state_dict(torch.load('model.pkl'), strict=False)
model.load_state_dict(torch.load('model.pth', map_location='cpu'))

数据处理

视频基本信息

通过opencv-python得到视频的信息。

import cv2
video = cv2.VideoCapture('v.mp4)
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
num_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(video.get(cv2.CAP_PROP_FPS))
video.release()

图像常用预处理

各种处理方法的含义我在数据准备的博客中介绍过。

import torchvision
train_transform = torchvision.transforms.Compose([torchvision.transforms.RandomResizedCrop(size=224,scale=(0.08, 1.0)),torchvision.transforms.RandomHorizontalFlip(),torchvision.transforms.ToTensor(),torchvision.transforms.Normalize(mean=(0.485, 0.456, 0.406),std=(0.229, 0.224, 0.225)),
])
val_transform = torchvision.transforms.Compose([torchvision.transforms.Resize(256),torchvision.transforms.CenterCrop(224),torchvision.transforms.ToTensor(),torchvision.transforms.Normalize(mean=(0.485, 0.456, 0.406),std=(0.229, 0.224, 0.225)),
])

分类模型训练及验证

训练的大致流程代码。

for epoch in range(epochs):# 训练集训练train_loss = 0.0correct = 0.0total = 0.0for step, data in enumerate(train_loader):x, y = dataout = model(x)loss = criterion(out, y)optimizer.zero_grad()loss.backward()optimizer.step()_, pred = torch.max(out.data, 1)total += y.size(0)correct += (pred == y).squeeze().sum().numpy()train_loss += loss.item()if step % 100 == 0:print("epoch", epoch, "step", step, "loss", loss.item())train_acc = correct / total# 验证集验证valid_loss = 0.0correct = 0.0total = 0.0for step, data in enumerate(valid_loader):model.eval()x, y = dataout = model(x)out.detach_()loss = criterion(out, y)_, pred = torch.max(out.data, 1)valid_loss += loss.item()total += y.size(0)correct += (pred == y).squeeze().sum().numpy()valid_acc = correct / totalscheduler.step(valid_loss)writer.add_scalars('loss', {'train_loss': train_loss, 'valid_loss': valid_loss}, epoch)writer.add_scalars('accuracy', {'train_acc': train_acc, 'valid_acc': valid_acc}, epoch)

自定义损失

PyTorch中损失也是继承自nn.Module类,通过forward方法计算损失值。

from torch import nn
class MyLoss(nn.Moudle):def __init__(self):super(MyLoss, self).__init__()def forward(self, x, y):loss = torch.mean((x - y) ** 2)return loss

梯度裁减

这是一个防止梯度爆炸的有效手段,但也会带来一些问题。

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=20)

其他

模型状态

训练和验证是对模型的要求是不一样的,通过模型前向计算输出前调整模型状态。(通过model.train()model.eval()进行调整。)

交叉熵损失

PyTorch中的交叉熵损失不需要经过Softmax,因为其内置了softmax计算。同时,也不需要进行onehot编码,内置了。

梯度置零

model.zero_grad()会把整个模型的参数的梯度都归零, 而optimizer.zero_grad()只会把传入其中的参数的梯度归零。

反向传播

loss.backward()进行反向传播之前要用用optimizer.zero_grad()清除累积的梯度。

GPU数据IO

尽量减少CPU和GPU之间的数据交互,因为这种交互很费时间。如要获得每个batch的loss 和acc,可以将它们累积在GPU中等整个epoch结束后一起传输到CPU(使用loss.cpu()方法)会比每个batch 都进行一次GPU到CPU的IO快很多。

补充说明

本文主要介绍PyTorch中常用的一些代码段,都是比较实用的代码,部分参考PyTorch CookBook。本文涉及到的所有代码都可以在我的Github找到,欢迎star或者fork。

PyTorch-常用代码相关推荐

  1. 收藏!PyTorch常用代码段合集

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:Jack Stark,来源:极市平台 来源丨https://zhu ...

  2. PyTorch常用代码段合集

    ↑ 点击蓝字 关注视学算法 作者丨Jack Stark@知乎 来源丨https://zhuanlan.zhihu.com/p/104019160 极市导读 本文是PyTorch常用代码段合集,涵盖基本 ...

  3. 【深度学习】PyTorch常用代码段合集

    来源 | 极市平台,机器学习算法与自然语言处理 本文是PyTorch常用代码段合集,涵盖基本配置.张量处理.模型定义与操作.数据处理.模型训练与测试等5个方面,还给出了多个值得注意的Tips,内容非常 ...

  4. pytorch list转tensor_PyTorch 52.PyTorch常用代码段合集

    本文参考于: Jack Stark:[深度学习框架]PyTorch常用代码段​zhuanlan.zhihu.com 1. 基本配置 导入包和版本查询: import torch import torc ...

  5. 收藏 | PyTorch常用代码段合集

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者丨Jack Stark@知乎 来源丨https://zh ...

  6. 深度盘点:PyTorch常用代码段合集

    本文是PyTorch常用代码段合集,涵盖基本配置.张量处理.模型定义与操作.数据处理.模型训练与测试等5个方面,还给出了多个值得注意的Tips,内容非常全面. PyTorch最好的资料是官方文档.本文 ...

  7. PyTorch 常用代码段整理合集

    PyTorch 常用代码段整理合集 来源:知乎 作者:张皓 众所周知,程序猿在写代码时通常会在网上搜索大量资料,其中大部分是代码段.然而,这项工作常常令人心累身疲,耗费大量时间.所以,今天小编转载了知 ...

  8. 赶快收藏,PyTorch 常用代码段PDF合辑版来了

    前段时间我分享了 PyTorch 常用代码段合集,涵盖基本配置.张量处理.模型定义与操作.数据处 理.模型训练与测试等5个方面,还给出了多个值得注意的Tips. 这篇文章发布后,收到了很多朋友的喜爱和 ...

  9. Pytorch 常用代码

    Pytorch 常用代码 本文代码基于PyTorch 1.0版本,需要用到以下包 import collections import os import shutil import tqdmimpor ...

  10. pytorch常用代码

    20211228 https://mp.weixin.qq.com/s/4breleAhCh6_9tvMK3WDaw 常用代码段 本文代码基于 PyTorch 1.x 版本,需要用到以下包: impo ...

最新文章

  1. Computer Systems A Programmer’s Perspective ----阅读翻译日志
  2. Struts 学习笔记1 -Struts Framework 概览
  3. ElasticSearch优化系列一:集群节点规划
  4. Android So简单加固
  5. 岗位推荐 | 阿里巴巴达摩院招聘自然语言处理、机器翻译算法专家
  6. Linux中的防火墙----iptables
  7. Jenkins cannot restart itself as currently configured
  8. python3.8.4rc1_Python3.8.4rc1 官方正式版
  9. SAP License:SAP顾问是如何炼成的——你适合做SAP顾问吗?
  10. python编程语言-python编程语言基础知识总结
  11. 烟台大学举办首届ACM程序设计大赛
  12. 计算机与打印机怎么连接,如何连接打印机,教您电脑如何与打印机连接
  13. 刻意练习+一万小时定律+异类
  14. 单片机 串口通信实验
  15. 渗透之——使用Metasploit编写绕过DEP渗透模块
  16. 英伟达RTX 4070最新测评来了!光追效果更棒,但仅限于2k游戏
  17. cuda/cudnn/cuda 10.1安装教程
  18. c语言桶是什么意思,桶排序算法
  19. RTMP直播推流(一)视频推流
  20. OpenGLES glUniform1i用法

热门文章

  1. 关于Execution 表达式
  2. redis的安装及springDataRedis
  3. spring基于XML的声明式事务控制-配置步骤
  4. 实现runable接口创建线程
  5. SpringBoot_web开发-简介
  6. navicat怎么安装mysql数据库_【20170825】从零开始学SQL数据库 安装mysql与navicat,开始练习...
  7. eof怎么结束输入_SimRobot算法社第二次活动圆满结束啦!
  8. 同步与异步、并行与并发、阻塞与挂起
  9. PyTorch深度学习实践06
  10. SIMD学习 -- 用SSE2指令作点乘和累加计算