Pytorch学习

本文详细介绍了PyTorch中数据加载的步骤,包括自定义Dataset和使用ImageFolder,讲解了DataLoader的使用,以及如何使用tensorboard进行可视化。还涉及了数据预处理的转换操作,如ToTensor、Normalize、Resize等。此外,文章还讨论了如何在代码中使用os、shutil、TensorBoard、torchvision等库,并介绍了数据增强、异常处理、进度条工具tqdm的使用。
摘要由CSDN通过智能技术生成

B站小土堆教程 小土堆 Python常用模块


查看pytorch是否可用 pycharm的一个技巧,在函数的括号里按ctrl+P可以看要写哪些参数。进入debug模式可以直接在debugger的python console里查看变量值。

import torch
print( torch.cuda.is_available() )

如何在pytorch环境中安装jupyter notebook和使用 教程

学习和使用中的两个常用的辅助查询函数
dir():打开package库看看里面有什么,例如dir(torch),看看torch里有什么
help():说明书,例如help(torch.cuda.is_available)

一行语句如果嫌太长可以换行但是最好在最后加一个\。 一个项目的相对路径是以当前的程序文件来说的。

如果想在一行中写多个语句,中间可以用逗号','或者分号';'隔开。一个变量想打印可以直接在这个变量后面加.print然后回车。

pytorch加载数据

Dataset (一般来说Dataset都自己写,然后继承自Dataset)

通常在一个完整的 神经网络训练流程中,我们常常需要构建Dataset和Dataloader用于后续模型训练时的数据读取,一般我们自己定义一个Dataset类,重写 __geiitem____len__函数来构建Dataset。然而对于简单 图像分类任务而言,无需自己定义Dataset类,调用 torchvision.datasets.ImageFolder函数即可构建自己的Dataset,非常方便。

我对Dataset的理解是不管用什么方法制作Dataset,最后Dataset都必须有这个功能:

Dataset[0]=(img_data, target),然后再放到Dataloader里打包batchsize,多一个维度。

Dataset应该具有的功能

获取数据及其label和数据集长度,所以必须要实现三个方法__init__, _getitem__, __len__

  • 如何获取每一个数据及其label,__getitem__(self, idx) 基于一个索引返回一个训练样本

  • 告诉我们总共有多少的数据

from torch.utils.data import Dataset

ImageFolder使用详解

用torchvision.datasets.ImageFolder( )读取数据,在读取单通道数据(灰度图)时此函数会自动将单通道图像转换为三通道图像(r=g=b)。

ImageFolder好像会自动调用PIL来读取图片,不需要自己在前面再写一步读图了。

ImageFolder假设所有的文件按文件夹保存,每个文件夹下存储同一个类别的图片,文件夹名为类名,其构造函数如下:

dataset=torchvision.datasets.ImageFolder(
                       root, transform=None, 
                       target_transform=None, 
                       loader=<function default_loader>, 
                       is_valid_file=None)
root:图片存储的根目录,即各类别文件夹所在目录的上一级目录。
transform:对图片进行预处理的操作(函数),原始图片作为输入,返回一个转换后的图片。
target_transform:对图片类别进行预处理的操作,输入为 target,输出对其的转换。 如果不传该参数,即对 target 不做任何转换,返回的顺序索引 0,1, 2…
loader:表示数据集加载方式,通常默认加载方式即可。
is_valid_file:获取图像文件的路径并检查该文件是否为有效文件的函数(用于检查损坏文件)

用ImageFolder输出的dataset的结构就是[(img_data,class_id),(img_data,class_id),…],比如dataset[0]就是(一张图片, 标签)

