transform 是一个工具箱,在使用工具时,首先得自己制定一个工具,接着传入参数,输出结果。
tensor_img里面有些属性,tensor数据类型可以理解为包装了 反向神经网络理论基础的参数。
transform实际是一个python文件,里面有很多class文件,可以通过查看pycharm左边结构查看,其中这些选中的是最常用的类。
P11
PIL是用Image.open()后的返回类型。
tensor就是transforms 包中ToTensor类的返回方法。
narrays 是用cv.imread()方法打开。
python中__call__的使用
新建CallTest文件,写入下方代码👇
class Person:
def __call__(self, name):
print("__call__"+"Hello" +name)
def hello (self , name):
print("hello"+name)
person = Person()
person("zhangsan")
#自动调用,
person.hello("lisi")
#调用了hello方法
运行结果👇
__call__Hellozhangsan
hellolisi
call函数在实例绑定时被调用,在执行person()时/类的实例带有参数时被调用1。
另一种解释:
ToTensor的使用
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision.transforms import transforms
img_path = "dataset/train/bees/39747887_42df2855ee.jpg"
writer = SummaryWriter("logs")
img = Image.open(img_path)
trans_tensor= transforms.ToTensor()
#这里的ToTensor()就是有call方法,如果将参数放入进去,就可以zhi'diao'yong
img_tensor = trans_tensor(img)
writer.add_image("img_tensor" , img_tensor)
writer.close()
接着再在终端键入tensorboard --logdir= logs
打开浏览器选择image就可以查看刚刚写入的照片。
Normalize的使用
class Normalize(torch.nn.Module):
"""Normalize a tensor image with mean and standard deviation.
This transform does not support PIL Image.
用均值和标准差对张量图像进行归一化。这个变换不支持PIL。
Given mean: ``(mean[1],...,mean[n])`` and std: ``(std[1],..,std[n])`` for ``n``
channels, this transform will normalize each channel of the input
``torch.*Tensor`` i.e.,
``output[channel] = (input[channel] - mean[channel]) / std[channel]``
.. note::
This transform acts out of place, i.e., it does not mutate the input tensor.
Args:
mean (sequence): Sequence of means for each channel.
std (sequence): Sequence of standard deviations for each channel.
inplace(bool,optional): Bool to make this operation in-place.
"""
def __init__(self, mean, std, inplace=False):
super().__init__()
self.mean = mean
self.std = std
self.inplace = inplace
def forward(self, tensor: Tensor) -> Tensor:
"""
Args:
tensor (Tensor): Tensor image to be normalized.
Returns:
Tensor: Normalized Tensor image.
"""
return F.normalize(tensor, self.mean, self.std, self.inplace)
def __repr__(self):
return self.__class__.__name__ + '(mean={0}, std={1})'.format(self.mean, self.std)
因为官文说有三个信道,所以提供3个标准差。
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])
writer.add_image("Normalize",img_norm)
writer.close()
在传入数据类型时,需要传入tensor数据类型,所以需要用到上一个ToTensor数据类型img_tensor
。
归一化(Normalize)的公式如下:
output[channel] = (input[channel] - mean[channel]) / std[channel]
举例:(input - 0.5) = 2 * input -1
input [ 0, 1 ] , result = [ -1 , 1]
forward什么时候被调用?
一般是在创建类的实例,调用于类方法call
中4。
>>>class A():
def __call__(self,param):
print("i can called like a function")
print(f"the parameter which have been input is {param},its type is {type(param)}")
result = self.forward(param)
return result
def forward(self,param):
print("forward function is called")
print(f"in forward function , the type of input parameter is {type(param)}, and its value is {param}")
return param
>>>a = A()
>>>input_param = a('parameter')
i can called like a function
the parameter which have been input is parameter,its type is <class 'str'>
forward function is called
in forward function , the type of input parameter is <class 'str'>, and its value is parameter
>>>print(f"对象a传入的参数是{input_param}")
对象a传入的参数是parameter
pytorch主要也是按照__call__,__init__,forward三个函数来实现网络层之间架构的
repr什么时候被调用?
repr是什么函数?——将对象转化为供解释器读取的形式。
语法repr[object]
、参数object--对象
、返回值-返回该对象的String形式5。
assert语句6
用来检查某个条件是否为真,如果该条件非真,那么在这条件之前添加条assert,会在执行时引发一个错误。
>>>mylist = ['item1']
>>>assert len(mylist)>=1
>>>mylist.pop()
'item1'
>>>repr(mylist)
'[]'
>>>assert len(mylist)>=1
Traceback (most recent call last):
File "D:\SetUpSoftWare\Anaconda3\envs\test2\lib\code.py", line 90, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
AssertionError
如上所示,使用了repr
和assert
这个方法和这条语句。在mylist没有元素时,引发错误。
P12
Resize的使用
根据官文得知,
- 如果给定参数为(h,w),那尺寸裁剪为该序列大小(元组)
- 若给定参数为整数,则匹配原图片最小边为该整数,并成比例缩小。
举例:
#resize的使用
print("原始尺寸为:",img.size)
trans_size = transforms.Resize([512 , 512])
#方式1
#此时的img还是PIL类型,如果想在tensorboard进行显示,需要用到totensor。
img_resize = trans_size(img)
img_resize = trans_tensor(img_resize)#这里 是将PILImage类型转换为了Tensor类型。
writer.add_image("resize" , img_resize , global_step=0)
#与上面一致,增加了转换类型的解释
#img PIL类型 -> Resize操作 -> img PIL类型
trans_size=transforms.Resize([512,512])
#img PIL类型 -> ToTensor操作 -> tensor类型
trans_size = trans_tensor(trans_size)
writer.add_image("Resize",trans_img ,global_step = 1)
#方式2
#此时Resize输入为512,即裁剪为原图片中短边为512,长边与短边比例保持不变。
img_resize = transforms.Resize(512)
#img PIL类型 -> Resize操作 -> img PIL类型
trans_img = img_resize(img)
#img PIL类型 -> ToTensor操作 -> tensor类型
trans_img = trans_totensor(trans_img)
writer.add_image("Resize",trans_img,global_step=2)
[第15行img来源](#ToTensor 的使用)7
compose的用法
compose的参数需要是一个列表,python中,列表的表示形式为【数据1, 数据2,…】,compose中,数据需要是transforms类型,所以得到,compose(【transforms参数1 , transforms参数2,……】)。
compose要关注输入和输出。
#对于以上Resize,还可以用compose流程化处理
trans_compose = transforms.Compose([img_resize , trans_totensor ])
#因为第一步是对图片进行裁剪,所以类型传入resize时为img PIL 传出时一致, 而第二步为将PIL数据类型转换为tensor数据类型
trans_img = trans_compose(img)
#展示
writer.add_image("trans_compose" , trans_img , 0)
后面一个参数所需要的输入,和前面一个参数所需要的输出是否匹配。
随机裁剪RandomCrop
官文中显示,若给定一元组,则裁剪为对应的长宽;若给定一数字,则裁剪为正方形。
#RandomCrop
trans_random = transforms.RandomCrop((309 , 500))
trans_compose_2 = transforms.Compose([trans_random , trans_tensor])
for i in range(10):
img_crop = trans_compose_2(img)
writer.add_image("RandomCrop" , img_crop , i )
总结
- 要关注输入类型和输出类型。·多看官方文档。一般的参数保留默认即可。
- 关注方法需要什么参数。
不知道返回值可以使用print,type,debug,或者上网。
一定要注意转换为totensor,在tensorboard中看看。
忽略大小写匹配👇
Setting→Editor→General→Code Completion 取消选中MatchCase
问题
已解决
按照道理来说,应该是500×366更换为500×512,但是为什么是699×512呢?
只给一个数,会进行等比缩放,不改变高和宽的比例。进行实验之后确实这样。
transform 只是对图片进行处理。
—未解决
dataloader中,img, target都是什么?
imgs是test_loader中64个数据的img的集合,targets是其数据的target的集合。
如何把数据集和transform结合在一起。&介绍标准数据集如何组织下载查看使用。
coco数据集一般语义分割,目标检测经常使用。
MNIST是入门数据集——手写文字。
CIFAR一般用于物体识别。
torchvision.datasets,以及如何联合transform使用。
2022年10月12日
数据集的使用
pytorch数据集在官网可以看到。有很多数据集,举例来说为👇
https://pytorch.org/vision/stable/datasets.html
这个图片即显示为图片分类数据集,CIFAR10数据集一般用于物体识别。
https://pytorch.org/vision/stable/generated/torchvision.datasets.CIFAR10.html#torchvision.datasets.CIFAR10
由这里的参数可以知道👇
CIFAR10 Dataset.
Parameters
root (string) – Root directory of dataset where directory cifar-10-batches-py exists or will be saved to if download is set to True.#数据集在哪里
train (bool, optional) – If True, creates dataset from training set, otherwise creates from test set.
#若为真,则创建数据集为训练集,若为假,则创建为测试集。
transform (callable, optional) – A function/transform that takes in an PIL image and returns a transformed version. E.g, transforms.RandomCrop
#若想对数据集中数据进行什么样的变化,便可以在该参数中指定变化类型。
target_transform (callable, optional) – A function/transform that takes in the target and transforms it.
#对target进行transform。
download (bool, optional) – If true, downloads the dataset from the internet and puts it in root directory. If dataset is already downloaded, it is not downloaded again.
#若设置为真,则自动下载数据集。否则则不下载。
练习代码👇
#
import torchvision
from torch.utils.tensorboard import SummaryWriter
#下载数据集,同时查看参数并写入。
#root为保存位置,此时保存为同一目录下datasets文件夹。
#train,true为训练集,false为测试集
#download,true为默认下载至root文件夹中,
#transform (callable, optional) ,将PILImage转换为tensor类型。
#下面一行代码是创建了自己的工具。用来对PILImage图像进行转换。
dataset_transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor()
])
#有了自定义工具之后,就可以在数据集中对PILImage转换为Tensor数据类型。
train_set = torchvision.datasets.CIFAR10(root="./dataset" , train=True , download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset",train=False , download=True)
#除此之外,还可以直接通过控制台链接下载数据集,新建对应文件夹拖拽其中即可。
img , target = test_set[0]
#查看数据集中的第一个数据集
print(test_set[0])
print(img)
# 为什么这两个显示的不同呢?不应该一样吗?
#弄明白test_set 是什么,它是一个数据集,并不简单只包括里面的每一项,还有其他属性。
#test_set[0]表示什么?img又表示什么?img=1360,而test_set[0]=1192,img地址更远。
# 此时里面classes是列表。target[0]则为airplane
# print(test_set.classes)
# img.show()
#这样就分别获得PILImage以及对应target
#验证如下
# print(img)
# print(target)
# print(test_set.classes[target])
print(test_set[0])
writer = SummaryWriter("P10")
for i in range(10):
img , target = test_set[i]
writer.add_image("test_set" , img , i)
writer.close()
之后再在终端中输入 tensorboard logdir P10,就可以打开tensorboard在网页中查看了。
dataloader的使用
dataset只是说明数据在数据集中哪个位置,而dataloader是加载器,要加载到神经网络中,说明数据取多少,怎么取出来。
dataloader网址:https://pytorch.org/docs/stable/data.html?highlight=dataloader#torch.utils.data.DataLoader
下面仅摘取主要参数(常用)
Parameters
dataset (Dataset) – dataset from which to load the data.
#其他参数有数据集,这个没有。数据集就是告诉我们数据在什么地方,总共有多少条数据。用时,只需要将之前自定义的Dataset实例化放在此处即可。
batch_size (int, optional) – how many samples per batch to load (default: 1).
每次载入数据时载入多少。
shuffle (bool, optional) – set to True to have the data reshuffled at every epoch (default: False).
num_workers (int, optional) – how many subprocesses to use for data loading. 0 means that the data will be loaded in the main process. (default: 0)
加载数据时应采用单进程还是多个进程。默认情况下是0,采用主进程加载。有时会出现问题试试设置为0,看是否会解决问题。
drop_last (bool, optional) – set to True to drop the last incomplete batch, if the dataset size is not divisible by the batch size. If False and the size of dataset is not divisible by the batch size, then the last batch will be smaller. (default: False)
当无法正好取出对应batch_size时,是否舍去。
true:舍去;false:保留
具体使用过程如下👇
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#准备的测试集👇
test_data = torchvision.datasets.CIFAR10(root="./dataset" , train=False , transform = torchvision.transforms.ToTensor() )
#若要查看test_data中的第一个数据,点击进入方法,查看getitem方法,查看后发现先返回img, 后返回target。
test_loader = DataLoader(dataset=test_data,batch_size=64, drop_last= True , num_workers=0 , shuffle=True)
#batch_size 为每次打包的数量。drop_last若设置为false,则不舍弃最后的几张零散图片,若设置为true,则舍弃最后的零散图片保持美观。
# shuffle,是每次运行时是否重新洗载入的数据集,使其保持乱序。
#测试数据集中第一张图片及target
img , target = test_data[0]
print (img.shape)
print(target)
#此时发现通道为3通道,大小为32×32
#batch_size == 4 , 其实就是取四个数据,对它们的img,target打包
for data in test_loader:
imgs , targets = data
print(imgs.shape)
print(targets)
#运行结束之后,看到torch.size([4,3, 32,32])即为4张图片,都是3通道,且为32×32。
# 下面是查看载入的img效果。使用tensorboard
writer = SummaryWriter("dataloader")
step = 0
for data in test_loader:
imgs , targets = data
writer.add_images("data_loader_no_shuffle" , imgs , step)
step+=1
writer.close()
for epcho in range(2):
for data in test_loader:
imgs , targets = data
writer.add_images("Epcho:{}".format(epcho) , imgs , step)
step+=1
writer.close()
参考资料
https://blog.csdn.net/xiaofeng_yan/article/details/6632838 ↩︎
https://foofish.net/magic-method.html ↩︎
https://blog.csdn.net/xxboy61/article/details/88101192 ↩︎
https://blog.csdn.net/xxboy61/article/details/88101192 ↩︎
https://www.runoob.com/python/python-func-repr.html、https://www.cnblogs.com/sddai/p/14884688.html ↩︎
https://wizardforcel.gitbooks.io/a-byte-of-python/content/95.html ↩︎
https://www.cnblogs.com/xypersonal/p/16155184.html ↩︎