import torch
from torch.utils.data import Dataset
from torchvision import datasets
from torchvision.transforms import ToTensor
import matplotlib.pyplot as plt
training_data = datasets.FashionMNIST(
root="data1",
train=True,
download=True,
transform=ToTensor()
)
test_data = datasets.FashionMNIST(
root="data1",
train=False,
download=True,
transform=ToTensor()
)
labels_map = {
0: "T-Shirt",
1: "Trouser",
2: "Pullover",
3: "Dress",
4: "Coat",
5: "Sandal",
6: "Shirt",
7: "Sneaker",
8: "Bag",
9: "Ankle Boot",
}
cols, rows = 3, 3
for i in range(1, cols * rows + 1):
sample_idx = torch.randint(len(training_data), size=(1,)).item() #用于随机取出一个training_data
img, label = training_data[sample_idx]
plt.subplot(3,3,i) #此处i必须是1开始
plt.title(labels_map[label])
plt.axis("off")
plt.imshow(img.squeeze(), cmap="gray")
plt.show()
device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
print(f"Using {device} device")
model.to(device)
#或者
model.to('mps')
model.to('cuda')
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
print(f"Model structure: {model}\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
详见文章Variable
需要优化的参数需要加requires_grad=True
,会计算这些参数对于loss的梯度
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
计算导数
loss.backward()
print(w.grad)
print(b.grad)
训练好后进行测试,也就是不要更新参数时使用
z = torch.matmul(x, w)+b
print(z.requires_grad)
with torch.no_grad():
z = torch.matmul(x, w)+b
print(z.requires_grad)
optmizer.zero_grad()
loss.backward()
optmizer.step()
import torch
import torchvision.models as models
model = models.vgg16(weights='IMAGENET1K_V1')
torch.save(model.state_dict(), 'model_weights.pth')
model = models.vgg16() # we do not specify ``weights``, i.e. create untrained model
model.load_state_dict(torch.load('model_weights.pth'))
model.eval()
常见的迁移学习方式
torch.manual_seed(64)
tensor.permute(3,2,1,0)
原本位置为0,1,2,3
爱因斯坦求和约定:用于简洁的表示乘积、点积、转置等方法
>>> import torch
>>> A = torch.randn(3, 4)
>>> B = torch.randn(4, 5)
>>> C = torch.einsum('ik,kj->ij', A, B)
>>> C.shape
torch.Size([3, 5])
A代表ik,B代表kj,C代表ij
input=torch.randn(1,1,3,3)
m=torch.nn.ZeroPad2d((1,1,2,0)) #左,右,上,下
m(input)
torch.nn.ReLU(inplace=True)
output=[branch1,branch2,branch3,branch4]
torch.cat(output,1) #在1维度上合并
avgpool=torch.nn.AdaptiveAvgPool2d((1,1)) #输出shape为(1,1)
将卷积分为dw卷积和pw卷积(pw实际就是普通卷积,只是卷积核大小为1)
将groups设置为输入的深度(通道数),就是深度可分离卷积
nn.Conv2d(groups=1)
#原本
torch.save(
model.state_dict(),
os.path.join(proj_save_dir, 'iterations{}.pth'.format(whole_iter_num))
)
#修改
checkpoint = {
"model_state_dict": model.state_dict(),
"optimizer_state_dict": optimizer.state_dict(),
"epoch": epoch,
}
torch.save(checkpoint, os.path.join(proj_save_dir, 'iterations{}.pth'.format(whole_iter_num)))
注意:checkpoint不要写在iteration里面,要写在epoch循环中
2. 在实例化模型代码后加上加载模型的权重等
path_checkpoint = "./checkpoint/ORSI_COSOD/iterations102.pth"
checkpoint = torch.load(path_checkpoint)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
start_epoch = checkpoint['epoch']
lr_scheduler.last_epoch = start_epoch
#原本
model.load_state_dict(torch.load(os.path.join(model_dir, model_name, "iterations102.pth")))
#修改
model.load_state_dict(torch.load(os.path.join(model_dir, model_name, "iterations102.pth"))['model_state_dict'])
from torchsummary import summary
net=vggnet()
print(summary(net,(3,224,224),8))
注意:8是batch size
选择要可视化的模型文件上传即可
网站
终端进行安装pip install netron
安装完成后,在脚本中 调用包 import netron
运行程序 netron.start("model.onnx")
,会自动打开浏览器进行可视化
net = Alexnet()
img = torch.rand((1, 3, 224, 224))
torch.onnx.export(model=net, args=img, f='model.onnx', input_names=['image'], output_names=['feature_map'])
onnx.save(onnx.shape_inference.infer_shapes(onnx.load("model.onnx")), "model.onnx") #用来在onnx显示中间层的一些尺寸
netron.start("model.onnx")
args是指输入,f是指文件名
之前自己是用Tensorboard来可视化,链接在此,此处是用TensorboardX
from tensorboardX import SummaryWriter as SummaryWriter
net=vggnet()
img=torch.randn(1,3,224,224)
with SummaryWriter(log_dir='logs') as w:
w.add_graph(net,img)
终端cd到logs目录所在的统计目录,输入下面代码
tensorboard --logdir ./logs --port 6006
然后打开终端提示的网站
作用:保存到网络对象的参数中,被优化器作用进行学习,进而保存到网络参数文件
import torch
import torch.nn as nn
class MyModule(nn.Module):
def __init__(self):
super(MyModule, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=1, bias=False)
self.conv2 = nn.Conv2d(in_channels=6, out_channels=9, kernel_size=3, stride=1, padding=1, bias=False)
self.register_parameter('weight', torch.nn.Parameter(torch.ones(10, 10)))
self.register_parameter('bias', torch.nn.Parameter(torch.zeros(10)))
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x * self.weight + self.bias
return x
net = MyModule()
for name, param in net.named_parameters():
print(name, param.shape)
print('\n', '*'*40, '\n')
for key, val in net.state_dict().items():
print(key, val.shape)
data_loader = torch.utils.data.DataLoader(...)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, steps_per_epoch=len(data_loader), epochs=10)
for epoch in range(10):
for batch in data_loader:
train_batch(...)
scheduler.step()
torch.optim.AdamW()
经验:当batchsize加倍时,通常学习率也需要加倍
使用多少子进程进行加载,一般设置为可用GPU数量的4倍
已证明在transformer和resnets等架构非常有用
(1)训练时要将traning参数设置为True,在验证时将trainning参数设置为False。在pytorch中可通过创建模型的model.train()和model.eval()方法控制。
(2)batch size尽可能设置大点,设置小后表现可能很糟糕,设置的越大求的均值和方差越接近整个训练集的均值和方差。
(3)建议将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,因为没有用
from PIL import Image
im=Image.open('1.jpg')
import os
data_root=os.path.abspath(os.getcwd())
data_root
#或者
pwd
data_transform={
'train':transforms.Compose([transforms.RandomResizedCrop(224),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]),
'val':transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
}
from torchvision import transforms,datasets,utils
train_dataset=datasets.ImageFolder(root=data_root+'train',
transform=data_transform['train'])
train_dataset.class_to_idx
cla_dict=dict((val,key) for key,val in flower_list.items())
import json
json_str=json.dumps(cla_dict,indent=4) #转成json文件
with open('class_indices.json','w') as json_file: #写入json文件
json_file.write(json_str)
try:
json_file=open('./class_indices.json','r')
class_indict=json.load(json_file)
except Exception as e:
print(e)
exit(-1)
import time
t1=time.time()
time.sleep(1)
t2=time.time()
print(t2-t1)
import time
t1=time.perf_counter()
time.sleep(1)
t2=time.perf_counter()
print(t2-t1)
from ..utils.train_utils import get_info
作用:让使用者以类似 Unix/Linux 命令参数的方式输入参数(在终端以命令行的方式指定参数),argparse 会自动将命令行指定的参数解析为 Python 变量,从而让使用者更加快捷的处理参数
使用步骤如下
import argparse
# 创建解释器
parser = argparse.ArgumentParser(description="可写可不写,此处会在命令行参数出现错误的时候,随着错误信息打印出来。")
parser.add_argument('-gf', '--girlfriend', choices=['jingjing', 'lihuan'])
# --girlfriend 代表完整的参数名称,可以尽量做到让人见名知意,需要注意的是如果想通过解析后的参数取出该值,必须使用带--的名称
# -gf 代表参数名缩写,在命令行输入 -gf 和 --girlfriend 的效果是一样的,用简称的作用是简化参数输入
# choices 代表输入参数的值只能是这个choices里面的内容,其他内容则会保错
parser.add_argument('food')
# 该种方式则要求必须输入该参数; 输入该参数不需要指定参数名称,指定反而会报错,解释器会自动将输入的参数赋值给food
parser.add_argument('--house', type=int, default=0)
# type 代表输入参数的类型,从命令行输入的参数,默认是字符串类型
# default 如果不指定该参数的值,则会使用该默认值
# 进行参数解析
args = parser.parse_args()