print(dataset[0])
输出:
(tensor([[[-0.5137, -0.4667, -0.4902,  ..., -0.0980, -0.0980, -0.0902],
         [-0.5922, -0.5529, -0.5059,  ..., -0.0902, -0.0980, -0.0667],
         [-0.5373, -0.5294, -0.4824,  ..., -0.0588, -0.0824, -0.0196],
         ...,
         [-0.3098, -0.3882, -0.3725,  ..., -0.4353, -0.4510, -0.4196],
         [-0.2863, -0.3647, -0.3725,  ..., -0.4431, -0.4118, -0.4196],
         [-0.3412, -0.3569, -0.3882,  ..., -0.4667, -0.4588, -0.4196]],
        [[-0.6157, -0.5686, -0.5922,  ..., -0.2863, -0.2784, -0.2706],
         [-0.6941, -0.6549, -0.6078,  ..., -0.2784, -0.2784, -0.2471],
         [-0.6392, -0.6314, -0.5843,  ..., -0.2471, -0.2706, -0.2078],
         ...,
         [-0.4431, -0.5059, -0.5059,  ..., -0.5608, -0.5765, -0.5451],
         [-0.4196, -0.4824, -0.5059,  ..., -0.5686, -0.5373, -0.5451],
         [-0.4745, -0.4902, -0.5294,  ..., -0.5922, -0.5843, -0.5451]],
        [[-0.6627, -0.6157, -0.6549,  ..., -0.5059, -0.5216, -0.5137],
         [-0.7412, -0.7020, -0.6706,  ..., -0.4980, -0.5216, -0.4902],
         [-0.6863, -0.6784, -0.6471,  ..., -0.4667, -0.4902, -0.4275],
         ...,
         [-0.6000, -0.6549, -0.6627,  ..., -0.6784, -0.6941, -0.6627],
         [-0.5765, -0.6314, -0.6471,  ..., -0.6863, -0.6549, -0.6627],
         [-0.6314, -0.6314, -0.6392,  ..., -0.7098, -0.7020, -0.6627]]]), 0)

用ImageFolder输出的dataset还有以下三种属性:

  • self.classes:用一个 list 保存类别名称

  • self.class_to_idx:类别对应的索引,与不做任何转换返回的 target 对应

  • self.imgs:保存(img-path, class) tuple的 list

print(dataset.classes)  #根据分的文件夹的名字来确定的类别
print(dataset.class_to_idx) #按顺序为这些类别定义索引为0,1...
print(dataset.imgs) #返回从所有文件夹中得到的图片的路径以及其类别
输出:
['cat', 'dog']
{'cat': 0, 'dog': 1}
[('./data/train\\cat\\1.jpg', 0), 
 ('./data/train\\cat\\2.jpg', 0), 
 ('./data/train\\dog\\1.jpg', 1), 
 ('./data/train\\dog\\2.jpg', 1)]

torchvision.datasets.ImageFolder使用详解(讲的很清楚)

讲的也还可以

读取一张图片

路径的话用相对路径比较好,因为这样假如换电脑换系统跑代码,绝对路径会发生变化,但只要项目文件不变,相对路径就不会变。另外要注意使用相对路径要保证在同一目录下,如果不是同一目录就要加../,. / 代表目前所在的目录; . . / 代表上一层目录; / 代表根目录。win系统下路径斜杠最好换成/,这样就不会有转义符了。

#读取一张图片的代码
from PIL import Image

img_path = "D:\\Python\Projects_all\\小土堆课程\\hymenoptera_data\\train\\ants\\0013035.jpg" 
                          #win系统记得加两个斜杠\\,表示转义
img = Image.open(img_path) #根据路径读取图片给img变量,可以用python控制台,里面可以显示很多变量信息
print(img.size) #查看图片尺寸,好像并不能看到通道数
img.show()      #打开图片

读取一个文件夹里的所有图片的文件名,并放到一个列表

from PIL import Image
import os

dir_path = "D:\\Python\\Projects_all\\小土堆课程\\hymenoptera_data\\train\\ants" 
            #win系统要加双斜杠,转义符号
img_path_list = os.listdir(dir_path)  #把文件夹里的所有东西的名字变成一个列表
print(img_path_list)  
img0_path = dir_path + "\\" + img_path_list[0]  #第一张图片的路径,手动写路径
img0_path = os.path.join(dir_path,img_path_list[0]) 
            #这个函数可以根据不同系统自动合并路径,两种方法,第二种更好
img0 = Image.open(img0_path)  #读取第一张图片
img0.show()               #打开 查看第一张图片

img0_path = os.path.join(dir_path,img_path_list[0]) #这个函数可以根据不同系统自动合并路径,不同系统斜杠不同

创建数据集(一般来说Dataset都自己写,然后继承自Dataset)

from torch.utils.data import Dataset
from PIL import Image
import os

