卷积的stride默认为1,而池化默认为kernel_size(卷积核的大小)
Floor向下取整,ceiling向上取整
一、卷积(conv2d的应用)
224*224*3 -> 224*224*64 输出通道为64(可以理解为64种结果),说明需要64个卷积核。
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3,stride=1, padding=0)
def forward(self,x):
x = self.conv1(x)
return x
tudui = Tudui()
print(tudui)
writer = SummaryWriter("logs")
step = 0
for data in dataloader:
imgs, targrts = data
output = tudui(imgs)
print(imgs.shape)
print(output.shape)
# torch.Size([64, 3, 32, 32])
writer.add_images("input", imgs, step)
# torch.Size([64, 6, 30, 30]) -> 令batch_size变多,channel就会变少 [xxx, 3, 30, 30]
# AssertionError:assert I.ndim == 4 and I.shape[1] == 3 即6个channel不知道怎么显示
# -1的意思是可以根据后面的3、30、30自动计算这个batch_size
output = torch.reshape(output, (-1, 3, 30, 30))
writer.add_images("output", output, step)
step = step + 1
writer.close()
二、最大池化的使用
使用:最大池化是取9宫格里的最大值,减少数据量,使少数据量也能保留所需信息
ceil_mode:False = Floor向下取整(不保留),True = ceiling向上取整(保留)
import torch
import torchvision.datasets
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("../data", train=False, download=True, transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)
# "max_pool2d" not implemented for 'Long' 解决:变为浮点数
input = torch.tensor([[1, 2, 0, 3, 1],
[0, 1, 2, 3, 1],
[1, 2, 1, 0, 0],
[5, 2, 3, 1, 1],
[2, 1, 0, 1, 1]], dtype=torch.float32)
# batch_size,channel,w,h
input = torch.reshape(input, (-1, 1, 5, 5))
print(input.shape)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
def forward(self, input):
output = self.maxpool1(input)
return output
tudui = Tudui()
# output = tudui(input)
# print(output)
# ../表示返回上级目录
writer = SummaryWriter("logs_maxpool")
step = 0
for data in dataloader:
imgs, targets = data
writer.add_images("input", imgs, step)
output = tudui(imgs)
writer.add_images("output",output,step)
step = step + 1
writer.close()
三、非线性激活(如ReLU、Sigmoid)
作用:引入非线性特征
ReLU:input>0就取input自身的值,input<0就取0; inplace为True,就是对原来位置的值进行替换,为False,则不替换原来位置的值
Sigmoid:1/(1+exp(-x))
import torch
import torchvision.datasets
from torch import nn
from torch.nn import ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
input = torch.tensor([[1, -0.5],
[-1, 3]])
input = torch.reshape(input, (-1, 1, 2, 2))
print(input.shape)
dataset = torchvision.datasets.CIFAR10("../data",train=False, transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.relu1 = ReLU()
self.sigmoid1 = Sigmoid()
def forward(self,input):
# output = self.relu1(input)
output = self.sigmoid1(input)
return output
tudui = Tudui()
writer = SummaryWriter("logs_relu")
step = 0
for data in dataloader:
imgs, targets = data
writer.add_images("input",imgs,step)
output = tudui(imgs)
writer.add_images("output", output, step)
step = step + 1
# output = tudui(input)
# print(output)
writer.close()
四、线性层及其他层介绍
(1)正则化层(Normalization layer)
作用:加快训练速度
参数:
-
num_features – C from an expected input of size (N,C,H,W) channe
(2)线性层(Linear layer)
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64, drop_last=True) #丢弃无法整除的数据
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
self.linear1 = Linear(196608, 10) #input_feature对应于reshape得到的-1,output_feature设置为10
def forward(self, input):
output = self.linear1(input)
return output
tudui = Tudui()
for data in dataloader:
imgs, targets = data
print(imgs.shape)
# output = torch.reshape(imgs, (1,1,1,-1)) #变成一行数据,-1为自动计算 等价于torch.flatten(imgs)
output = torch.flatten(imgs)
print(output.shape)
output = tudui(output)
print(output.shape)
五、Sequential的使用及搭建小实战
Sequential作用:顺序模块型写法
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
# self.conv1 = Conv2d(3, 32, 5, padding=2)
# self.maxpool1 = MaxPool2d(2) # kernel_size为2
# self.conv2 = Conv2d(32, 32, 5, padding=2) # 图片保持不变 padding=(kernel_size - 1)/2
# self.maxpool2 = MaxPool2d(2)
# self.conv3 = Conv2d(32, 32, 5, padding=2)
# self.maxpool3 = MaxPool2d(2)
# self.flatten = Flatten()
# # 测试前 self.linear1 = Linear(1024, 64)
# self.linear1 = Linear(512, 64)
# self.linear2 = Linear(64, 10)
# 使用Sequential
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(512, 64),
Linear(64, 10)
)
def forward(self, x):
# x = self.conv1(x)
# x = self.maxpool1(x)
# x = self.conv2(x)
# x = self.maxpool2(x)
# x = self.conv3(x)
# x = self.maxpool3(x)
# x = self.flatten(x)
# # 假设未知flatten的结果是1024 得到torch.Size([64, 512]) ,batch_size有64张图片 ,每张图片都展成1*512
# x = self.linear1(x)
# x = self.linear2(x)
# 使用Sequential
x = self.model1(x)
return x
tudui = Tudui()
print(tudui)
input = torch.ones((64, 3, 32, 32))
output = tudui(input)
print(output.shape)
writer = SummaryWriter("../logs_seq")
writer.add_graph(tudui, input) #第一个参数是模型名
writer.close()
六、损失函数(loss)与反向传播
loss函数的作用:
1、计算实际输出和目标之间的差距;
2、用来指导output去接近target,是训练的依据,为我们更新输出提供了一定的依据(反向传播) grad(梯度,weight根据梯度的方向下降改变以降低loss):反向传播计算梯度,根据梯度来更新参数,实现loss最小化
(1)常用函数
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform= torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(512, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in dataloader:
imgs, targets = data
outputs = tudui(imgs)
# print(outputs)
# print(targets)
result_loss = loss(outputs, targets) # 是对result_loss这个变量进行反向传播
result_loss.backward() # 反向传播
print(result_loss)
(2)引入反向传播
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform= torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(512, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in dataloader:
imgs, targets = data
outputs = tudui(imgs)
# print(outputs)
# print(targets)
result_loss = loss(outputs, targets) # 是对result_loss这个变量进行反向传播
result_loss.backward() # 反向传播
print(result_loss)
七、优化器(torch.optim)
import torch.optim
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform= torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
# 网络模型:土堆
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(512, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
tudui = Tudui()
# 设置优化器 —— 随机梯度下降
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)
for epoch in range(20):
running_loss = 0.0 #这一轮loss的总和
# 这只是一次学习
for data in dataloader:
imgs, targets = data
outputs = tudui(imgs)
result_loss = loss(outputs, targets) # 是对result_loss这个变量进行反向传播
# 1、网络中每一个可以调节的参数的梯度设置为0
optim.zero_grad()
# 2、反向传播计算梯度
result_loss.backward()
# 3、对每一个参数调优
optim.step()
running_loss = running_loss +result_loss
print(running_loss)
八、现有网络模型的使用及修改
import torchvision.datasets
from torch import nn
# train_data = torchvision.datasets.ImageNet("../data_image_net", split='train', download = True,
# transform=torchvision.transforms.ToTensor())
vgg16_false = torchvision.models.vgg16(pretrained=False) # 没有预训练,只需要加载已有的网络架构,相当于初始化的样子,都是默认的参数
vgg16_true = torchvision.models.vgg16(pretrained=True) # 需要训练,网络参数是训练好的
print('ok')
# 可以打印出训练好的参数
print(vgg16_true)
train_data = torchvision.datasets.CIFAR10('../data', train=True,transform=torchvision.transforms.ToTensor(),
download=True)
# 1、修改网络模型,使in_features为1000,out_features为10
# modele是指Conv2d、Linear这种
vgg16_true.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)
# 2、修改网络模型,将增加的module放到classifier中
vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)
# 3、在未预训练的模型中修改
print(vgg16_false)
vgg16_false.classifier[6] = nn.Linear(4096, 10)
print(vgg16_false)
九、网络模型的保存与读取
(1)保存方式
import torch
import torchvision
from torch import nn
vgg16 = torchvision.models.vgg16(pretrained = False)
# 保存方式1 保存了模型结构 + 模型参数
torch.save(vgg16, "vgg16_method1.pth")
# 保存方式2 将vgg16模型中的参数保存为字典[[[],[]],[]](官方推荐)
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
# 陷阱
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
x=self.conv1(x)
return x
tudui = Tudui()
torch.save(tudui, "tudui_method1.pth")
(2)读取方式
import torch
import torchvision.models
from module_save import *
# 方式1-》保存方式1.加载模型
model = torch.load("vgg16_method1.pth")
print(model)
# 方式2-》保存方式2.加载模型
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16)
# 陷阱1 Can't get attribute 'Tudui' on <module '__main__' from 'G:\\learn_pytorch\\module_load.py'>
# model = torch.load("tudui_method1.pth")
# print(model)
# 解决陷阱1 无需创建模型tudui = Tudui(),但是要定义模型
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
x=self.conv1(x)
return x
model2 = torch.load("tudui_method1.pth")
print(model2)
# 解决陷阱1 或者from module_save import *