一、损失函数与反向传播
loss function(越小越好):1.计算实际输出与目标输出之间的差距;2.为我们更新输出提供一定的依据(反向传播)
import torch
from torch import nn
from torch.nn import L1Loss
inputs = torch.tensor([1,2,3],dtype=float)
targets = torch.tensor([1,2,5],dtype=float)
inputs = torch.reshape(inputs,(1,1,1,3))
targets = torch.reshape(targets,(1,1,1,3))
loss = L1Loss(reduction='sum')
result = loss(inputs,targets)#省略了forward
loss_mse = nn.MSELoss()
result_mse = loss_mse(inputs,targets)
print(result)
print(result_mse)
x = torch.tensor([0.1,0.2,0.3])#N,C
y = torch.tensor([1])#N
x = torch.reshape(x,(1,3))
loss_cross = nn.CrossEntropyLoss()#注意每个损失函数输入与输出的形式
result_cross = loss_cross(x,y)
print(result_cross)
import torch
from torch import nn
from torch.nn import ReLU, Sigmoid, Linear
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=64)
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = Linear(196608,10)
def forward(self,input):
output = self.linear1(input)
return output
model = Model()
for data in dataloader:
imgs,targets=data
print(imgs.shape)
#output = torch.reshape(input,(1,1,1,-1))
output = torch.flatten(imgs)
print(output.shape)
output = model(output)
print(output.shape)
二、优化器
优化器根据梯度调整参数,达到降低误差的目的。学习率一般刚开始选择比较大的,后面选择比较小的
import torch
import torchvision
from torch import nn
from torch.autograd import Variable
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=1)
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.model1 = Sequential(
Conv2d(3,32,5,padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
model = Model()
optim = torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(20):
running_loss = 0
for data in dataloader:
imgs,targets = data
outputs = model(imgs)
result_loss = loss(outputs,targets)
optim.zero_grad()#清零梯度
result_loss.backward()#计算每个参数的梯度
optim.step()#参数调优
running_loss += result_loss#计算一轮循环所有图片loss的总和
print(result_loss)
三、pytorch现有网络模型的使用及修改
import torchvision
#train_data = torchvision.datasets.ImageNet("./dataset_imagenet",split='train',download=True,transform=torchvision.transforms.ToTensor())
from torch import nn
vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)
train_data = torchvision.datasets.CIFAR10("./dataset",train=True,download=True,transform=torchvision.transforms.ToTensor())
#如何利用现有的网络改动它的结构,迁移学习,很多网络用vgg16作为前置网络结构,用vgg16提取一些特征,在vgg16之后加一些网络结构实现一个功能,所以vgg16比较重要
vgg16_true.add_module('add_linear',nn.Linear(1000,10))#把线性层加到classifier之后,平级
print(vgg16_true)
vgg16_true.classifier.add_module('add_linear',nn.Linear(1000,10))#把线性层加到classifier之内
vgg16_false.classifier[6] = nn.Linear(4096,10)#不是添加,而是直接修改某一层的参数
四、网络模型的保存与读取
import torch
import torchvision
from torch import nn
vgg16 = torchvision.models.vgg16(pretrained=False)
#网络模型的保存有两种方式,第一种方式不仅保存了网络模型结构,还保存了网络模型的一些参数
torch.save(vgg16,"model_method1.pth")
#保存方式二(官方推荐)占用内存小
torch.save(vgg16.state_dict(),"vgg16_method2.pth")#把vgg16的状态保存成字典形式,不再保存网络模型的结构,只保存网络模型的一些参数
#保存方式一加载数据
model = torch.load("model_method1.pth")
#print(model)
#保存方式二加载数据
#model = torch.load("vgg16_method2.pth")#这种方式加载出来的为字典格式的参数
#下面这种方式加载的数据依然是模型结构
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
#print(vgg16)
#保存方式一具有一定的陷阱,如果保存模型与加载数据时不在同一个文件夹,则有可能会报错类不存在
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv1 = nn.Conv2d(3,64,kernel_size=3)
def forward(self, x):
x = self.conv1(x)
return x
model = Model()
torch.save(model,"model1_method1.pth")
五、完整的模型训练套路
import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from model import *
train_data = torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
#查看数据集图片的数量
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))#字符串格式化
print("测试数据集的长度为:{}".format(test_data_size))
#加载数据集
train_dataloader = DataLoader(train_data,batch_size=64)
test_dataloader = DataLoader(test_data,batch_size=64)
#创建网络模型
model = Model()
#损失函数
loss_fn = nn.CrossEntropyLoss()
#优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(model.parameters(),lr=learning_rate)
#设置训练网络的一些参数
total_train_step = 0 #记录训练的次数
total_test_step = 0 #记录测试的次数
epoch = 10 #记录训练的轮数
#添加tensorboard
writer = SummaryWriter("logs")
for i in range(epoch):
print("-------第{}轮训练-------".format(i+1))
#训练步骤开始
model.train()#对特定层有作用
for data in train_dataloader:
imgs,targets = data
output = model(imgs)
loss = loss_fn(output,targets)
#优化器优化模型,优化之前梯度需要清零
optimizer.zero_grad()
loss.backward()#获取每个参数节点的梯度
optimizer.step()#梯度优化
total_train_step +=1
if total_train_step %100 ==0:#减少输出次数
print("训练次数{},Loss:{}".format(total_train_step,loss.item()))#加上item可以把数据类型去掉,直接输出数字
writer.add_scalar("train_loss",loss.item(),total_train_step)
#测试步骤开始
model.eval()#对特定层有作用
total_test_loss = 0 #循环内的loss每次求出的是data的loss,而不是整个数据集的loss
total_accuracy = 0 #计算正确率
with torch.no_grad():#让网络模型中没有梯度
for data in test_dataloader:
imgs,targets = data
outputs = model(imgs)
loss = loss_fn(outputs,targets)
total_test_loss += loss.item()
accuracy = (outputs.argmax(1) == targets).sum() #横向1和竖向0
total_accuracy += accuracy
print("整体测试集上的loss: {}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss",total_test_loss,total_test_step)
writer.add_scalar("test_accuracy",total_accuracy/test_data_size,total_test_step)
total_test_step += 1
#模型保存
torch.save(model,"model_{}.pth".format(i))#一般保存每一轮训练的结果,也可以保存每训练多少步的结果
print("模型已保存")
writer.close()
model部分
#搭建神经网络,为了规范,会将这些代码单独放在一个文件里面
import torch
from torch import nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,5,1,2),
nn.MaxPool2d(2),
nn.Conv2d(32,32,5,1,2),
nn.MaxPool2d(2),
nn.Conv2d(32,64,5,1,2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4,64),
nn.Linear(64,10)
)
def forward(self,x):
x = self.model(x)
return x
if __name__ == '__main__':
model = Model()
input = torch.ones(64,3,32,32)
output = model(input)
print(output.shape)
六、利用gpu训练
gpu训练方式有两种,
1.模型,数据,损失函数调用cuda
2…首先定义训练的设备
device = torch.device("cpu")
device = torch.device("cuda")
device = torch.device("cuda:0")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
然后采用网络模型调用device
model = model.to(device)#可以不用复制model.to(device)
loss_fn = loss_fn.to(device)#可以不用复制loss_fn.to(device)
imgs = imgs.to(device)
targets = targets.to(device)
七、完整的模型验证(测试,demo)套路–利用已经训练好的模型,然后给它提供输入
import torch
import torchvision
from PIL import Image
from torch import nn
from torchvision.transforms import Resize, ToTensor
#加载图片
img_path = "./imgs1/dog.png"
image = Image.open(img_path)
print(image)
image = image.convert("RGB")
transform = torchvision.transforms.Compose([Resize((32,32)),ToTensor()])
image = transform(image)
print(image.shape)
#加载网络模型
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,5,1,2),
nn.MaxPool2d(2),
nn.Conv2d(32,32,5,1,2),
nn.MaxPool2d(2),
nn.Conv2d(32,64,5,1,2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4,64),
nn.Linear(64,10)
)
def forward(self,x):
x = self.model(x)
return x
moxing = torch.load("model_0.pth")
print(moxing)
image = torch.reshape(image,(1,3,32,32))
moxing.eval()
with torch.no_grad():
output = moxing(image)
print(output)
print(output.argmax(1))