class MyData(Dataset):  #创建一个MyData类,继承自Dataset类,这样就继承了Dataset的一部分资源,自己也可以添加一些资源
    def __init__(self,root_dir,label_dir):
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.dir_path = os.path.join(self.root_dir, self.label_dir)
        self.img_path = os.listdir(self.dir_path)  #把文件里的所有东西的名字做成列表

    def __getitem__(self, idx): # 基于一个索引返回一个训练样本
        img_name = self.img_path[idx]  #找到对应索引号的图片名字
        img_idx_path = os.path.join(self.root_dir, self.label_dir, img_name) #写出完整路径
        img = Image.open(img_idx_path)  #读取图片
        label = self.label_dir  #图片标签
        return img, label

    def __len__(self):
        return len(self.img_path)

root_dir = "D:\\Python\\Projects_all\\小土堆课程\hymenoptera_data\\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)) #输出124
print(len(bees_dataset)) #输出121

img0, label = ants_dataset[0]
img0.show() #显示蚂蚁数据集的第一张图片

train_dataset = ants_dataset + bees_dataset  #两个数据集合并了,
           # 试了下必须用MyData(Dataset)继承Dataset才行,普通类实例化出来的是不行的
print(len(train_dataset)) #输出245

from torch.utils.data import Dataset可以合并数据集

Dataset与DataLoader详细使用教程deep_thoughts DATASETS & DATALOADERS pytorch官方Tutorials 下面是pytorch官方的代码示例

import os
import pandas as pd
from torchvision.io import read_image

class CustomImageDataset(Dataset):
    def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
        self.img_labels = pd.read_csv(annotations_file)
        self.img_dir = img_dir
        self.transform = transform
        self.target_transform = target_transform

    def __len__(self):
        return len(self.img_labels)

    def __getitem__(self, idx):
        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
        image = read_image(img_path)
        label = self.img_labels.iloc[idx, 1]
        if self.transform:
            image = self.transform(image)
        if self.target_transform:
            label = self.target_transform(label)
        return image, label

torch.from_numpy()把数组转换成张量

torch.from_numpy()方法把数组转换成张量,且二者共享内存,对张量进行修改比如重新赋值,那么原始数组也会相应发生改变。

>>> a = numpy.array([1, 2, 3])
>>> t = torch.from_numpy(a)
>>> t
tensor([ 1, 2, 3])
>>> t[0] = -1
>>> a
array([-1, 2, 3])

torch.Tensor也可以将数组转换成tensor,但是使用torch.from_numpy更加安全,使用tensor.Tensor在非float类型下会与预期不符。

  1. 当转换的源是float类型,torch.Tensortorch.from_numpy会共享一块内存!且转换后的结果的类型是torch.float32

  1. 当转换的源不是float类型,torch.Tensor得到的是torch.float32,而torch.from_numpy则是与源类型一致torch.from_numpy VS torch.Tensor

Dataloader (拆分成多个batch)(输出的tensor都是NCHW维度的

为后面的网络提供不同的数据形式。DataLoader是一个可迭代的数据装载器,组合了数据集和采样器,并在给定数据集上提供可迭代对象。可以完成对数据集中多个对象的集成。官方文档

CLASS DataLoader
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=None, sampler=None,
batch_sampler=None, num_workers=0, collate_fn=None, pin_memory=False,
drop_last=False, timeout=0, worker_init_fn=None, multiprocessing_context=None,
generator=None, *, prefetch_factor=2, persistent_workers=False, pin_memory_device='')
先导概念介绍: 转自
Epoch: 所有训练样本都已输入到模型中,称为一个epoch
Iteration: 一批样本(batch_size)输入到模型中,称为一个Iteration
Batchsize: 一批样本的大小, 决定一个epoch有多少个Iteration
常用的主要有以下五个参数:
dataset(数据集):需要提取数据的数据集, Dataset对象
batch_size(批大小):每一次装载样本的个数,int型
shuffle(洗牌):进行新一轮epoch时是否要重新洗牌,Boolean型
num_workers:是否多进程读取机制
drop_last:当样本数不能被batchsize整除时, 是否舍弃最后一批数据

官方文档

DataLoader的使用

使用CIFAR10的测试数据集来完成DataLoader的使用。

导入并实例化DataLoader

创建一个dataloader,设置批大小为4,每一个epoch重新洗牌,不进行多进程读取机制,不舍弃不能被整除的批次。

