学习参考:
PyTorch简单入门视频
深入浅出PyTorch
小土堆笔记
前置知识
- AI vs ML vs DL
- AI(Artificial Intelligence):通过让机器模仿人类进而超越人类
- ML(Machine Learning):让机器模仿人类的一种方法
是AI的一个分支(也是最重要分支) - DL(Deep Learning):让机器不借助人工标注,也能自主提取目标特征进而解决问题的一种方法
是ML的一个分支
TP为True Positive,True代表实际和预测相同,Positive代表预测为正样本。
同理可得,False Positive (FP)代表的是实际类别和预测类标不同,并且预测类别为正样本,实际类别为负样本;
False Negative (FN)代表的是实际类别和预测类标不同,并且预测类别为负样本,实际类别为正样本;
True Negative (TN)代表的是实际类别和预测类标相同,预测类别和实际类别均为负样本。
-
模型评价指标
-
Overall Accuracy:所有预测正确的样本占所有预测样本总数的比例
-
Average accuracy( AA) :平均精度的计算,平均精度计算的是每一类预测正确的样本与该类总体数量之间的比值,最终再取每一类的精度的平均值
-
Recall:也称召回率,代表了实际为正样本并且也被正确识别为正样本的数量占样本中所有为正样本的比例。
Recall是判断模型正确识别所有正样本的能力。 -
Precision:也称精准率,代表的是在全部预测为正的结果中,被预测正确的正样本所占的比例
Precision代表了预测结果中有多少样本是分类正确的。 -
F1:可以解释为召回率R(Recall)和P(精确率)的加权平均。
F1越高,说明模型鲁棒性越好
人们希望有一种更加广义的方法定义F-score,希望可以改变P和R的权重,于是人们定义了Fβ,其定义式如下 F β = ( 1 + β 2 ) × P × R ( β 2 × P ) + R \rm{F_{\beta}}=\frac{\left(1+\beta^{2}\right) \times P \times R}{\left(\beta^{2} \times P\right)+R} Fβ=(β2×P)+R(1+β2)×P×R
-
Overall Accuracy:所有预测正确的样本占所有预测样本总数的比例
-
Average accuracy( AA) :平均精度的计算,平均精度计算的是每一类预测正确的样本与该类总体数量之间的比值,最终再取每一类的精度的平均值
-
置信度:在目标检测中,我们通常需要将边界框内物体划分为正样本和负样本。我们使用置信度这个指标来进行划分,当小于置信度设置的阈值判定为负样本(背景),大于置信度设置的阈值判定为正样本
-
-
dir()打开,看见
返回指定对象的属性和方法列表 -
help()使用说明
提供有关对象的详细信息和文档
查看函数不需要括号,可以联想为我们是在求助,而之所以要求助是因为被打劫了,少了东西(括号)~以后用dir()或者help()查函数时,记得无需带最后的括号,因为已经被“打劫”走了
单下划线通常用来表示临时变量、私有变量或函数以及避免命名冲突;双下划线则具有重写Python内置方法、避免命名冲突、名称修饰以及名称修饰器等作用。
一、PyTorch安装
创建虚拟环境
conda create -n 虚拟环境名字 python=版本 -c 镜像地址
清华镜像:https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
北京外国语大学镜像:https://mirrors.bfsu.edu.cn/anaconda/pkgs/main
阿里巴巴镜像:http://mirrors.aliyun.com/anaconda/pkgs/main
出现选择提示,输入y
简单验证pytorch是否安装成功
//激活你安装的虚拟环境
conda activate 虚拟环境名
conda env list
conda list
判断CUDA runtime版本
- 更新显卡驱动到最新版本
任务管理器 -》 性能 -》查看GPU型号
https://www.nvidia.cn/Download/index.aspx?lang=zh-cn
在官网选择对应版本并下载,其中台式机选择不带(Notebooks)
后缀的,笔记本反之。安装过程中,选择精简版即可,geforce experience可以不选择
-
打开命令窗口(win+r)输入
nvidia-smi
来确定cuda driver版本(选择比驱动版本小的 最新版本)
https://pytorch.org/
-
其中,更新驱动程序时,可能进度条会卡着一直不动
- 可以关掉360,火绒,安全管家等
- 或者直接进入安全模式再安装
安装PyTorch
进入之前创建好的虚拟环境中
conda activate 虚拟环境名
从官网找到对应的命令行进行下载
会先罗列将要下载的东西,可以确定下版本是否正确(例如pytorch是否带cuda,python是否是之前指定版本,cuda是否为之前查到的版本);
然后输入y开始下载即可。
验证PyTorch是否安装成功
激活对应的虚拟环境,输入
conda list
看有木有pytorch或者torch
再输入下图中的三条命令,输出true即电脑里有GPU&你的PyTorch也能正常使用你的GPU
二、Jupyter安装
在base里安装pytorch,或者在上述新创建的虚拟环境中安装jupyter,推荐后者
进入虚拟环境
conda activate 虚拟环境名
方法1. 安装 nb_conda_kernels,将所有 conda 环境同步至 Jupyter Notebook
conda install nb_conda_kernels
方法2. 安装 ipykernel,并将指定 conda 环境写入 Jupyter Notebook 的 Kernel
conda install ipykernel
- 验证是否安装成功
输入完一行命令后,shift+回车
看见熟悉的true即为安装成功
- python文件 vs python控制台 vs jupyter
-
python文件
代码以块(python文件的块是所有的行)为整体运行- 优:通用,传播方便,适用于大型项目
- 缺:需要从头运行
-
python控制台
以任意行为块,来运行- 优:显示每个变量属性
- 缺:不利于代码阅读和修改
-
jupyter
以任意行为块,来运行- 优:利于代码阅读及修改
- 缺:环境需要配置
-
三、基础入门
加载数据初识
蚂蚁蜜蜂/练手数据集:链接: https://pan.baidu.com/s/1jZoTmoFzaTLWh4lKBHVbEA 密码: 5suq
Dataset 是一个抽象类,所有数据集都需要继承这个类,所有子类都需要重写 __getitem__
的方法,这个方法主要是获取每个数据集及其对应 label,还可以重写长度类 __len__
# -*- codeing = utf-8 -*-
# @Time : 2024/6/15 21:39
# @File : read_data.py
# @Software : PyCharm
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.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 = "dataset/train"
ants_label_dir = "ants_image"
bees_label_dir = "bees_image"
beesData = MyData(root_dir, bees_label_dir)
antsData = MyData(root_dir, ants_label_dir)
trainData = beesData + antsData
当label比较复杂,存储数据比较多时,不可能以文件夹命名的方式,而是以每张图片对应一个txt文件,txt里存储label信息的方式
TensorBoard可视化
- 安装tensorboard
tensorboard不是pytorch自带的,pytorch只提供了使用的接口,所以需要自行下载。
conda install -c conda-forge tensorboard
启动tensorboard
tensorboard --logdir=/path/to/logs/ --port=xxxx
logdir=事件文件所在文件夹名
- add_scalar()
# -*- codeing = utf-8 -*-
# @Time : 2024/6/17 11:15
# @Author : Scarlett
# @File : hello_tb.py
# @Software : PyCharm
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter('logs')
for i in range(10):
writer.add_scalar("y = 2x", 2*i, i)
writer.close()
默认端口6006,为了防止端口冲突,也可以指定其他端口
如果想在同一张图中显示多个曲线,则需要分别建立存放子路径(使用SummaryWriter指定路径即可自动创建,但需要在tensorboard运行目录下),同时在add_scalar中修改曲线的标签使其一致即可:
# -*- codeing = utf-8 -*-
# @Time : 2024/6/17 11:15
# @Author : Scarlett
# @File : hello_tb.py
# @Software : PyCharm
from torch.utils.tensorboard import SummaryWriter
writer1 = SummaryWriter('logs/x')
writer2 = SummaryWriter('logs/y')
for i in range(10):
x = i
y = 2*i
writer1.add_scalar("f", x, i)
writer2.add_scalar("f", y, i)
writer1.close()
writer2.close()
这里也可以用一个writer,但for循环中不断创建SummaryWriter不是一个好选项。此时左下角的Runs部分出现了勾选项,我们可以选择我们想要可视化的曲线。曲线名称对应存放子路径的名称(这里是x和y)。
这部分功能非常适合损失函数的可视化,可以帮助我们更加直观地了解模型的训练情况,从而确定最佳的checkpoint。左侧的Smoothing滑动按钮可以调整曲线的平滑度,当损失函数震荡较大时,将Smoothing调大有助于观察loss的整体变化趋势。
- add_image()& 用numpy.array()对PIL图片进行转换
# -*- codeing = utf-8 -*-
# @Time : 2024/6/17 11:15
# @Author : Scarlett
# @File : hello_tb.py
# @Software : PyCharm
from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np
writer1 = SummaryWriter('logs/x')
writer2 = SummaryWriter('logs/y')
img_path = "dataset/train/ants/275429470_b2d7d9290b.jpg"
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
writer1.add_image("hello_image", img_array, 2, dataformats='HWC')
writer1.add_image("ants", img_array, 1, dataformats='HWC')
for i in range(10):
x = i
y = 2*i
writer1.add_scalar("f", x, i)
writer2.add_scalar("f", y, i)
writer1.close()
writer2.close()
通过滑块显示每一步的图形
重命名title,以单独显示
tranforms图像预处理
从transforms中选择一个class,对它进行创建,对创建的对象传入图片,即可返回出结果
# -*- codeing = utf-8 -*-
# @Time : 2024/6/18 17:17
# @Author : Scarlett
# @File : hello_transforms1.py
# @Software : PyCharm
from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
img_path = "dataset/train/bees/39672681_1302d204d1.jpg"
img = Image.open(img_path)
writer = SummaryWriter("logs")
# how to use transforms
# ToTensor将一个 PIL Image 或 numpy.ndarray 转换为 tensor的数据类型
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
writer.add_image("tensor_img", tensor_img)
writer.close()
# -*- codeing = utf-8 -*-
# @Time : 2024/6/18 21:38
# @Author : Scarlett
# @File : use_transforms.py
# @Software : PyCharm
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer = SummaryWriter("logs")
img = Image.open("dataset/train/bees/586041248_3032e277a9.jpg")
# ToTensor
trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image("totensor", img_tensor)
#nomalize
#用平均值/标准差归一化 tensor 类型的 image(输入)
#图片RGB三个信道,将每个信道中的输入进行归一化
print(img_tensor[0][0][0])
trans_norm = transforms.Normalize([6, 3, 2],[9, 3, 5])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize", img_norm, 2)
writer.close()
PyCharm小技巧设置:忽略大小写,进行提示匹配
一般情况下,你需要输入R,才能提示出Resize。我们想设置,即便你输入的是r,也能提示出Resize,也就是忽略了大小写进行匹配提示:
File—> Settings—> 搜索case—> Editor-General-Code Completion-去掉Match case前的√—>Apply—>OK
#resize
#将输入转变到指定尺寸:transforms.Resize((高度,宽度))
print(img.size)
trans_resize = transforms.Resize([512, 512])
img_resize = trans_resize(img_tensor)
writer.add_image("Resize", img_resize, 0)
print(img_resize)
#compose
#Compose() 中的参数需要是一个列表,Python中列表的表示形式为[数据1,数据2,...]
#在Compose中,数据需要是transforms类型,所以得到Compose([transforms参数1,transforms参数2,...])
trans_resize2 = transforms.Resize(512)
trans_compose = transforms.Compose([trans_resize2, trans_totensor])
img_resize2 = trans_compose(img)
writer.add_image("Compose",img_resize2, 1)
#RandomCrop
#随机裁剪
trans_random = transforms.RandomCrop(200)
trans_compose2 = transforms.Compose([trans_random, trans_totensor])
for i in range(10):
img_crop = trans_compose2(img)
writer.add_image("RandomCrop", img_crop, i)
- 小结:
-
关注输入输出类型
-
多看官方文档
-
关注方法需要什么参数:参数如果设置了默认值,保留默认值即可,没有默认值的需要指定(看一下要求传入什么类型的参数)
-
不知道变量的输出类型可以通过
- 直接print该变量
- print(type()),看结果里显示什么类型
- 断点调试 dubug
-
totensor,在 tensorboard 看一下结果(tensorboard需要tensor数据类型进行显示)
-
torchvision中的数据集使用
CIFAR10 数据集包含了6万张32×32像素的彩色图片,图片有10个类别,每个类别有6千张图像,其中有5万张图像为训练图片,1万张为测试图片
# -*- codeing = utf-8 -*-
# @Time : 2024/6/19 11:27
# @Author : Scarlett
# @File : dataset_transforms.py
# @Software : PyCharm
import torchvision
from torch.utils.tensorboard import SummaryWriter
#把dataset_transform运用到数据集中的每一张图片,都转为tensor数据类型
#CIFAR10数据集原始图片是PIL Image,如果要给pytorch使用,需要转为tensor数据类型(转成tensor后,就可以用tensorboard了)
dataset_transforms = torchvision.transforms.Compose([
torchvision.transforms.ToTensor()
])
train_set = torchvision.datasets.CIFAR10('./data', train=True, transform=dataset_transforms, download=True)
test_set = torchvision.datasets.CIFAR10('./data', train=False, transform=dataset_transforms, download=True)
writer = SummaryWriter(log_dir='logs/logs1')
#显示测试数据集中的前10张图片
for i in range(10):
img, target = test_set[i]
writer.add_image('test_img', img, i)
writer.close()
DataLoader的使用
- Dataset:告诉程序中数据集的位置,数据集中索引,数据集 中有多少数据(一叠扑克牌)
- DataLoader:把数据加载到神经网络中,每次从Dataset中取数据,通过DataLoader中的参数可设置如何取数据(一组牌)
- 参数
- dataset:只有dataset没有默认值,只需把之前自定义的dataset实例化,再放到dataloader中即可
- batch_size:每组抓牌抓几张
- shuffle:是否打乱。默认为False即不打乱,但一般是指定为True
- num_workers:加载数据时采用单个进程还是多个进程,多进程的话速度相对较快,默认为0(主进程加载)。win系统下该值>0会有问题,报错BrokenPipeError
- drop_last:最后不足batch_size的余下是否舍去,不进行取出。例如10张牌每次抽取3张,最后余下1张,若drop_last为True代表舍去这张牌,不取出,否则为False代表不舍去,取出这张牌
# -*- codeing = utf-8 -*-
# @Time : 2024/6/19 14:54
# @Author : Scarlett
# @File : dataloader.py
# @Software : PyCharm
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#准备的测试数据集
test_data = torchvision.datasets.CIFAR10('./data', train=False, transform=torchvision.transforms.ToTensor())
#测试数据集中的第一张图片以及target
test_dataloader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=False)
img, target = test_data[0]
print(img.shape)
print(target)
writer = SummaryWriter("logs/dataloader")
step = 0
for data in test_dataloader:
imgs, targets = data
writer.add_images('dataloader', imgs, step)
step += 1
writer.close()
四、神经网络基础结构
神经网络的基本骨架
前向传播 forward(在所有子类中进行重写)
主要的大将
# -*- codeing = utf-8 -*-
# @Time : 2024/6/19 19:04
# @Author : Scarlett
# @File : nn_module.py
# @Software : PyCharm
import torch
from torch import nn
class Moli(nn.Module):
def __init__(self):
super().__init__()
def forward(self, input):
return input + 1
moli = Moli()
x = torch.tensor(1)
print(moli(x))
卷积操作
# -*- codeing = utf-8 -*-
# @Time : 2024/6/19 21:37
# @Author : Scarlett
# @File : nn_conv.py
# @Software : PyCharm
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)
#(batch,通道数,高,宽)
input = input.reshape(1, 1, 5, 5)
kernel = torch.reshape(kernel, (1, 1, 3, 3))
#stride步长,可以是单个数,或元组(sH,sW) — 控制横向和纵向步长
output1 = F.conv2d(input, kernel, stride=1)
print(output1)
output2 = F.conv2d(input, kernel, stride=2)