文章目录
Log
2022.10.04开启本章的学习
2022.10.13事情好多,做项目、准备中检、读书、准备期末考试、审材料、做实验…啊!继续学习
2022.10.14继续学习
2022.10.17继续学习
2022.10.18继续学习
2022.10.19继续学习
2022.10.20继续学习
2022.10.21继续学习
2022.10.24电脑前几天坏了,自己检查了一下,内存条硬盘啥的都没问题,去维修店检查说是主板烧了,不知道啥时候能修好,今天过节先把文章发出来2022.10.27过两天不忙了把 Transforms 的一点内容给补上
2022.11.22有空了,回来接着搞
2022.11.24继续学习
2022.11.27继续学习
2022.11.28继续学习。弄完了这一章。
一、TensorBoard
1. TensorBoard 的安装
- 打开
P
y
c
h
a
r
m
\rm Pycharm
Pycharm 的终端
T
e
r
m
i
n
a
l
\rm Terminal
Terminal,切换到对应的虚拟环境,我创建了一个名为
Pytorch
的环境,激活并切换指令如下:
conda info -e # 查看虚拟环境
conda activate Pytorch # 切换到项目所用的虚拟环境Pytorch
- 随后输入命令
pip install tensorboard
即可进行安装。
2. SummaryWriter 的使用
- 从
torch
导入:
from torch.utils.tensorboard import SummaryWriter
- 按住
c
t
r
l
ctrl
ctrl 键点击
SummaryWriter
即可查看相关的介绍内容:
"""Writes entries directly to event files in the log_dir to be
consumed by TensorBoard"""
- 是可以向 l o g _ d i r log\_dir log_dir 写入的事件文件,事件文件可以被 T e n s o r B o a r d \rm TensorBoard TensorBoard 进行解析。
- 创建实例:
writer = SummaryWriter("logs")
- 常用的两个函数:
writer.add_image()
writer.add_scalar()
① add_scalar() 的使用
a. 参数说明
- 该函数需要添加标量数据,主要的参数如下:
tag
:生成图像的 titlescalar_value
:Y 轴,纵坐标global_step
:X 轴,横坐标
b. 函数使用
- 运行以下代码绘制图像:
for i in range(100):
writer.add_scalar("y=x", i, i)
c. 使用 Tensorboard
- 运行结束后可以看到在项目路径下多出来一个
logs
文件夹,在 T e r m i n a l \rm Terminal Terminal 运行以下命令打开 T e n s o r b o a r d \rm Tensorboard Tensorboard 窗口:
tensorboard --logdir=code/logs # 参数logdir为事件文件所在文件夹名
- 若多人同时操作,为防止冲突可以添加打开窗口选项:
tensorboard --logdir=code/logs --port=6007# 参数port为指定的打开端口
-
打开的界面如下:
-
我们可以在训练时每隔一定的步数将 t r a i n l o s s train_{loss} trainloss 等指标进行显式地绘制,但是如果在后续的绘制的过程中没有修改图像的 T i t l e Title Title(即参数
tag
,对应上面的y=x
),就会产生下面的情况:
-
所有的不同次的数据混合到了一起,绘制时被自动拟合,对应的解决方法有两种:
- 删除原有文件,重新绘制
- 训练新的模型时重新创建一个子文件夹(即
SummaryWriter("newFolder")
)
② add_image() 的使用
a. 参数说明
- 主要的参数如下:
tag
:生成图像的 titleimg_tensor
:图像(数据类型为torch.Tensor
或numpy.array
或string/blobname
)global_step
:训练的步骤(int
型)
b. 使用 numpy.array() 对 PIL 图片进行转换
- 在控制台执行以下代码查看图片的类型:
from PIL import Image
img_path = "dataset/hymenoptera_data/train/ants/0013035.jpg"
img = Image.open(img_path)
print(type(img)) # <class 'PIL.JpegImagePlugin.JpegImageFile'>
- 可以看到类型并不符合
add_image()
函数里第二个参数的要求,所以我们要使用将其转换为符合要求的类型:
import numpy as np
img_array = np.array(img)
print(type(img_array)) # <class 'numpy.ndarray'>
c. 使用函数
- 虽然我们目前已经将图片转换为了
numpy.array
的格式,但是查看add_image()
函数的具体说明可以发现输入的图片还需要满足 ( 3 , H , W ) \rm (3, H, W) (3,H,W) 的格式,即“通道数、高度、宽度”,执行以下语句:
print(img_array.shape) # (512, 768, 3)
- 发现我们的输入格式是
(
H
,
W
,
3
)
\rm (H, W, 3)
(H,W,3) ,即“高度、宽度、通道数”,因此我们还需要增加一个参数
dataformats
,即原有语句变为如下:
writer.add_image("test", img_array, 1, dataformats='HWC')
- 完整程序:
img_path = "../dataset/hymenoptera_data/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
print(img_array.shape)
writer.add_image("test", img_array, 1, dataformats='HWC')
d. 改变 global_step
- 更换图片并将
global_step
的值改为 2 :
img_path = "../dataset/hymenoptera_data/train/ants/24335309_c5ea483bb8.jpg"
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
print(img_array.shape)
writer.add_image("test", img_array, 2, dataformats='HWC')
-
运行后打开 T e n s o r b o a r d \rm Tensorboard Tensorboard 窗口,如下图所示:
-
拖动图片上方的滑块我们可以看到不同
step
下的图像。我们可以通过这种方式来观察训练模型时提供了哪些数据,或是在对模型进行测试时观察不同阶段的输出结果。
二、Transforms
1. Transforms 的结构及用法
① Transforms 的结构
a. stucture 的使用
- 导入
transforms
:
from torchvision import transforms
- 按住
c
t
r
l
ctrl
ctrl 点击进入查看
transforms
的详细信息,点击 P y c h a r m \rm Pycharm Pycharm 左侧的 s t u c t u r e stucture stucture 可以查看该文件( transforms.py )的结构:
- 我们也可以到
S
e
t
t
i
n
g
s
Settings
Settings 里的
K
e
y
m
a
p
Keymap
Keymap 中修改该选项的快捷键:
b. 常用的类
- 常用的有如下几个类:
Compose
:串联多个图片变换的操作( C o m p o s e s s e v e r a l t r a n s f o r m s t o g e t h e r Composes\ several\ transforms\ together Composes several transforms together )ToTensor
:把PIL Image
或numpy.ndarray
转换为一个tensor
ToPILImage
:把tensor
或ndarray
转换为PIL Image
Normalize(torch.nn.Module)
:正则化Resize(torch.nn.Module)
:改变尺寸CenterCrop(torch.nn.Module)
:中心裁剪
- 我们可以将
T
r
a
n
s
f
o
r
m
s
\rm Transforms
Transforms (也就是
transforms .py
文件)看成一个工具箱,我们的输入是特定格式的图片,使用工具箱里的工具模板(如ToTensor
、Resize
等)创建自己的工具(tool = transforms.ToTensor()
),再对输入进行处理,进而得到我们想要的结果。
② Transforms 的用法
- 通过
ToTensor
来讲解Transforms
的用法,以及什么是tensor
和为什么要用这种数据类型。
a. Transforms.ToTensor 的用法
- 首先用
Image
打开一张图片,输出可以查看图片的类型等信息:
from PIL import Image
img_path = "../dataset/hymenoptera_data/train/ants/24335309_c5ea483bb8.jpg"
img = Image.open(img_path)
print(img)
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x375 at 0x293161BCEE0>
- 通过
transforms .py
文件我们可以看到,类有这样的一个函数,也就是调用该类,输入为PIL Image
或numpy.ndarray
类型的图片,输出为tensor
类型的图片:
def __call__(self, pic):
"""
Args:
pic (PIL Image or numpy.ndarray): Image to be converted to tensor.
Returns:
Tensor: Converted image.
"""
return F.to_tensor(pic)
- 接着创建一个
ToTensor
类的实例,再调用该实例并输出:
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
print(tensor_img) # tensor([[[0.0510, 0.0471, 0.0431, ...
- 此外,我们还可以用前面学到的东西,将
tensor
类型的数据写到 t e n s o r b o a r d tensorboard tensorboard 中并进行查看:
writer.add_image("Tensor_img", tensor_img)
b. 使用 tensor 数据类型的原因
- 通过控制台运行程序,可以看到
tensor
类型的数据包含神经网络中用到梯度、梯度的方法以及使用的设备等信息,有利后续的使用:
c. 创建 numpy.ndarray 类型的数据
- T e r m i n a l \rm Terminal Terminal 中输入以下指令进行安装:
pip install opencv-python
- 在控制台运行以下代码:
import cv2
cv_img = cv2.imread(img_path)
- 可以看到我们得到的
cv_img
就是numpy.ndarray
类型:
2. 常用的 Transforms 函数
__call__(args)
:首先说明一下,创建一个类的实例有两种调用函数的方法,如果该类Clas
有__call__(self, args)
和func(self, args)
两种方法,那么他们调用的方法分别如下:
cla = Clas()
# __call__
cla(args)
# func
cla.func(args)
- 除此之外可以通过进行以下修改(关闭红框中的选项)使得编写代码时自动补全不区分大小写:
① ToTensor
- 上面介绍过了,这里就不多赘述了,直接放代码:
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer = SummaryWriter("logs")
img = Image.open("../images/dog.jpg")
print(img)
# ToTensor
trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image("ToTensor", img_tensor)
- 打开 tensorboard 后结果如下(换完电脑以后浏览器改成了暗色主题):
② Normalize
- 将每个信道中的输入进行归一化,改变输入值的像素变化范围,计算公式为输入值减均值再除以标准差:
output[channel] = (input[channel] - mean[channel]) / std[channel]
- 对应 RGB 图像(三通道)就需要输入每个信道的均值和标准差
Normalize
不支持PIL
格式的图片输入
# Normalize
print(img_tensor[0][0][0]) # tensor(0.0314)
trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
img_norm = trans_norm(img_tensor)
print(img_norm[0][0][0]) # tensor(-0.9373)
writer.add_image("Normalize", img_norm)
- 对变化前后的结果进行输出可以发现数据是有变化的(归一化的图片结果就不展示了,那狗像是被核污染了一样)
③ Resize
- 如果输入是一个序列
(h, w)
的话,就将输入图像的长和宽调整至相应的大小,如果是一个数的话就将小边变为该尺寸,对图像进行等比缩放 - 输入的图像为
PIL
类型,可以在Resize
之后进行ToTensor
操作:
# Resize
print(img.size) # (2048, 2048)
trans_resize = transforms.Resize((512, 512))
# img PIL --(Resize)--> img_resize PIL
img_resize = trans_resize(img)
# img_resize PIL --(ToTensor)--> img_resize Tensor
img_resize = trans_totensor(img_resize)
writer.add_image("Resize", img_resize, 0)
print(img_resize)
④ Compose
Compose
的作用是将多个步骤整合起来,它的输入参数是一个列表,列表中的元素要求是transforms
类型,前一个元素的输出类型要和后一个元素的输入相匹配,否则会报错。
# Compose - resize - 2
trans_resize_2 = transforms.Resize(512)
# PIL --> PIL --> Tensor
trans_compose = transforms.Compose([trans_resize_2, trans_totensor])
img_resize_2 = trans_compose(img)
writer.add_image("Resize", img_resize_2, 1)
⑤ RandomCrop
- 输入:一个序列
(h, w)
代表长和宽,或者一个整数size
,但是和前面的Resize
的等比缩放不同,这里会裁剪出一个边长为size
的正方形。
# RandomCrop
trans_random = transforms.RandomCrop(512)
trans_compose_2 = transforms.Compose([trans_random, trans_totensor])
for i in range(10):
img_crop = trans_compose_2(img)
writer.add_image("RandomCrop", img_crop, i)
- 裁剪的结果如下:
- 输入改成序列:
# RandomCrop
trans_random = transforms.RandomCrop((500, 1000))
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)
- 裁剪结果如下:
注意事项
- 关注输入输出类型
- 关注需要填写的参数
- 尽量看官方文档,准确性要高一些
总结
- 本文主要介绍了
T
e
n
s
o
r
B
o
a
r
d
\rm TensorBoard
TensorBoard 的安装以及其中的
S
u
m
m
a
r
y
W
r
i
t
e
r
\rm SummaryWriter
SummaryWriter 的使用,包括函数
add_scalar()
以及add_image()
的使用方法。 - 同时还介绍了
T
r
a
n
s
f
o
r
m
s
\rm Transforms
Transforms 的结构及用法,以及诸如
ToTensor
、Normalize
、Resize
、Compose
、RandomCrop
等的常用的函数的用法。