#导入数据集的包
import torchvision.datasets
#导入dataloader的包
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#创建测试数据集
test_dataset = torchvision.datasets.CIFAR10(root="./CIRFA10",train=False,transform=torchvision.transforms.ToTensor())
#创建一个dataloader,设置批大小为4,每一个epoch重新洗牌,不进行多进程读取机制,不舍弃不能被整除的批次
test_dataloader = DataLoader(dataset=test_dataset,batch_size=4,shuffle=True,num_workers=0,drop_last=False)
数据集中数据的读取

由于数据集中的数据已经被我们转换成了tensor型,我们用dataset[0]输出第一张图片,使用shape属性输出tensor类型的大小,target代表图片的标签。

img,target = test_dataset[0]
print(img.shape,target)
输出:torch.Size([3,32,32]) 3  图片有RGB3个通道,大小为32*32,标签target为3。
DataLoader中数据的读取

在dataset中,每一个数据样本元组由一张图片对象img和一个标签target组成;

而dataloader中会分别对一个批次中的图片和标签进行打包,因此dataloader中,每一个对象元组由batchsize张图片对象imgs和batchsize个标签targets组成。(注意取数据的时候并不是按顺序取的,采样器sampler默认是随机采样,也就是说抓取四张图片的时候是随机取的)

  • 对一个batchsize批次中的所有图片对象进行打包,形成一个对象,我们叫它imgs

  • 对一个batchsize批次中所有的标签进行打包,形成一个对象,我们叫它targets

我们需要通过for循环来取出loader中的对象,loader中的对象个数=数据集中对象个数/batch_size,故应为10000/4=2500个对象。

在dataloader中取数据出来for循环训练时可以这么写,用for data in test_dataloader:来遍历数据

#导入数据集的包
import torchvision.datasets
#导入dataloader的包
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#创建测试数据集
test_dataset = torchvision.datasets.CIFAR10(root="./CIRFA10",train=False,transform=torchvision.transforms.ToTensor())
#创建一个dataloader,设置批大小为4,每一个epoch重新洗牌,不进行多进程读取机制,不舍弃不能被整除的批次
test_dataloader = DataLoader(dataset=test_dataset,batch_size=4,shuffle=True,num_workers=0,drop_last=False)
 
#测试数据集中第一张图片对象
img,target = test_dataset[0]
print(img.shape,target)
 
#打印数据集中图片数量
print(len(test_dataset))
 
#loader中对象
for data in test_dataloader:
    imgs,targets = data
    print(imgs.shape)
    print(targets)
 
#dataloader中对象个数
print(len(test_dataloader))

loader中的对象格式:

  • imgs的维度变成了4*3*32*32,即四张图片,每张图片3个通道,每张图片大小为32*32。

  • targets里有4个target,分别是四张图片的标签target,组合到一起了。

在dataloader中取数据出来for循环训练时也可以这么写,用iter(),next()一遍遍迭代

for iteration in range(epochs):
    AE_Encoder.train()  #  让模型进入训练状态
    AE_Decoder.train()
    
    data_iter_VIS = iter(dataloader_VIS) # 生成可迭代对象
    data_iter_IR  = iter(dataloader_IR)  # dataloader_VIS已经经过了dataloader了
    
    for step in range(Iter_per_epoch):
        data_VIS, _ = next(data_iter_VIS)
        data_IR,  _ = next(data_iter_IR)
        if is_cuda:
            data_VIS = data_VIS.cuda()
            data_IR  = data_IR.cuda()
        optimizer1.zero_grad() # 梯度清零
        optimizer2.zero_grad()
…………………………

使用tensorboard可视化效果

修改数据集的batchsize为64,writer中调用的方法为add_images(),因为需要读取的图片有多张

#导入数据集的包
import torchvision.datasets
#导入dataloader的包
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#创建测试数据集
test_dataset = torchvision.datasets.CIFAR10(root="./CIRFA10",train=False,transform=torchvision.transforms.ToTensor())
#创建一个dataloader,设置批大小为64,每一个epoch重新洗牌,不进行多进程读取机制,不舍弃不能被整除的批次
test_dataloader = DataLoader(dataset=test_dataset,batch_size=64,shuffle=True,num_workers=0,drop_last=False)
 
writer = SummaryWriter("log")
 
#loader中对象
step = 0
for data in test_dataloader:
    imgs,targets = data
    writer.add_images("loader",imgs,step)
    step+=1
 
writer.close()

结果如下所示,可以看到一个step中有64张图片。

