一、安装路径:D:\SoftwareTool\anaconda3
先验概率是 以全事件为背景下,A事件发生的概率,P(A|Ω)
后验概率是 以新事件B为背景下,A事件发生的概率, P(A|B)
全事件一般是统计获得的,所以称为先验概率,没有实验前的概率
新事件一般是实验,如试验B,此时的事件背景从全事件变成了B,该事件B可能对A的概率有影响,那么需要对A现在的概率进行一个修正,从P(A|Ω)变成 P(A|B),
所以称 P(A|B)为后验概率,也就是试验(事件B发生)后的概率
1. Dataset (idx的数据集)
2. Dataloader(数据加载入神经网络)
from torch.utils.data import Dataset
from PIL import Image
import os
class MyData(Dataset):
def __init__(self, root_dir, label_dir):
self.root_dir = root_dir
self.label_dir = label_dir
self.path = os.path.join(self.root_dir, self.label_dir)
self.img_path = os.listdir(self.path)
def __getitem__(self, idx):
img_name = self.img_path[idx]
img_item_path = os.path.join(self.path, img_name)
img = Image.open(img_item_path) # img = Image.open(ImgPath)打开的图片是PIL类型,默认RGB
label = self.label_dir
return img, label
def __len__(self):
return len(self.img_path)
root_dir = "dataset/train"
ants_label_dir = "ants"
bees_label_dir = "bees"
ants_dataset = MyData(root_dir, ants_label_dir)
bees_dataset = MyData(root_dir, bees_label_dir)
train_dataset = ants_dataset + bees_dataset
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("log") # 存储事件文件到log
# terminal 运行代码
tensorboard --logdir=logs --port=xxx
1. add_scalar
for i in range(100):
writer.add_scalar("y=3x", 3*i, i) #scalar 标量 标题,y轴,x轴 画数据曲线图
2. add_image
import numpy as np
from PIL import Image
writer = SummaryWriter("log") # 存储事件文件到log
image_path = "data/train/bees_image/16838648_415acd9e3f.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL)
writer.add_image("test", img_array, 2,dataformats='HWC')
transform(torchvision)
图片的变换
resize (PILImage对象size属性返回的是w, h,而resize的参数顺序是h, w)传入PIL传出PIL
compose组合函数
Normalize 归一化 image = (image - mean) / std
# normalize 归一化 需要tensor类型图片
print(img_tensor[0][0][0]) # 第0层0行0列
trans_norm = transforms.Normalize([3, 0.5, 5],[2, 0.5, 1])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm,3)
normalize的mean和std应该是基于训练集的统计得来的。
RandomCrop (H,W)(int*int) 处理PIL 随机裁剪
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer = SummaryWriter("logs")
img = Image.open("data/train/ants_image/7759525_1363d24e88.jpg")
# print(img)
trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image("ToTensor",img_tensor)
# normalize 归一化 需要tensor类型图片
print(img_tensor[0][0][0]) # 第0层0行0列
trans_norm = transforms.Normalize([3, 0.5, 5],[2, 0.5, 1])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm,3)
# Resize 可以处理PIL类型
print(img.size)
trans_resize = transforms.Resize((512,512))
img_resize = trans_resize(img)
img_resize = trans_totensor(img_resize) # PIL->转换为tensor类型
writer.add_image("Resize",img_resize)
# Compose 组合函数 先转换大小 再转换类型
trans_resize_2 = transforms.Resize(512)
trans_compose = transforms.Compose([trans_resize_2, trans_totensor])
img_resize_2 = trans_compose(img)
writer.add_image("Resize",img_resize_2,1)
#randomCrop 随即裁剪
trans_random = transforms.RandomCrop((300,400))
trans_compose_2 = transforms.Compose([trans_random,trans_totensor])
for i in range(10):
img_crop = trans_compose_2(img)
writer.add_image("RandomCropHW",img_crop,i)
writer.close()
Pytorch的Dataloader中一个很方便的功能是允许使用多进程来加速数据读取,我们可以通过num_workers来设置使用几个进程读取数据。
我们可以将一个torch.utils.data.Dataset的子类传入DataLoader来创建一个读取小批量数据样本的DataLoader实例。
分成多组进行试验。
test_data = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())
# dataloader
# batch_size 打包
# num_worker个worker 工作进程
# drop_last True代表不舍弃数据 False代表舍弃(默认false)
# collate_fn: 在Dataset的__getitem__把一条一条的数据发出来以后,Dataloader会根据你定义的batch_size参数把这些东西组织起来(其实是一个batch_list)。然后再送给collate_fn组织成batch最后的样子,lambda x: x就是指不对这个batch_list进行任何组织,直接输出。从这里就能看到,如果不设置collate_fn,我们得到的数据是很不好用的,且不说这数据是list的形式;就近了说,所有的数据格式是[(data1, label1), (data2, label2)m, (data3, label3), ......]。但是我们希望得形式是:(data1, data2, data3); (label1, label2, label3)。注意这里是一个示意,就是说我们希望从dataloader出来的东西,所有的数据部分组织到一起,所有的label又组织到一起。它们的大小是batch_size。
test_loader = DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0,drop_last=False)
nn.Conv2d(图像二维)
class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)stride 步长;padding 边缘填充 kernel_size 卷积核大小
池化层
nn.maxpool2d()
class torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
池化层夹在连续的卷积层中间, 用于压缩数据和参数的量,减小过拟合。
简而言之,如果输入是图像的话,那么池化层的最主要作用就是压缩图像。
下采样层也叫池化层,其具体操作与卷积层的操作基本相同,只不过下采样的卷积核为只取对应位置的最大值、平均值等(最大池化、平均池化),即矩阵之间的运算规律不一样,并且不经过反向传播的修改。
池化层的作用:
个人觉得主要是两个作用:
1. invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度)
2. 保留主要的特征同时减少参数(降维,效果类似PCA)和计算量,防止过拟合,提高模型泛化能力
线性层
torch.flatten(imgs) # 摊平成一维
self.linear1 = Linear(196608, 10) # 降维
Sequential
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),
)
损失函数
Loss Function (loss = nn.CrossEntropyLoss() result=loss(output,targets))
反向传播->梯度下降
优化器
optim = torch.optim.SGD(test.parameters(), lr=0.01 ) # lr: 学习速率及梯度下降前的参数,小了下降太慢,大了容易梯度振荡
优化器:
vgg16_true.classifier[6].add_module('add_linear',nn.Linear(1000,10)) # 直接插入覆盖
vgg16_true.add_module('add_linear',nn.Linear(1000,10)) # 在外层增加线性器
#保存-1-2
# 保存方式1
torch.save(vgg16,"vgg16_method1.pth")
# 保存方式2 官方推荐
torch.save(vgg16.state_dict(),"vgg16_method2.pth") # 只保存参数为字典形式,不保模型存
#加载-1-2
# 方式1-保存方式1,加载model
model=torch.load("vgg16_method1.pth")
print(model)
# 方式2,加载模型
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16) # 把储存的字节再正常输出
项目完整代码:
import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
from model import *
# 定义训练设备
device = torch.device("cuda")
train_data = torchvision.datasets.CIFAR10("../data",train=True,transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10("../data",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,test_data_size))
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
# 创建网络模型
class Test(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model1 = nn.Sequential(
nn.Conv2d(3, 32, 5, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, padding=2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10),
)
def forward(self,x):
x = self.model1(x)
return x
test = Test()
# gpu-
# test = test.cuda()
test = test.to(device)
# 损失函数
loss_fn = nn.CrossEntropyLoss() # 交叉熵损失函数
# loss_fn = loss_fn.cuda()
loss_fn = loss_fn.to(device)
# 优化器
learning_rate = 1e-2
optimizer = torch.optim.SGD(params=test.parameters(),lr = learning_rate)
# 设置训练网络参数
total_train_step = 0 # 训练步数
total_test_step = 0# 测试步数
epoch = 10 # 训练轮数
# 添加tensorboard
writer = SummaryWriter("logs_train")
# 设置时间
start_time=time.time()
for i in range(epoch):
print("_____第{}轮开始".format(i+1))
# 训练步骤开始
test.train() #
for data in train_dataloader:
imgs, targets = data
# imgs = imgs.cuda()
# targets = targets.cuda()
imgs = imgs.to(device)
targets = targets.to(device)
outputs = test(imgs)
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step += 1
if total_train_step % 100 == 0:
end_time=time.time()
print(end_time-start_time)
print("训练次数:{} loss:{}".format(total_train_step,loss.item()))
writer.add_scalar("train_loss",loss.item(),total_train_step)
# 测试步骤开始
test.eval() # 测试阶段,避免BN Dropout产生的影响
total_test_loss = 0
total_accuracy = 0
with torch.no_grad(): # 提升性能 包裹的记录再反向传播时不会被记录
for data in test_dataloader:
imgs, targets = data
# imgs = imgs.cuda()
# targets = targets.cuda()
imgs = imgs.to(device)
targets = targets.to(device)
outputs = test(imgs)
loss = loss_fn(outputs, targets)
total_test_loss += loss.item()
# 整体正确率
accuracy = (outputs.argmax(1) == targets).sum()
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(test, "test_{}.pth".format(i+1))
print("模型已保存")
writer.close()
在PyTorch中进行validation时,会使用model.eval()切换到测试模式,在该模式下,
主要用于通知dropout层和batchnorm层在train和val模式间切换
该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)
with torch.no_grad()则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。
池化层总结(Summary)
接收单元大小为:W1∗H1∗D1W1∗H1∗D1
需要两个参数(hyperparameters):
their spatial extent FF,
the stride SS,
输出大小:W2∗H2∗D2W2∗H2∗D2,其中:
W2=W1−FSW2=W1−FS
H2=H1−FS+1H2=H1−FS+1
D2=D1D2=D1
不需要引入新权重
————————————————
卷积层总结(Summary)
接收三维输入 W1∗H1∗D1W1∗H1∗D1
需要给出4个参数(hyperparameters):
Number of filters KK,
their spatial extent FF,
the stride SS,
the amount of zero padding PP.
输出一个三维单元 W2∗H2∗D2W2∗H2∗D2,其中:
W2=W1−F+2PS+1W2=W1−F+2PS+1
H2=H1−F+2PS+1H2=H1−F+2PS+1
D2=KD2=K
应用权值共享,每个filter会产生F∗F∗D1F∗F∗D1 个权重,总共 (F∗F∗D1)∗K(F∗F∗D1)∗K 个权重和 KK 个偏置。
在输出单元,第d个深度切片的结果是由第d个filter 和输入单元做卷积运算,然后再加上偏置而来。
————————————————