目录
本文基于B站“我是土堆”的课程记录学习笔记,原视频讲解:P4. PyCharm及Jupyter使用及对比_哔哩哔哩_bilibili
P4 PyCharm和Jupyter的对比
测试程序:
#用来测试的错误代码,a是字符型,b是整型,所以加在一起会报错
print("Start")
a = "hello word"
b = 2019
c = a + b
print(c)
#正确的代码,把b也写成字符型
print("Start")
a = "hello word"
b = "2019"
c = a + b
print(c)
python控制台运行代码可读性比较差,可以用来做调试;Jupyter可用于小项目或调试。
P5 PyTorch加载数据
Dataset:提供一种方式去获取数据及其lable。
要实现的功能:
- 如何获取每一数据及其lable
- 告诉我们总共有多少个数据(知道训练的时候要迭代多少次)
在Jupyter里查看Dataset的官方文档解释
from torch.utils.data import Dataset
help(Dataset)
#第二种查看方式
Dataset??
- 函数def __init__(self,xx,xx):
初始化类,创建特例实例时要运行的函数,为整个class提供共一个全局变量,为后面的函数如getitem,length等方法提供它们需要的一些量。这个类中定义的一些self.xx=...能够成为全局变量,方便后续的使用。xx为所需的全局变量
- 函数def __getitem__(self,idx):
idx一般作为数据的编号,根据图片地址的列表获取每一条数据。
- 函数def __len__(self):
获取数据集的长度,有多少条数据。
P6 Dataset类代码实现
数据集下载:https://download.pytorch.org/tutorial/hymenoptera_data.zip
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.root_dir 相当于类中的全局变量
self.label_dir = label_dir
self.path = os.path.join(self.root_dir,self.label_dir) # 字符串拼接,根据是Windows或Lixus系统情况进行拼接
self.img_path = os.listdir(self.path) # 获得路径下所有图片的地址
def __getitem__(self,idx):
img_name = self.img_path[idx]
img_item_path = os.path.join(self.root_dir,self.label_dir,img_name)
img = Image.open(img_item_path)
label = self.label_dir
return img, label
def __len__(self):
return len(self.img_path)
root_dir = "Data/FirstTypeData/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)
print(len(ants_dataset))
print(len(bees_dataset))
train_dataset = ants_dataset + bees_dataset # train_dataset 就是两个数据集的集合了
print(len(train_dataset))
img,label = train_dataset[200]
print("label:",label)
img.show()
Datalodader:为后面的网络提供不同的数据形式。将数据打包
P7 Tensorboard 写日志
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("logs") # 创建一个logs文件夹,writer写的文件都在该文件夹下
#writer.add_image()
for i in range(100):
writer.add_scalar("y=2x",2*i,i)
writer.close()
运行之后会产生一个log目录和一个日志文件
读取日志文件
在 Anaconda 终端里面,激活py3.6.3环境,再输入
tensorboard --logdir=logs #你自己的logs路径
命将网址赋值浏览器的网址栏,回车,即可查看tensorboard显示日志情况。
② 为避免多人使用端口导致冲突,也可以在后面加上后缀,使得端口独立
tensorboard --logdir=C:\Users\wangy\Desktop\03CV\logs --port=6007
③ 输入网址可得Tensorboard界面。
Tensorboard 读图片
from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np
img_path1 = "Data/FirstTypeData/train/ants/0013035.jpg"
img_PIL1 = Image.open(img_path1)
img_array1 = np.array(img_PIL1)
img_path2 = "Data/SecondTypeData/train/bees_image/17209602_fe5a5a746f.jpg"
img_PIL2 = Image.open(img_path2)
img_array2 = np.array(img_PIL2)
writer = SummaryWriter("logs")
writer.add_image("test",img_array1,1,dataformats="HWC") # 1 表示该图片在第1步
writer.add_image("test",img_array2,2,dataformats="HWC") # 2 表示该图片在第2步
writer.close()
通过这种方式可以很直观的观察训练过程中给model提供了哪些数据,或者说想对model测试的时候可以看到它每阶段的输出结果,或者可以看到每个阶段的一些不同的显示。
P10 Transforms使用
Transforms用途
① Transforms当成工具箱的话,里面的class就是不同的工具。例如像totensor、resize这些工具。
② Transforms拿一些特定格式的图片,经过Transforms里面的工具,获得我们想要的结果。
transforms.Totensor使用
from torchvision import transforms
from PIL import Image
img_path = "Data/FirstTypeData/val/bees/10870992_eebeeb3a12.jpg"
img = Image.open(img_path)
tensor_trans = transforms.ToTensor() # 创建 transforms.ToTensor类 的实例化对象
tensor_img = tensor_trans(img) # 调用 transforms.ToTensor类 的__call__的魔术方法
print(tensor_img)
需要Tensor数据类型原因
Tensor有一些属性,比如反向传播、梯度等属性,它包装了神经网络需要的一些属性。
常见的Transforms工具
Transforms的工具主要关注他的输入、输出、作用。
Compose()用法
Compose()中的参数需要是一个列表,Python中,列表的表示形式为[数据1,数据2,….]
在Compose中,数据需要是 transforms类型,所以得到,Compose([transforms参数1,transforms参数2....]
Compose类就是把不同的transform结合在一起。
transforms.Compose([
transforms.Centercrop(10),
transforms.ToTensor(),
])
P14 torchvision数据集使用
pytorch提供的数据集API:torchvision — Torchvision master documentation
torchvision数据集介绍
① torchvision中有很多数据集,当我们写代码时指定相应的数据集指定一些参数,它就可以自行下载。
② CIFAR-10数据集包含60000张32×32的彩色图片,一共10个类别,其中50000张训练图片,10000张测试图片。
运行代码下载数据集:
import torchvision
train_set = torchvision.datasets.CIFAR10(root="./dataset",train=True,download=True) # root为存放数据集的相对路线
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False,download=True) # train=True是训练集,train=False是测试集
查看CIFAR10数据集内容
import torchvision
train_set = torchvision.datasets.CIFAR10(root="./dataset",train=True,download=True) # root为存放数据集的相对路线
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False,download=True) # train=True是训练集,train=False是测试集
print(test_set[0]) # 输出的3是target
print(test_set.classes) # 测试数据集中有多少种
img, target = test_set[0] # 分别获得图片、target
print(img)
print(target)
print(test_set.classes[target]) # 3号target对应的种类
img.show()
与Transform结合
定义Transform的图像变换,下载数据时加入transform
dataset_transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
train_set = torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=dataset_transform,download=True) # 将ToTensor应用到数据集中的每一张图片,每一张图片转为Tensor数据类型
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=dataset_transform,download=True)
P15 Dataloader使用
① Dataset只是去告诉我们程序,我们的数据集在什么位置,数据集第一个数据给它一个索引0,它对应的是哪一个数据。
② Dataloader就是把数据加载到神经网络当中,Dataloader所做的事就是每次从Dataset中取数据,至于怎么取,是由Dataloader中的参数决定的。
加载数据的参数中:dataset数据位置,batch_size每次加载的数据量,shuffle是否要打乱数据,num_works设置多进程,默认0只设置主进程,dorp_last选数据如果有不足batch_size个剩余数的话要不要丢弃,True丢弃。
import torchvision
from torch.utils.data import DataLoader
# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())
img, target = test_data[0]
print(img.shape)
print(img)
# batch_size=4 使得 img0, target0 = dataset[0]、img1, target1 = dataset[1]、img2, target2 = dataset[2]、img3, target3 = dataset[3],然后这四个数据作为Dataloader的一个返回
test_loader = DataLoader(dataset=test_data,batch_size=4,shuffle=True,num_workers=0,drop_last=False)
# 用for循环取出DataLoader打包好的四个数据
for data in test_loader:
imgs, targets = data # 每个data都是由4张图片组成,imgs.size 为 [4,3,32,32],四张32×32图片三通道,targets由四个标签组成
print(imgs.shape)
print(targets)
dataloder返回的是图片和标签的打包形式,比如batch_size=4,返回的是4个img叠起来的imgs和4个target叠起来的targets。下面可以看到 imgs的形状是4个(3,32,32)形状的图片,而targets包含了4个标签分别是2,3,6,8对应四张图片。
Tensorboard展示+Dataloader多轮次
shuffle如果设置为False则第一个epoch和第二个epoch的图片顺序都一样,设置为True则每次取的图片顺序都不一样。
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())
# batch_size=4 使得 img0, target0 = dataset[0]、img1, target1 = dataset[1]、img2, target2 = dataset[2]、img3, target3 = dataset[3],然后这四个数据作为Dataloader的一个返回
test_loader = DataLoader(dataset=test_data,batch_size=64,shuffle=True,num_workers=0,drop_last=True)
# 用for循环取出DataLoader打包好的四个数据
writer = SummaryWriter("logs")
for epoch in range(2):
step = 0
for data in test_loader:
imgs, targets = data # 每个data都是由4张图片组成,imgs.size 为 [4,3,32,32],四张32×32图片三通道,targets由四个标签组成
writer.add_images("Epoch:{}".format(epoch),imgs,step)
step = step + 1
writer.close()
P16 nn.Module模块使用
torch.nn — PyTorch 2.4 documentation
关于神经网络的使用在torch.nn里边,其中nn是Neural network的缩写
nn.Module模块使用
① nn.Module是对所有神经网络提供一个基本的类。init初始化函数,forward前向传播函数接受输入,处理后输出。x指输入
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 20, 5)
self.conv2 = nn.Conv2d(20, 20, 5)
def forward(self, x):
x = F.relu(self.conv1(x))
return F.relu(self.conv2(x))
② 我们的神经网络是继承nn.Module这个类,即nn.Module为父类,nn.Module为所有神经网络提供一个模板,对其中一些我们不满意的部分进行修改。
import torch
from torch import nn
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__() # 继承父类的初始化
def forward(self, input): # 将forward函数进行重写
output = input + 1
return output
tudui = Tudui()
x = torch.tensor(1.0) # 创建一个值为 1.0 的tensor
output = tudui(x)
print(output)
super(Myclass, self).__init__()
① 简单理解就是子类把父类的__init__()放到自己的__init__()当中,这样子类就有了父类的__init__()的那些东西。
② Myclass类继承nn.Module,super(Myclass, self).__init__()就是对继承自父类nn.Module的属性进行初始化。而且是用nn.Module的初始化方法来初始化继承的属性。
③ super().__init()__()来通过初始化父类属性以初始化自身继承了父类的那部分属性;这样一来,作为nn.Module的子类就无需再初始化那一部分属性了,只需初始化新加的元素。
③ 子类继承了父类的所有属性和方法,父类属性自然会用父类方法来进行初始化。
forward函数
① 使用pytorch的时候,不需要手动调用forward函数,只要在实例化一个对象中传入对应的参数就可以自动调用 forward 函数。
② 因为 PyTorch 中的大部分方法都继承自 torch.nn.Module,而 torch.nn.Module 的__call__(self)函数中会返回 forward()函数 的结果,因此PyTroch中的 forward()函数等于是被嵌套在了__call__(self)函数中;因此forward()函数可以直接通过类名被调用,而不用实例化对象。
P17 卷积原理
torch.nn.functional.conv2d — PyTorch 2.4 documentation
① 卷积核不停的在原图上进行滑动,对应元素相乘再相加。
② 下图为每次滑动移动1格,然后再利用原图与卷积核上的数值进行计算得到缩略图矩阵的数据,如下图右所示。
stride=1时默认横向、纵向的步幅都为1。stride=2时,表示横向和纵向步幅都为2,即计算完第一个之后,卷积核移两步。先横向走再纵向走
代码实现:
import torch
import torch.nn.functional as F
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]])
kernel = torch.tensor([[1, 2, 1],
[0, 1, 0],
[2, 1, 0]])
print(input.shape)
print(kernel.shape)
input = torch.reshape(input, (1,1,5,5))
kernel = torch.reshape(kernel, (1,1,3,3))
print(input.shape)
print(kernel.shape)
output = F.conv2d(input, kernel, stride=1)
print(output)
代码中原始input的形状为torch.Size([5, 5]),但是从官方文档里可以看到还要有batch批次、channel通道的维度,所以还要把input的形状改一下,用到了reshape。F是卷积函数。
padding表示填充 ,默认为0即不填充,padding=1时,表示在输入图像周围添加一圈,默认值都为0,再根据步幅去做计算。
代码实现:
import torch
import torch.nn.functional as F
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]])
kernel = torch.tensor([[1, 2, 1],
[0, 1, 0],
[2, 1, 0]])
print(input.shape)
print(kernel.shape)
input = torch.reshape(input, (1,1,5,5))
kernel = torch.reshape(kernel, (1,1,3,3))
print(input.shape)
print(kernel.shape)
output3 = F.conv2d(input, kernel, stride=1, padding=1) # 周围只填充一层
print(output3)
步幅、填充原理
① 步幅:卷积核经过输入特征图的采样间隔。设置步幅的目的:希望减小输入参数的数目,减少计算量。
② 填充:在输入特征图的每一边添加一定数目的行列。设置填充的目的:希望每个输入方块都能作为卷积窗口的中心,或使得输出的特征图的长、宽 = 输入的特征图的长、宽。
③ 一个尺寸 a * a 的特征图,经过 b * b 的卷积层,步幅(stride)= c,填充(padding)= d,若d等于0,也就是不填充,输出的特征图的尺寸 =(a-b)/ c+1;若d不等于0,也就是填充,输出的特征图的尺寸 =(a+2d-b)/ c+1。
例子1:一个特征图尺寸为4 * 4的输入,使用3 * 3的卷积核,步幅=1,填充=0,输出的尺寸=(4 - 3)/1 + 1 = 2。
例子2: 一个特征图尺寸为5 * 5的输入,使用3 * 3的卷积核,步幅=1,填充=1,输出的尺寸=(5 + 2 * 1 - 3)/1 + 1 = 5。
例子3:一个特征图尺寸为5 * 5的输入, 使用3 * 3的卷积核,步幅=2,填充=0,输出的尺寸=(5-3)/2 + 1 = 2。