改变shuffle

每一轮epoch之后就是分配完了一次数据,而shuffle决定了是否在新一轮epoch开始时打乱所有图片的属性进行分配。

在代码中epoch就是最外层的循环,假设我们的epoch=2,即需要分配两次数据:

  • shuffle=TRUE代表第一轮循环结束后会打乱数据集中所有图片的顺序重新进行分配。

  • shuffle=FALSE代表第一轮循环结束后不打乱数据集中所有图片的顺序,还是按原顺序进行分配。

#导入数据集的包
import torchvision.datasets
#导入dataloader的包
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
 
#创建测试数据集
test_dataset = torchvision.datasets.CIFAR10(root="./CIRFA10",train=False,transform=torchvision.transforms.ToTensor())
#创建一个dataloader,设置批大小为64,每一个epoch重新洗牌,不进行多进程读取机制,不舍弃不能被整除的批次
test_dataloader = DataLoader(dataset=test_dataset,batch_size=64,shuffle=True,num_workers=0,drop_last=True)
 
writer = SummaryWriter("log")
 
#loader中对象
 
for epoch in range(2):
    step = 0
    for data in test_dataloader:
        imgs, targets = data
        writer.add_images("Epoch:{}".format(epoch), imgs, step)
        step += 1
 
writer.close()

可以看到shuffle=True时epoch=0和epoch=1的每一个step中的图片不同了,说明每一轮大循环开始前都在数据集中重新打乱了顺序。

import os os库的用法

python os库用法详解

获取目录列表 os.listdir(目录)

img_path_list = os.listdir(dir_path)

把文件夹里的所有东西的名字变成一个列表,注意返回顺序是任意的

os.listdir用法,如何找到文件里的jpg

os.listdir(path)返回文件列表的顺序是任意的,sort排序方法

路径拼接 os.path.join(path,name) 可以不止两个参数合并

img0_path = os.path.join(dir_path,img_path_list[0]) #这个函数可以根据不同系统自动合并路径

重命名文件或目录 os.rename()

os 模块提供了重命名文件和目录的函数 rename(),如果指定的路径是文件,则重命名文件;反之,如果执行的路径是目录,则重命名目录。

基本语法格式:os.rename(src , dst)

  • os.rename("D:\\demo\\a.txt","D:\\demo\\b.txt") # 重命名文件,将 a.txt 文件(完整路径为:D:\demo\a.txt)重命名为 b.txt 文件。

  • os.rename("D:\\demo","D:\\new") # 重命名目录,和重命名文件基本相同,只需要将文件路径替换为目录路径即可。例如,将 D:\demo 目录重命名为 new 目录。

创建目录(判断该目录是否存在,不存在则创建)

os.mkdirs(dir,exist_ok=False) 默认exist_ok=False ,如果目录已存在会抛出异常,不存在则创建。

法一:

import os
if not os.path.exists(dir):
    os.mkdirs(dir)

法二:

exist_ok=False 默认,如果目录已存在抛出异常,不存在则创建。True,若不存在则创建,若存在不会抛异常,继续让它存在。

os.makedirs(dir, exist_ok=True)

shutil文件操作库

Python的shutil模块 shutil提供了对文件(夹)复制,移动,删除,压缩和解压缩的方法。

文件复制

shutil.copy(src, dst)

shutil.copyfile(src, dst)

TensorBoard

conda install tensorboard 安装

from torch.utils.tensorboard import SummaryWriter

writer.add_scalar( ) 遇到报错或者不知道参数可以点进去看看函数注释

from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs") # 把对应的事件文件存到logs目录里,如果没有会自动创建

# writer.add_image()
# y = 2x
for i in range(100):
    writer.add_scalar("y=2x", 2*i, i) #第一个参数是图表标题,第二个参数是y轴数值,第三个
                              #参数是步数,相对于x轴。具体参数可以ctrl+左键 点进去看看
writer.close()

代码写好之后先run一下,然后当前目录下就会多一个logs目录,里面存了tensorboard保存的事件文件。

接下来用终端terminal打开这个事件文件,

tensorboard --logdir=D:\Python\Projects_all\小土堆课程\代码\logs

logdir后面是事件文件所在的目录,绝对路径和相对路径都行但是要正确。然后打开http://localhost:6006/ 这个链接就行了。

