PyTorch-共通コード

PyTorch共通コード

簡単な紹介

一般にPyTorch深トレーニングはそうもちろん、最も適切な基準物質がまだ、我々はいくつかの共通のコード部分をコンパイルし、いくつかの共通コード・セグメントが必要である学習、比較的固定されたプロセスであり、前述しました公式文書

フレームワークの構成

表示パッケージおよびインポート

この部分は、コードは次のようにマシンは、使用可能なGPUの数としてGPUトレーニングを使用できるかどうか、ビューのバージョンPyTorchあるノートを詳述しています。

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の、トーチ乱数を含め、プログラムが始まる前に、乱数シードを修正することですシード。

import numpy as np
import torch

np.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'

テンソル計算

基本的なテンソルクラスAPIの作成を含まない9つのテンソルCPUタイプと共通の操作テンソル主に一部対応テンソルGPU型のPyTorch合計、。

ここに画像を挿入説明

テンソル情報

テンソルのために、時にはそのようなコードをデバッグする寸法、データ型として、その基本的な情報に焦点を当てます。

import torch

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

データ型変換

PyTorchは、しばしば、時には(フロートタイプPyTorchはるかに高速タイプダブルに)デフォルトのデータ型を設定する操作を容易にするために、CPUのGPUデータに、異なるタイプのデータ、特にデータ間の変換を伴います。

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のもPyTorchテンソルにnumpyの配列をサポートしています。

import torch

t = 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))

張単一要素の測定値が得られます

結果はテンソルであるが、実際には、このテンソルは一つの値だけを含んでいるが、時には損失のため、これらの値は、このテンソルの値が項目法により除去しました。

import torch

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

モデル事業

モデルの定義

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

import torch
import torch.nn as nn
import torch.nn.functional as F


class 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.0
    correct = 0.0
    total = 0.0
    for step, data in enumerate(train_loader):
        x, y = data
        out = 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.0
    correct = 0.0
    total = 0.0

    for step, data in enumerate(valid_loader):
        model.eval()
        x, y = data
        out = 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 / total

    scheduler.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間のデータ交換を最小限に抑えます。バッチおよびACCあたり損失を得るために、それらは一緒に送信することができる(使用CPUに全体エポック媒体GPUの端に蓄積loss.cpu()方式)をはるかに高速バッチ当たりCPU IOよりGPUでなければならないであろう。

サプリメント

本稿では、コードは、参照PyTorch料理の一部より実用的であり、いくつかの一般的なPyTorchコードセグメントに記載されています。この記事のコードはすべてに関与することができ、私のGitHubのあなたは歓迎の星やフォークを見つけます。

234元記事公開 ウォンの賞賛148 ビューに14万+を

おすすめ

転載: blog.csdn.net/zhouchen1998/article/details/104148082