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のあなたは歓迎の星やフォークを見つけます。