tensorboard --logdir=D:\Python\Projects_all\小土堆课程\代码\logs --port=6007

用的人太多的话也可以修改端口的。

注意:对于标题一样的图,tensorboard会保存上一次运行的数据,也就是说图上会有上次的数据和这次的数据,全部乱套了。解决方法:一、更换标题,重新运行,刷新tensorboard图表界面,会生成新的图表; 二、删除logs下面所有的事件文件,然后重新运行,并且重新进入终端输入命令。

writer.add_image( ) 遇到报错或者不知道参数可以点进去看看函数注释

可接受的图像格式:img_tensor (torch.Tensor, numpy.array, or string/blobname): Image data

from PIL import Image
img_path = "D:\Python\Projects_all\小土堆课程\hymenoptera_data\\train\\ants\\0013035.jpg"
img = Image.open(img_path)
print(type(img))
<class 'PIL.JpegImagePlugin.JpegImageFile'>

可见用PIL这个包来读取图片并不满足tensorboard的格式输入要求。

可以利用Opencv读取图片,获得numpy型图片数据。

这里小土堆直接用numpy对图片格式进行了转化。

from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np

writer = SummaryWriter("logs") # 把对应的事件文件存到logs目录里,如果没有会自动创建
img_path = "D:\Python\Projects_all\小土堆课程\hymenoptera_data\\train\\ants\\0013035.jpg"
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
print(img_array.shape)
# print(np.transpose(2, 0, 1))  # [H, W, C] -> [C, H, W]

writer.add_image("test", img_array, global_step= 1, dataformats="HWC")  # 如果想换一张图片显示,要么就是换标题,
                                                            # 要么不换标题改一下global_step,会有一个滑动的效果
# y = 2x
for i in range(100):
    writer.add_scalar("y=x", 4*i, i) #第一个参数是图表标题,第二个参数是y轴数值,第三个
                              #参数是步数,相对于x轴。具体参数可以ctrl+左键 点进去看看
writer.close()

运行,然后在terminal中输入tensorboard --logdir=D:\Python\Projects_all\小土堆课程\代码\logs。打开链接就能看到图片了。

torchvision

torchvision 中的 transforms

from torchvision import transforms

transforms是一个处理图片的工具箱。

ToTensor

基于python脚本语言开发的数字图片处理包,比如PIL,Pillow, opencv, scikit-image等。
PIL和Pillow只提供最基础的数字图像处理,功能有限;opencv实际上是一个c++库,只是提供了python接口,更新速度非常慢。scikit-image是基于scipy的一款图像处理包,它将图片作为numpy数组进行处理,正好与matlab一样。

用PIL和cv2读取的图片都是HWC格式的(0~255),ToTensor会自动转换成CHW格式(0~1)。

class ToTensor:
"""Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor. """
RGB格式的图片,如果三通道值都相等就是灰度图255 255 255是白色,0 0 0是黑色。
用PIL的Image来读取图片 读取出来是RGB格式,HWC格式, 0~255

用np.array( )转成numpy以后dtype是uint8

from PIL import Image
from torchvision import transforms

img_path = "../hymenoptera_data/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img_PIL)
print(tensor_img.shape)
输出:torch.Size([3, 512, 768])

PIL库对于图像操作方法整理

读取图片信息

print(img.format) #打印图片的格式    JPEG
print(img.size)  #打印图片的大小     (619, 539)
print(img.mode)  #打印图片的模式属性  RGB 或者 L

常见的mode 有“L” (luminance) 表示灰度图像,“RGB”表示真彩色图像。

用opencv的CV2的imread来读取图片 读取出来是BGR格式,HWC格式,0-255

opencv读出来的图片是numpy格式,opencv读取时路径中不可以有中文 opencv读取图片的方法

import cv2
from torchvision import transforms
img_path = "../hymenoptera_data/train/ants/0013035.jpg"
img_cv2 = cv2.imread(img_path)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img_cv2)
print(tensor_img.shape)
输出:torch.Size([3, 512, 768])

假设用cv2读取了一张图片img,那它就是一个HWC BGR格式的np数组,现在我想用plt.imshow显示这张图,那首先就要转换成RGB格式,plt.imshow(img[:,:,::-1]),img[:, : ,::-1]的作用是列表数组左右翻转图像领域img[:,:,::-1]的理解

skimage.io.imread & imsave HWC格式 0-255 numpy格式 RGB
  • imread:x.png格式应该是RGBA四通道,但是使用imread读取出来的矩阵仍然是三通道。

  • imsave:保存类型既可以是uint8类型也可以是float类型。一般如果是float类型要求取值在[-1,1],否则会报错。不论保存的时候使用的是uint8类型还是float类型,使用imread读取出来仍然为uint8的矩阵(取值[0,255])。注意,imsave()保存可以是(M, N),(M, N, 3)或者(M, N, 4),也就是灰度图单通道,rgb和rgba都可以。

  • imsave(fname,arr),第一个参数表示保存的路径和名称,第二个参数表示需要保存的数组变量。保存图片的同时也起到了转换格式的作用。如果读取时图片格式为jpg图片,保存为png格式,则将图片从jpg图片转换为png图片并保存。

  • 读取单张rgb图片,使用skimage.io.imread(fname)。

  • 显示图片使用skimage.io.imshow(arr) arr表示需要显示的numpy数组。

  • 读取单张灰度图片,使用skimage.io.imread(fname,as_grey=True),第一个参数为图片路径,第二个参数为as_grey,默认为False。如果设as_grey为True,即一张彩色图片转换为灰度图,它的数据类型就由unit8变成了float,也就是由[0,255]到[0,1]

  • RGB图片访问方式为:img[i, j, c];灰度图片访问方式为:gray[i, j]。

skimage图像处理

用tensorboard来显示tensor格式的图片
from torch.utils.tensorboard import SummaryWriter
import cv2
from torchvision import transforms
img_path = "../hymenoptera_data/train/ants/0013035.jpg"
img_cv2 = cv2.imread(img_path)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img_cv2)

writer = SummaryWriter("logs")
writer.add_image("tensor_image", tensor_img)
writer.close()

然后在python console输入命令打开tensorboard查看。

Normalize输入图片归一化

输入必须是tensor,图片tensor的数据范围是0-1。

公式是output[channel] = (input[channel] - mean[channel]) / std[channel]

trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) #均值和方差,图片的三个通道都要归一化
img_norm_PIL = trans_norm(tensor_img_PIL_RGB) #输入必须是tensor类型,注意格式是RGB
img_norm_cv2 = trans_norm(tensor_img_cv2_RGB)
PyTorch 是一种开源的深度学习框架,由 Facebook 推出,以其动态计算图(Dynamic Computational Graph)的设计和易于使用的 API 而闻名。它非常适合研究实验以及快速原型设计。 **开始学习 PyTorch 的步骤:** 1. **安装**:首先,确保你已经安装了 Python 和 pip,然后可以通过 pip 安装 torch 和 torchvision 库,这是 PyTorch 的核心组件。例如: ```bash pip install torch torchvision ``` 2. **基本概念**: - **张量(Tensor)**:PyTorch 中的核心数据结构,类似于 NumPy 的数组,但支持GPU加速。 - **自动梯度(Autograd)**:PyTorch 自动跟踪计算图,使得反向传播求导变得简单。 - **nn.Module**:定义神经网络的基本模块,包含前向传播的方法 `forward()`。 3. **入门教程**: - 官方文档:https://pytorch.org/docs/stable/getting_started.html 是非常好的起点,有详细的教程、示例和API文档。 - Codecademy 或 Coursera 上的课程,如 "Practical Deep Learning with PyTorch",提供了实践项目。 4. **实践项目**: - 利用 MNIST 数据集训练一个简单的线性分类器或卷积神经网络(CNN)。 - 使用预训练模型如 ResNet 进行图像分类或物体检测。 - 实现 GANs 或变分自编码器等更复杂的深度学习模型。 5. **社区资源**: - GitHub 上的 PyTorch 示例项目(https://github.com/pytorch/examples) - Stack Overflow 和 PyTorch 社区论坛(https://discuss.pytorch.org/)可以帮助解答问题。 6. **深入学习**: - 阅读论文和书籍,如《动手学深度学习》(Deep Learning with PyTorch) 和《PyTorch官方指南》(Learning PyTorch with Examples)。 **相关问题--:** 1. PyTorch和NumPy的主要区别是什么? 2. 如何在PyTorch中创建并操作张量? 3. 哪些情况下你会选择静态计算图框架(如TensorFlow)而不是PyTorch? 4. 如何使用PyTorch进行GPU加速?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值