← 返回知识库Python 与 AI

PyTorch 学习笔记

- PyTorch是一个Python包,提供两个高级功能:

  • PyTorch是一个Python包,提供两个高级功能:
    • 具有强大的GPU加速的张量计算(如NumPy)
    • 包含自动求导系统的的深度神经网络

一、环境的安装

参考文章

这篇文章比较好

安装CUDA Toolkit和cuDNN

==在虚拟环境下安装CUDA Toolkit和cudbb==

下包的时候报PackagesNotFoundError:

1.安装Anaconda

2.显卡GPU的准备(个人未选择安装,安装巨麻烦,而且24年很多博主说不需要安装,在虚拟环境下可以下载cudatoolkit和cudnn包)

CUDA和CUDNN的版本选择

CUDA下载

CUDNN下载

本人NVIDIA显卡驱动cuda driver为12.7

查看命令:nvidia-smi

区分一下显卡CUDA driver驱动版本和运行版本

驱动是电脑显卡的驱动器版本,运行版本是小于等于运行版本的

本人安装的是CUDA11.6(运行版本)对应CUDNN为11.x(8.60)版本

为什么安装CUDA运行版本和CUDNN?

简单点说,安装pytorch,就是安装CUDA的阉割版;安装CUDA就是安装完整版,安装CUDNN就是下载对应深度学习加速库,有对应API

参考文章

但是但是要依赖VScode,就是那个紫色的代码软件

3.管理环境的准备:由于环境版本多,所以要创建几个环境变量

查看环境:conda env list

在Anconda prompt管理器中打开输入

Python
conda create -n pytorch_py39 python=3.9
#-n 后面输入的环境名称
#安排python3.9
conda activate pytorch_py39 #为选择环境名
pip list #为查找当前环境下的包

4.pytorch的安装

事先准备:

切换下载pytorch中的国内源地址

修改下载pytorch中的env和pkgs的安装位置

切换国内镜像源: 修改 .condarc 文件(最强硬)

Windows 中,该文件的位置在:C:\Users(你的用户名).condarc

修改如下

C
show_channel_urls: true
ssl_verify: true
channels:
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
  - defaults
//修改虚拟环境中安装包中的env和pkgs的位置
envs_dirs:
  - D://CodeInstall//Anaconda//envs
pkgs_dirs:
  - D://CodeInstall//Anaconda//pkgs

​ 安装pytorch

https://pytorch.org/index.html

Cmd
#查看显卡版本,无空格
nvidia-smi

原笔记图片缺失:image-20240918170106447

进入pytorch的环境,注意安装的CUDA版本要小于等于自己安装的CUDA版本并且要对应python版本

复制上面的命令行

Cmd
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia

检验安装

Cmd
#cmd进入python环境
python
#导入torch,如果不报错就没问题了
import torch
#查看是否能够使用当前机器的GPU
torch.cuda.is_available()

5.切换虚拟环境

先查看环境下的list

conda env list

在激活对应环境

conda activate 虚拟环境名

查看安装的包

conda list

6.虚拟环境的卸载

conda remove -n 虚拟环境名称 --all

7.虚拟环境相关命令:

查看当前存在哪些虚拟环境:conda env list 或 conda info -e; 查看安装了哪些包: conda list; 退出虚拟环境: conda deactivate; 卸载虚拟环境 :conda remove -n your_env_name(虚拟环境名称) --all; 创建虚拟环境:conda create -n your_env_name(虚拟环境名称); 激活虚拟环境:conda activate your_env_name(虚拟环境名称);

二、编译器的选择

Pycharm或jupyter-notebook

1.Pycharm中创建pytorch项目(换环境)

1.进入设置中,项目中python解释器,添加本地的解释器,换到Conda环境,使用现有的“pytorch”环境

名称pytorch是自己取的,实际要先创建环境,再到环境中安装pytorch

2.检查pytorch环境

Pythons
python
import torch
torch.cuda.is_available(s)#Ture

2.在jupyter中安装pytorch

本人电脑python版本为3.11,出现与pytorch版本冲突,

问题来源1:

​ 在Anaconda环境下使用pytorch环境,然后使用了这个命令

Cmd
conda install nb_canda

​ 下个pthon版本不冲突的,再进行安装即可

原笔记图片缺失:image-20240920204017844

解决方法:

https://blog.csdn.net/leoound/article/details/137928032

==jupyter相关配置==

jupyter notebook

在jupyter中查看输入参数shift+tab+tab

三、基础语句

dir()函数,能让我们知道 工具箱以及工具箱中的分隔区有什么东西。

help()函数,能让我们知道每个工具是如何使用的,工具的使用方法。

四、基本数据类型Tensor

参考文章:

https://blog.csdn.net/CltCj/article/details/120060543

4.1Tensor

torch.Tensor

Tensor张量是Pytorch里最基本的数据结构。直观上来讲,它是一个多维矩阵,支持GPU加速,其基本数据类型如下,分两种数据类型:一种是用CPU加速的,另一种是GPU加速的。

torch.xxxTensor(列表或维度值)

列表就是行列式

维度就是(行数,列数)

数据类型 CPU tensor GPU tensor
8位无符号整型 torch.ByteTensor torch.cuda.ByteTensor
8位有符号整型 torch.CharTensor torch.cuda.CharTensor
16位有符号整型 torch.ShortTensor torch.cuda.ShortTensor
32位有符号整型 torch.IntTensor torch.cuda.IntTensor
64位有符号整型 torch.LongTensor torch.cuda.LonfTensor
32位浮点型 torch.FloatTensor torch.cuda.FloatTensor
64位浮点型 torch.DoubleTensor torch.cuda.DoubleTensor
布尔类型 torch.BoolTensor torch.cuda.BoolTensor

指定数据类型:dtype=数据类型

函数名称 函数解释
torch.FloatTensor 生成为浮点型的Tensor,传递给torch.FloatTensor的参数是列表或维度值。
torch.IntTensor 生成为整型的Tensor,传递给传递给torch.IntTensor的参数是列表或维度值
torh.xxxTensor 基本方法一样
torch.randn() 生成浮点数且维度指定的随机Tensor,和在numpy中使用的numpy.randn生成的随机数的方法类似,随机生成的浮点数的取值满足均值为0,方差为1的正态分布
torch.rand(*sizes, out=None) → [Tensor] 返回一个张量,包含了从区间[0, 1)的均匀分布中抽取的一组随机数。张量的形状由参数sizes定义。
torch.range() 生成浮点型且起始范围和结束范围的Tensor,所以传递给torch.range的参数有三个,分别为起始值,结束值,步长,其中步长用于指定从起始值到结束值得每步的数据间隔。[step,end),左闭右开
torch.arange() 生成浮点型且起始范围和结束范围的Tensor,所以传递给torch.range的参数有三个,分别为起始值,结束值,步长,其中步长用于指定从起始值到结束值得每步的数据间隔。[step,end],左闭右闭
torch.zeros() 生成浮点型且维度指定的Tensor,不过这个浮点型的Tensor中的元素值全部为0。
torch.ones 生成全1的数组。
torch.empty 创建一个未被初始化数值的tensor,tensor的大小是由size确定,size: 定义tensor的shape ,这里可以是一个list 也可以是一个tuple
x = torch.tensor([5,5],[2,3]) 使用list序列直接创建

4.2 Tensor的运算

函数名称 函数解释
torch.abs 将参数传递到torch.abs后返回输入参数的绝对值作为输出,输入参数必须是一个Tensor数据类型的变量。
torch.add(input, other, *, alpha=1, out=None) -> Tensor 将参数传递到torch.add后返回输入参数的求和结果作为输出,输入参数:既可以全部是Tensor数据类型的变量,也可以一个是Tensor数据类型的变量,另一个是标量。
torch.clamp(input, min=None, max=None, *, out=None) -> Tensor 对输入参数按照自定义的范围进行裁剪,最后将参数裁剪的结果作为输出,所以输入参数一共有三个,(变量名,上界,下界);其中上下界的含义就是输入的数据在范围内就不变,在范围外就变成上下界的大小。
torch.div(input, other, *, rounding_mode=None, out=None) -> Tensor 将参数传递到torch.div后返回输入参数的求商结果作为输出,同样,参与运算的参数可以全部是Tensor数据类型的变量,也可以是Tensor数据类型的变量和标量的组合
torch.pow(input, exponent, *, out=None) -> Tensor 将参数传递到torch.pow后返回输入参数的求幂结果作为输出,参与运算的参数可以全部是Tensor数据类型的变量,也可以是Tensor数据类型的变量和标量的组合。
torch.mm 将参数传递到torch.mm后返回输入参数的矩阵求积结果作为输出,不过这个求积的方式和之前的torch.mul运算方式不太一样,torch.mm运用矩阵之间的乘法规则进行计算,所以被传入的参数会被当作矩阵进行处理,参数的维度自然也要满足矩阵乘法的前提条件,即前一个矩阵的行数必须和后一个矩阵列数相等
torch.mv 将参数传递到torch.mv后返回输入参数的求积结果作为输出,torch.mv运用矩阵与向量之间的乘法规则进行计算,被传入的第1个参数代表矩阵,第2个参数代表向量,循序不能颠倒。
torch.as_tensor(data, dtype=None, device=None)->Tensor 传入参数(list、tuple、ndarray等)转换为tensor
torch.from_numpy(ndarray) → Tensor 传入ndarray数据转换为tensor
torch.mean(tensor) 求平均值。median平均数,sqrt开方

一、运算符中最后加_和不加的区别:

​ 例如:torch.add()和torch.add_()

​ 所有的带<font color='red'>_</font>符号的函数都会对原数据进行修改,即x.add_(y),相对于x+y 的结果会存储到原来的x中(即x = x+y)

二、torch.stack()函数

​ stack为拼接函数,函数的第一个参数为需要拼接的Tensor参数,第二个参数为细分到哪个维度

Python
import torch
A=torch.IntTensor([[1,2,3],[4,5,6]])
B=torch.IntTensor([[7,8,9],[10,11,12]])
C1=torch.stack((A,B),dim=0) # or C1=torch.stack((A,B))
C2=torch.stack((A,B),dim=1)
C3=torch.stack((A,B),dim=2)
C4=torch.stack((A,B),dim=-1)
print(C1,C2,C3,C4)
'''
dim=0,C1 = [ A,B ]
dim=1,C2 = [ [ A[0],B[0] ] , [ A[1],B[1] ] ]
dim=2,C3 = [ [ [ A[0][0],B[0][0] ] , [ A[0][1],B[0][1] ] , [ A[0][2],B[0][2] ] ],
      [ [ A[1][0],B[1][0] ] , [ A[1][1],B[1][1] ] , [ A[1][2],B[1][2] ] ] ]

dim=-1,C4 = C3
'''

dim的不同值表示不同维度。特别的在dim=0表示二维中的行,dim=1在二维矩阵中表示列。广泛的来说,我们不管一个矩阵是几维的,比如一个矩阵维度如下:(do,d.,…, dn-1),那么dim=0就表示对应到dg也就是第一个维度,dim=1表示对应到di也就是第二个维度,依次类推。

即:A,B矩阵中使用的是三维矩阵,其中: C1中,dim=0,即高度进行拼接

​ C2中,dim=1,即行进行拼接

​ C3中,dim=2,即列进行拼接

​ C4中,dim=-1,即列进行拼接,为什么-1代表列呢?可以理解为逆向的表示

​ (-2,-1,0,1,2),其中dim=-2=1,行;dim=-1=2,代表列。

那么在torch.stack()中对tensor拼接使用dim函数代表什么呢?

​ 在二维矩阵下:

  • dim = 0,列不变(按列-将当前列所有行数据-计算),指定的是行,那就是行变,理解成:针对每一列中,所有行之间的数据比较或者求和等操作,是每一行的比较,因为行是可变的。
  • dim = 1,行不变(按行-将当前行所有列数据-计算),指定的是列,那就是列变,理解成:针对每一行中,所有列之间的数据比较或者求和等操作,是每一行的比较,因为行是可变的。

参考文章1

三、tensor数据的切分

和numpy是一样的

4.3 一些参数的对比

4.3.1 torch.tensor()&&torch.tensor([])

区别:就是圆括号里面是否有[],有[]是列表

Python
import torch 
print(torch.Tensor(2,3))
'''
tensor([[0., 0., 0.],
        [0., 0., 0.]])
'''
print(torch.Tensor([2,3]))
'''
tensor([2., 3.])
'''

4.3.2 torch.randn && torch.randperm&&torch.rand()

区别:

​ torch.randn是生成的数据类型为浮点型,与numpy.randn生成随机数的方法类似,生成的浮点数的取值满足均值为0,方差为1的正态分布

​ torch.randperm(n)是创建一个n个整数,随机排列的Tensor

torch.rand(size)是创建一个n个整数,随机均匀分布的Tensor

Python
import torch 
print(torch.rand(2,3))
'''
tensor([[0.4199, 0.7724, 0.7531],
        [0.3629, 0.2401, 0.5478]])
'''
print(torch.randperm(10))
'''
tensor([7, 4, 5, 1, 6, 0, 2, 9, 8, 3])
'''

4.3.3 torch.range(begin,end,step)

torch.range(begin,end,step)生成一个一维的Tensor,三个参数分别的起始位置,终止位置和步长

Python
import torch 
print(torch.range(1,41,2))
'''
tensor([ 2.,  4.,  6.,  8., 10., 12., 14., 16., 18., 20., 22., 24., 26., 28.,
        30., 32., 34., 36., 38., 40.])
'''

如今版本已经不在使用torch.range(),改用torch.arange(),在[begin,end]

4.3.4 利用numpy 创建指定Tensor

很多时候我们需要创建指定的Tensor,而numpy就是一个很好的方式

Python
import torch
import numpy as np
print(torch.tensor(np.arange(15).reshape(3,4)))
'''
tensor([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14]])
'''

4.3.5 torch.tensor() 、torch.Tensor()、torch.as_tensor()、transforms.ToTensor()

torch.tensor()

是一个通过深拷贝数据,构造一个新张量的函数:

torch.tensor(data, *, dtype=None, device=None, requires_grad=False, pin_memory=False) →Tensor

​ 即data为 list, tuple, NumPy ndarray, scalar, and other types,就没waring。

​ 如果data为tensor,会报警告;建议使用clone().detach()等函数

Python
import torch 
import numpy as np
#使用非tensor类型,不会waring
a = np.array([1,3,4])
t0 = torch.tensor(a)

b = [1,34,5]
t1 = torch.tensor(b)

c = (1,223,423)
t2 = torch.tensor(c)
#使用tensor会导致Userwarning
d = torch.tensor([1,2,3],[1,2,3])
t3 = torch.tensor(d)

print(t0.dtype, t1.dtype, t2.dtype,t3.dtype)
'''
 UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor). t3 = torch.tensor(d)
 
torch.int64 torch.int64 torch.int64 torch.int64
'''

**torch.Tensor() **

是默认张量类型 (torch.FloatTensor()) 的别名。也就是说,torch.Tensor() 的作用实际上跟 torch.FloatTensor() 一样,都是生成一个数据类型为 32 位浮点数的张量,如果没传入数据就返回空张量,如果有列表或者 narray 的返回其对应张量。但无论传入数据本身的数据类型是什么,返回的都是 32 位浮点数的张量。

Python
>>> torch.Tensor()
tensor([])
>>> torch.Tensor().dtype
torch.float32
>>> torch.FloatTensor()
tensor([])
>>> torch.FloatTensor().dtype
torch.float32

torch.as_tensor

(data, dtype=None,device=None)->Tensor : 为data生成tensor,保留 autograd 历史记录并尽量避免复制(dtype和devices相同,尽量浅拷贝)。

如果data已经是tensor,且dtype和device与参数相同,则生成的tensor会和data共享内存(浅拷贝)。如果data是ndarray,且dtype对应,devices为cpu,则同样共享内存。其他情况则不共享内存。

Python
#1)数据类型和device相同,浅拷贝,共享内存
import numpy
a = numpy.array([1, 2, 3])
t = torch.as_tensor(a)
t[0] = -1
a,t
 
#Out[77]: (array([-1,  2,  3]), tensor([-1,  2,  3], dtype=torch.int32))
 
#2)数据类型相同,但是device不同,深拷贝,不再共享内存
import numpy
a = numpy.array([1, 2, 3])
t = torch.as_tensor(a, device=torch.device('cuda'))
t[0] = -1
a,t
 
#Out[78]: (array([1, 2, 3]), tensor([-1,  2,  3], device='cuda:0', dtype=torch.int32))
 
#3)device相同,但数据类型不同,深拷贝,不再共享内存
import numpy
a = numpy.array([1, 2, 3])
t = torch.as_tensor(a, dtype=torch.float32)
t[0] = -1
a,t
 
Out[80]: (array([1, 2, 3]), tensor([-1.,  2.,  3.]))

transforms.ToTensor()

ToTensor()将shape为(H, W, C)的nump.ndarray或img转为shape为(C, H, W)的tensor,其将每一个数值归一化到[0,1],其归一化方法比较简单。

Python
# 归一化到(0,1)之后,再数据标准化处理 (x-mean)/std,归一化到(-1,1),数据中存在大于mean和小于mean
transform2 = transforms.Compose([
    transforms.ToTensor(), 
    transforms.Normalize(std=(0.5,0.5,0.5),
                         mean=(0.5,0.5,0.5))])

4.3.6 torch.as_strided

torch.as_strided(input, size, stride, storage_offset=0) → Tensor

创建具有指定size,stride和storage_offset的现有torches,input的视图

参数分析:

  • input (Tensor) – the input tensor.
  • 大小(元组 或 python:ints )–输出张量的形状
  • 跨度(元组 或 python:ints )–输出张量的跨度,
  • storage_offset (python:int , 可选)–输出张量的基础存储中的偏移量
Python
import torch 
>>> x = torch.randn(3, 3)
>>> x
tensor([[ 0.9039,  0.6291,  1.0795],
        [ 0.1586,  2.1939, -0.4900],
        [-0.1909, -0.7503,  1.9355]])
>>> t = torch.as_strided(x, (2, 2), (1, 2))
>>> t
tensor([[0.9039, 1.0795],
        [0.6291, 0.1586]])
>>> t = torch.as_strided(x, (2, 2), (1, 2), 1)
tensor([[0.6291, 0.1586],
        [1.0795, 2.1939]])

4.3.7 torch.xxx和torch.xxx_like的区别

总结来说,torch.xxx 需要你明确指定新张量的形状,而 torch.xxx_like 则是根据一个已有张量的形状来创建新张量。

  1. torch.ones:
    • torch.ones 函数用于创建一个指定大小的张量,并将所有元素初始化为1。
    • 它的用法是 torch.ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)。
    • 你可以指定张量的形状(size),数据类型(dtype),内存布局(layout),设备(device)等参数。
    • 例如,torch.ones(2, 3) 会创建一个2行3列的张量,所有元素都是1。
  2. torch.ones_like:
    • torch.ones_like 函数用于创建一个与给定张量形状相同、所有元素为1的新张量。
    • 它的用法是 torch.ones_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format)。
    • 你只需要提供一个已有的张量(input),函数会根据这个张量的形状创建一个新的张量,并且所有元素都是1。
    • 例如,如果有一个张量 x = torch.empty(2, 3),那么 torch.ones_like(x) 会创建一个同样形状的张量,所有元素都是1。

4.4 一些常见属性的解释

在函数里面有许多变量参数如size、data、dtype、layout、device、requires_grad等,使用的时候总是迷糊

  • size:大小 (python:int ... )–定义输出张量形状的整数序列。 可以是可变数量的参数,也可以是列表或元组之类的集合。

  • data:数据 (array_like )–张量的初始数据。 可以是列表,元组,NumPy ndarray,标量和其他类型。

如torch.tensor(data,...)

​ torch.IntTensor(size,...)

这两个函数输入的参数不同,tensor只接收初始数据,即值确定了的,无法定义张量初始尺寸。而xxxTensor可以直接定义张量尺寸

  • dtype (torch.dtype ,可选)–返回张量的所需数据类型。 默认值:如果None,则从data推断数据类型。

  • 设备 (device ,可选)–返回张量的所需设备。 默认值:如果None,则使用当前设备作为默认张量类型

这个参数默认为none,选择当前设备的Cpu或Gpu进行计算。反之可以选择cup和gpu来计算

对应torch.device函数

import torch

#创建一个CPU设备

device_cpu = torch.device("cpu")

#创建一个GPU设备,如果有多个GPU,可以指定编号

device_gpu = torch.device("cuda:0") # 编号0的GPU

  • require_grad (bool , 可选)–如果 autograd 应该在返回的张量上记录操作。 默认值:False。

在 PyTorch 中,require_grad 是一个张量(Tensor)的属性,用来指示该张量是否需要梯度。当一个张量设置了 requires_grad=True 时,PyTorch 会自动跟踪对这个张量的所有操作,并计算梯度。这对于训练神经网络时进行反向传播是必要的。

以下是一些关于 requires_grad 的关键点:

  1. 默认值:当你创建一个新的张量时,requires_grad 默认是 False。

  2. 设置 requires_grad:

    Python
    import torch
             
    # 创建一个张量,并设置requires_grad=True
    tensor = torch.randn(2, 2, requires_grad=True)
  3. 查看 requires_grad 状态:

    Python
    print(tensor.requires_grad)  # 输出: True
  4. 自动梯度计算:当你对设置了 requires_grad=True 的张量进行操作时,PyTorch 会记录这些操作,以便在反向传播时计算梯度。

  5. 停止梯度计算:如果你不想对某个操作的输出计算梯度,可以使用 .detach() 方法,这会创建一个新的张量,与原始张量共享数据,但是不会跟踪梯度。

    Python
    detached_tensor = tensor.detach()
    print(detached_tensor.requires_grad)  # 输出: False
  6. 梯度清零:在每次反向传播之前,需要将梯度清零,否则梯度会累积。可以使用 .zero_grad() 方法。

    Python
    tensor.grad = None  # 清空梯度
  7. 梯度裁剪:为了防止梯度爆炸,可以使用 torch.nn.utils.clip_grad_norm_ 或 torch.nn.utils.clip_grad_value_ 来裁剪梯度。

  8. 反向传播:在训练过程中,你需要调用 .backward() 方法来计算梯度。

    Python
    loss = criterion(output, target)
    loss.backward()  # 计算梯度

requires_grad 是 PyTorch 中实现自动微分的核心属性之一,对于深度学习模型的训练至关重要。通过正确设置和管理 requires_grad,你可以有效地控制梯度的计算和反向传播过程。

  • 布局 (torch.layout ,可选)–返回的 Tensor 所需的布局。 默认值:torch.strided。

在 PyTorch 中,layout 是一个与张量(Tensor)相关的概念,它定义了张量数据在内存中的存储方式。不同的 layout 会影响张量的操作和性能,尤其是在不同的设备(如 CPU 和 GPU)上。PyTorch 支持多种 layout,但最常用的是以下几种:

  1. Strided Layout(默认):

    • 这是 PyTorch 的默认布局,也是大多数操作所期望的布局。
    • 在这种布局中,数据是连续存储的,每个维度的步长(stride)是固定的。
    • 对于多维张量,后一个维度的步长是该维度大小乘以前一个维度的步长。
  2. Sparse Layout:

    • 稀疏布局用于存储大部分元素为零的张量,以节省内存。
    • PyTorch 通过 torch.sparse 和 torch.sparse_coo_tensor 等函数支持稀疏张量。
  3. MKLDNN Layout:

    • 这是一种针对英特尔 CPU 优化的布局,可以提高某些操作的性能。
    • 通常用于与 MKL-DNN 库集成,以加速深度学习模型。
  4. Channels Last Layout:

    • 在图像处理中,这种布局将通道维度放在最后,例如,对于一个形状为 (N, C, H, W) 的张量,C 是通道数,H 和 W 分别是高度和宽度。
    • 这种布局在某些情况下可以提高性能,尤其是在使用 CUDA 时。
  5. Channels First Layout:

    • 与 Channels Last 相反,这种布局将通道维度放在第一个维度,例如 (N, C, H, W)。
    • 这种布局在某些框架和操作中更常见。
  6. Packed Layout:

    • 这是一种特殊的布局,用于存储打包的序列数据,例如在 RNN 操作中。

在 PyTorch 中,你可以通过 torch.Tensor.layout 属性查看张量的布局,但这个属性是只读的。如果你需要改变张量的布局,可以使用 torch.Tensor.contiguous() 方法将张量转换为连续的 Strided Layout,或者使用 torch.Tensor.view() 方法在不改变数据的情况下重新排列张量的形状。

请注意,改变张量的布局可能会影响性能,因此在设计深度学习模型时,了解和选择合适的布局是很重要的。

4.5 索引,切片,联接,操作变更

torch.cat(tensors, dim=0, out=None) → Tensor

用于将多个张量(tensors)沿着指定的维度连接起来

Python
import torch

# 创建两个形状为2x3的张量
tensor1 = torch.randn(2, 3)
tensor2 = torch.randn(2, 3)

# 沿着第一个维度(dim=0)连接它们,结果形状为4x3
result = torch.cat((tensor1, tensor2), dim=0)

多维连接

torch.cat 也可以用于多维张量的连接,只要除了连接的维度外,其他维度的形状必须相同。

Python
# 创建两个形状为2x3x4的张量
tensor3 = torch.randn(2, 3, 4)
tensor4 = torch.randn(2, 3, 4)

# 沿着第二个维度(dim=1)连接它们,结果形状为2x6x4
result = torch.cat((tensor3, tensor4), dim=1)

注意事项:

  • 所有输入张量的数据类型必须相同。
  • 如果输入张量中有任何张量需要梯度,那么输出张量也会需要梯度。
  • torch.cat 返回的张量是连续的(contiguous),这意味着它在内存中是连续存储的。

与 torch.stack 的区别:

  • torch.cat 是在指定维度上进行连接,而 torch.stack 是在新的维度上堆叠张量,这会增加结果张量的维度

torch.chunk(input, chunks, dim=0) → List of Tensors

用于将一个张量(tensor)分割成指定数量的块(chunks)

  1. 参数:
    • input:要分割的张量。
    • chunks:一个整数,表示要将张量分割成多少块。
    • dim:指定沿着哪个维度进行分割,默认为0。
  2. 使用示例:
Python
import torch

# 创建一个形状为6的一维张量
tensor = torch.arange(6)

# 沿着维度0(默认维度)将张量分割成3块,每块包含2个元素
chunks = torch.chunk(tensor, chunks=3, dim=0)
for i, chunk in enumerate(chunks):
    print(f"Chunk {i}: {chunk}")

3.多维张量分割: torch.chunk 也可以用于多维张量的分割,只要指定的维度可以被块的数量整除。

Python
# 创建一个形状为2x6的二维张量
tensor2d = torch.arange(12).reshape(2, 6)

# 沿着维度1将张量分割成3块,每块包含2列
chunks = torch.chunk(tensor2d, chunks=3, dim=1)
for i, chunk in enumerate(chunks):
    print(f"Chunk {i}: {chunk}")

4.注意事项:

  • 张量在指定维度的大小必须能够被 chunks 参数整除,否则会抛出错误。
  • 返回的块是原始张量的视图,如果原始张量是可变的,那么对块的修改也会影响原始张量。
  • 如果你只需要分割张量的一小部分,可以使用列表推导式或循环来选择特定的块。

5.返回值: torch.chunk 返回一个元组,其中包含了分割后的张量块。每个块都是原始张量的子集。

五、TensorBoard可视化的使用

5.1TensorBoard的安装

在自己的pytorch环境下安装

Python
pip install tensorboard

Successfully installed absl-py-2.1.0 grpcio-1.66.1 markdown-3.7 protobuf-5.28.2 tensorboard-2.17.1 tensorboard-data-server-0.7.2 werkzeug-3.0.4

TensorBoard 是一组用于数据可视化的工具。它包含在流行的开源机器学习库 Tensorflow 中。TensorBoard 的主要功能包括:

  • 可视化模型的网络架构
  • 跟踪模型指标,如损失和准确性等
  • 检查机器学习工作流程中权重、偏差和其他组件的直方图
  • 显示非表格数据,包括图像、文本和音频
  • 将高维嵌入投影到低维空间

TensorBoard算是包含在 TensorFlow中的一个子服务。TensorFlow 库是一个专门为机器学习应用程序设计的开源库。Google Brain 于 2011 年构建了较早的 DistBelief 系统。随着其用户群的快速增长,它被简化并重构为我们现在称为 Tensorflow 的库。TensorFlow 随后于 2015 年向公众发布。TensorBoard刚出现时只能用于检查TensorFlow的指标和TensorFlow模型的可视化,但是后来经过多方的努力其他深度学习框架也可以使用TensorBoard的功能,例如Pytorch已经抛弃了自家的visdom(听到过这个名字的人应该都不多了吧)而全面支持TensorBoard。

5.2 opencv的安装

在自己的pytorch环境下安装

Python
pip install opencv-python

Successfully installed opencv-python-4.10.0.84

5.3基本使用

SummaryWriter:

这个用来创建一个log文件,TensorBoard面板查看时,也是需要选择查看那个log文件。

args 解释
log_dir (str) 日志保存地址,默认保存在runs/‘当前时间_主机名’;建议用'runs/exp1', 'runs/exp2', etc.来保存
comment (str) 注释;默认跟在log_dir参数后面,不选;只在log_dir报错时,提供信息
max_queue (int) 等待事件队列的大小其中一个“add”调用强制刷新磁盘之前的摘要。<br/>默认是10项。
flush_secs (int) 以秒为单位多久刷新,挂起事件和摘要到磁盘。默认是每两分钟一次。
filename_suffix (str) 所有事件文件名添加后缀log_dir目录。. 有关文件名构造的更多细节,请参见tensorboard.summary.writer.event_file_writer.EventFileWriter。
Python
#例子:
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("run/exp1")
# 会创建文件名称:run/exp1

add_something:

向log文件里面增添数据。例如可以通过add_scalar增添折线图数据,add_image可以增添图片。

add_something指的是添加__xxx

Python
#1.
def add_scalar(
    self,
    tag,
    scalar_value,
    global_step=None,
    walltime=None,(可选)
    new_style=False,(可选)
    double_precision=False,(可选)
):
    Args:
        tag (str): 图像名称
        scalar_value (float or string/blobname): y轴
        global_step (int):x轴
        walltime (float):可选覆盖默认的walltime (time.time()),事件发生后的几秒钟
        new_style (boolean): 是使用新样式(张量字段)还是旧样式
        style (simple_value field). 是使用新样式(张量字段)还是旧样式
    Examples::
		#创建100个数。循环遍历,图像名称为y=2x,x轴位2*i,y轴位i
        from torch.utils.tensorboard import SummaryWriter
        writer = SummaryWriter()
        x = range(100)
        for i in x:
            writer.add_scalar('y=2x', i * 2, i)
        writer.close()
		
    Expected result:
		#结果:
    .. image:: _static/img/tensorboard/add_scalar.png
       :scale: 50 %

    """
Python
#2.
def add_image(
    # 注意默认图片的格式为CHW,而输入图片格式
    self, tag, img_tensor, global_step=None, walltime=None, dataformats="CHW"
):
	#注意,这需要``pillow``包。
    Args:
        tag (str): 图像名称
        img_tensor (torch.Tensor, numpy.ndarray, or string/blobname): 图片数据类型
        global_step (int): 结果步长,也是y轴
        walltime (float): 
        dataformats (str): 图片格式的排布形状,C代表维度,H代表高度,W代表宽度。有 CHW, HWC, HW, WH, etc.
   

    Examples::

        from torch.utils.tensorboard import SummaryWriter
        import numpy as np
        img = np.zeros((3, 100, 100))
        img[0] = np.arange(0, 10000).reshape(100, 100) / 10000
        img[1] = 1 - np.arange(0, 10000).reshape(100, 100) / 10000

        img_HWC = np.zeros((100, 100, 3))
        img_HWC[:, :, 0] = np.arange(0, 10000).reshape(100, 100) / 10000
        img_HWC[:, :, 1] = 1 - np.arange(0, 10000).reshape(100, 100) / 10000

        writer = SummaryWriter()
        writer.add_image('my_image', img, 0)

        # If you have non-default dimension setting, set the dataformats argument.
        writer.add_image('my_image_HWC', img_HWC, 0, dataformats='HWC')
        writer.close()

    Expected result:

    .. image:: _static/img/tensorboard/add_image.png
       :scale: 50 %

    """

close

​ 当训练结束后,我们可以通过close方法结束log写入。

在train结束之后要记得write.close()

标准使用例子:

Python
#1.
#导入tensorboard 中SummaryWrite包
from torch.utils.tensorboard import SummaryWriter
#等价于 import torch.utils.tensorboard.SummaryWriter

#2.创建SummaryWrite实体,设置日志文件夹为run/exp1
writer = SummaryWriter("runs/exp1")

#3.导入数据例子
for i in range(100):
	writer.add_scalar("y=2x",2*i,i)
#关闭文件流
writer.close()

PS:程序运行完成后,不会自动跳入tensorboard运行网站,需要输入命令

在对应文件终端输入:tensorboard --logdir=runs/exp1

默认端口为6006

修改端口:tensorboard --logdir=runs/exp1 --port=xxx

Python
#2.
#导入tensorboard 中SummaryWrite包
from torch.utils.tensorboard import SummaryWriter

#由于add_image函数中图片格式只能为tensor,array类型etc.所以要转换类型
import numpy as np
from PIL import Image

#创建SummaryWrite实体,日志文件夹为run/exp1
writer = SummaryWriter("runs/exp1")
#导入图片路径(一般复制根路径),并转换图片格式为array类型
image_path = "data/train/ants/0013035.jpg"
img_PIL = Image.open(image_path)
img_array = np.array(img_PIL)

# Create a SummaryWriter instance
writer = SummaryWriter("runs/exp1")

# 注意add_image参数中默认图片shape格式为(维度C,高度H,宽度W)
writer.add_image("Ant Image", img_array, 1 , dataformats="HWC")

writer.close()

5.4 补充知识

5.4.1 安装opencv

注意:在自己的pytorch环境安装

Python
pip install opencv-python

5.4.1 Python的_call_ 方法

在 Python 中,_call_ 是一个特殊方法(也称为魔术方法或双下划线方法),用于使对象可以像函数一样被调用。当你在一个对象上调用 obj() 时,Python 解释器会查找该对象的_call_ 方法并调用它.

其实就是不需要用”.函数名“这样的方式去调用的,可以直接使用”对象名(参数)“这样的方法去调用

而非双划线的方法,是需要对象名.函数名(参数)的形式调用的

六、transforms的使用

前言:

首先要知道transforms这个类是干什么的?

​ transforms是torchvision中一个模块,这个模块定义了很多图像处理的类,比如:

TEXT
 数据中心化
    数据标准化
    缩放
 裁剪
    旋转
    翻转
    填充
  噪声添加
    灰度变换
   线性变换
   仿射变换
   亮度、饱和度以及对比度变换等。

变换是常见的图像变换,其可以适应连接在一起的Compose, 此外,还有torchvision.transforms.functionaltorchvision.transforms.functional模块,功能转换可以对转换进行细粒度控制,如果您必须构建更复杂的转换管道(例如,在分段任务情况下),这将非常有用类。

Python
torchvision.transforms.Compose(transforms)
  • transforms: (Transformes对象列表)要组成的变换列表。
Python
transforms.Compose([
     transforms.CenterCrop(10),
     transforms.ToTensor(), ])

其次:是如何使用transforms这个模块

Python
#导入的包名
from torchvision import transforms

1.实例化transforms

Python
tool = transforms.tool()#tool指的是模块中具体的方法类

2.转换方法;在创建好具体的方法类之后,就要把预处理的数据进行转换

Python
result = tool(InputData)

常见的图像变换

官方文档只将该方法陈列,没有归纳总结,顺序很乱,这里总结一共有四大类,方便大家索引。

  • 裁剪(Crop):—中心裁剪:
    • transforms.CenterCrop:中心裁剪
    • transforms.RandomCrop:随机裁剪
    • transforms.RandomResizedCrop:随机长宽比裁剪
    • transforms.FiveCrop:上下左右中心裁剪
    • transforms.TenCrop:上下左右中心裁剪后翻转
  • 翻转和旋转——
    • transforms.RandomHorizontalFlip(p=0.5):依概率p pp水平翻转
    • transforms.RandomVerticalFlip(p=0.5):依概率p垂直翻转
    • transforms.RandomRotation:随机旋转。
  • 图像变换(resize)
    • transforms.Resize : 图像变换(resize)
    • transforms.Normalize:标准化
    • transforms.ToTensor: 转为tensor,并归一化为[0-1]
    • transforms.Pad :。填充
    • transforms.ColorJitter:修改亮度、对比度和饱和度
    • transforms.Grayscale:转灰度图
    • transforms.LinearTransformation():线性变换
    • transforms.RandomAffine:放射变换
    • transforms.RandomGrayscale:依概率p pp转为灰度图
    • transforms.ToPILImage:将数据转换为PILImage
    • transforms.Lambda:Apply a user-defined lambda as a transform
  • 对transforms操作,使数据增强更灵活,transforms.RandomChoice(transforms),从给定一系列的transform中选一个进行操作,transforms.RandomApply(transforms, p=0.5), 给一个transform加上概率,依概率进行操作:transforms.RandomOrder。将transform中的操作进行随机打乱。

6.1 图像变换(resize)

6.1.1 ToTensor

将PIL图像或NumPy ndarray 转换为PyTorch张量,‌并将像素值从[0, 255]缩放到[0.0, 1.0]。‌并且归一化至[ 0 − 1 ] , 注意事项:归一化至[0-1]是直接除以255,若自己的ndarray数据尺度有变化,则需要自行修改。

只支持输入以下两类的数据:

  • PIL类型的图像数据
  • numpy.ndarray类型的图像数据

而且会将shape由HWC转换成CHW

Python
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

#数据的导入
img_path="data/train/ants/0013035.jpg"
img = Image.open(img_path)
#tensorboard文件日志的写入
writer = SummaryWriter('runs/exp1')

print(type(img))
#totensor的使用,先创建实例
tersor = transforms.ToTensor()
#再进行转换
tensor_image =tersor(img)
print(type(tensor_image))

#tensorboard写入
writer.add_image("Ant Image", tensor_image, 1 , dataformats="CHW")

print(tensor_image.shape)
writer.close()

6.1.2 ToPILImage()

ToPILImage()作用: 将PyTorch张量转换回PIL图像

Python
#ToPILImage的使用:首先还是先创建实例
Tensor_to_PIL = transforms.ToPILImage()
#在把数据导入进行转换
img_PIL = Tensor_to_PIL(tensor_image)
print(img_PIL)
img_PIL.show()

总结:

​ 1.PIL、narrays格式的数据通过ToTensor()来转换成张量(理解成特殊矩阵)

​ 2.利用ToPILImage()函数把张量转换成PIL图像

​ 3.PIL数据通过Image库中的open()函数来打开,即Image.open()

​ 4.tensor数据,即张量,通过Tosensor()来打开

​ 5.narrays数据,通过cv.imread()函数打开,需要import cv库函数

6.1.3 Normalize()

transforms.Normalize()函数接受两个参数:mean和std,分别表示数据集的均值和标准差。函数会对输入数据进行以下操作:

​ $normalized_image=\frac{image-mean}{std}$ (1)

 如公式1所示,通过减去均值并除以标准差,我们可以将图像数据的分布转换为标准正态分布(均值为0,标准差为1)。这样,模型在训练过程中就可以更容易地学习到数据的特征。

Python
import cv2
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms


writer = SummaryWriter("runs/exp1")

img = cv2.imread("data/train/ants/0013035.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # cv2读入图像为BGR,转换成RGB

# transforms使用
trans_tensor = transforms.ToTensor()  # ToTensor类,实例化一个ToTensor工具
tensor_img = trans_tensor(img)

trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])  # 归一化
norm_img = trans_norm(tensor_img)

writer.add_image("ants_img", norm_img, 2)

writer.close()

这里的mean和std参数是根据ImageNet数据集的统计信息设置的。

6.1.4 Resize()

transforms.Resize():将输入图像的大小调整为给定的大小(高宽),参数值可以是序列 如(512, 512)或 int(512),图像可以是PIL图像或torch张量,shape格式为[…, H, W]

Python
import cv2
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms


writer = SummaryWriter("logs")

img = cv2.imread("./data/train/ants/0013035.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # cv2读入图像为BGR,转换成RGB

# transforms使用
trans_tensor = transforms.ToTensor()  # ToTensor类,实例化一个ToTensor工具
tensor_img = trans_tensor(img)

trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])  # 归一化
norm_img = trans_norm(tensor_img)

print(norm_img.shape)
trans_resize = transforms.Resize((512, 512))  # 改变尺寸为(512, 512)
resize_img = trans_resize(norm_img)
print(resize_img.shape)

writer.add_image("ants_img", resize_img, 3)

writer.close()

6.1.5 Compose

Compose就是把多个变换对象组合在一起

参数:一个list数组,数组里是多个’Transform’对象,即[transforms, transforms…]。 所在环境路径:/opt/conda/lib/python3.6/site-packages/torchvision/transforms/transforms.py 操作:如下所示,遍历list数组,对img依次执行每个transforms操作,并返回transforms后的img。

Python
#创建一个Compose对象,里面的包含许多transforms对象操作,最后会返回一个结果
transform1 = transforms.Compose(#注意用list数组把操作框起来
    [
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

Compose中调用的transform函数先后顺序,一定要跟数据类型一一对应

6.1.6 RandomCrop()

随即裁剪:

def init(self, size, padding=None, pad_if_needed=False, fill=0, padding_mode="constant")

​ size : (h,w) 类型:依照 长、宽裁剪; int 类型:方形裁剪(int,int) ​ padding: 边框填充,如果提供了单个int,则用于填充所有边框。如果提供了长度为2的序列,则这是填充分别位于左侧/右侧和顶部/底部。如果提供长度为4的序列,这是分别用于左、上、右和下边框的填充。

RandomCrop需要输入一个格式为PIL类型的图像

Python
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
#传入数据
img = Image.open("data/train/ants/0013035.jpg")
print(type(img))#是PIL类型
writer = SummaryWriter('runs/exp1')

# 裁剪成100*10的图像
tran_crop = transforms.RandomCrop(100,10)
# 创建转换成tensor张量的方法
transforms_totensor = transforms.ToTensor()
#使用Compose方法来组合使用transforms对象
trans_compose2 = transforms.Compose([tran_crop,transforms_totensor])

# 随机裁剪10次
for i in range(10):
    #数据传入
    img_crop =trans_compose2(img)
    writer.add_image('images',img_crop,i)

writer.close()

七、DataLoader的使用

使用CIFAR10数据集来讲解Dataloader的使用方法,并写入tensorboard中,可以更好的去查看。这是官方提供的数据集。

为什么学习Dataloader?

在pytorch中如何读取数据主要有两个类,分别是Dataset和Dataloader。 dataset可以理解为:提供一种方式去获取数据及其label(标签)。可以实现

(1)如何获取每一个数据及其label;

​ (2)总共有多少数据。这两个功能。

dataloader可以理解为:为后面的网络提供不同的数据形式。相比较dataset,dataloader更难一点,DataLoader直接与后面的神经网络有关,所以要重点学习。

7.1 DataLoader类的官方解释

Python
DataLoader(
 dataset,
 batch_size=1,
 shuffle=False,
 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
)
Python
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, 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)

详细注释:

dataset (Dataset) – 从中加载数据的数据集。 batch_size (int, optional) – 每批要加载多少个样本(默认值:1)。 shuffle (bool, optional) – 设置为 True 让数据在每个 epoch 重新洗牌(默认值:False)。 sampler(Sampler 或 Iterable,可选)——定义从数据集中抽取样本的策略。可以是任何实现了 len 的 Iterable。如果指定,则不得指定 shuffle。 batch_sampler(Sampler 或 Iterable,可选)- 类似于 sampler,但一次返回一批索引。与 batch_size、shuffle、sampler 和 drop_last 互斥。 num_workers (int, optional) – 用于数据加载的子进程数。 0 表示数据将在主进程中加载​​。 (默认值:0) collat​​e_fn(可调用,可选)——合并样本列表以形成小批量张量。从地图样式数据集中使用批量加载时使用。 pin_memory (bool, optional) – 如果为 True,数据加载器将在返回之前将张量复制到 CUDA 固定内存中。如果您的数据元素是自定义类型,或者您的 collat​​e_fn 返回一个自定义类型的批次,请参见下面的示例。 drop_last (bool, optional) – 如果数据集大小不能被批次大小整除,则设置为 True 以丢弃最后一个不完整的批次。如果 False 并且数据集的大小不能被批大小整除,则最后一批将更小。 (默认:假) timeout (numeric, optional) -- 如果为正,则从工人那里收集批次的超时值。应始终为非负数。 (默认值:0) worker_init_fn (callable, optional) – 如果不是None,这将在播种之后和数据加载之前以worker id([0,num_workers - 1]中的一个int)作为输入在每个worker子进程上调用。 (默认:无)

7.1.1如何导入并使用CIFAR10数据集

CIFR10参数

root: Union[str, Path],#即CIFR10存放的地址或下载的地址 train: bool = True,#是否为训练数据,反正为测试数据 transform: Optional[Callable] = None,#可选 target_transform: Optional[Callable] = None,#可选 download: bool = False,#是否要下载CIFR10数据,对应root参数

Python
import torchvision

train_set=torchvision.dataset.CIFAR10(root="./dataTest",train=True,download=True)

7.1.2 如何使用Dataset

Python
import torchvision
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("logs") # 日志文件存储位置
dataset_transform = transforms.Compose([
    transforms.ToTensor() 
])
train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True,transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset", train=False,transform=dataset_transform, download=True)
print(test_set[0])
img, target = test_set[0]  # target对应类的编号 对应cat
print(img)
print(target)
print(test_set.classes[target])

for i in range(10):
    img, target = test_set[i]
    writer.add_image("torchvision",img,i)
writer.close()

7.1.3 如何使用DataLoader

Python
from torch.utils.data import DataLoader
test_loader = DataLoader(dataset=train_set,batch_size=128,shuffle=True,num_workers=0,drop_last=False)

'''
注释:
dataset=test_data,     从test_data中加载数据
batch_size=128,        一次加载128个样本
shuffle=True,           true表示 在每一次循环中都变化,随机取样
num_workers=0,          在主程序进行
drop_last=False         保留最后一个不完整的批次,为True删除最后不完整的批次
'''

7.1.4利用tensorboard查看其Dataloader结果(完整代码)

Python
import torchvision.datasets
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

dataset_transform = transforms.Compose([
    transforms.ToTensor() # 转化为Tensor
])
test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=dataset_transform, download=True)
test_loader = DataLoader(dataset=test_set, batch_size=64, shuffle=True, num_workers=0, drop_last=False)
imgs, targets = test_set[0] # 获取CIFAR10中下标为0数据
print(imgs.shape)
print(targets)
writer = SummaryWriter("logs")
step = 0
for data in test_loader:
    imgs, targets = data
    writer.add_images("训练模型", imgs, step)
    step = step + 1
writer.close()

7.1.5 Dataset和Dataloader的区别:

https://blog.csdn.net/hxhabcd123/article/details/132953769

Dataset定义了数据集的内容,它相当于一个类似列表的数据结构,具有确定的长度,能够用索引获取数据集中的元素。

DataLoader定义了按batch加载数据集的方法,它是一个实现了**iter方法的可迭代对象,**每次迭代输出一个batch的数据。 DataLoader能够控制batch的大小,batch中元素的采样方法,以及将batch结果整理成模型所需输入形式的方法(collate_fn),并且能够使用多进程读取数据。

在绝大部分情况下,用户只需实现Dataset的__len__方法和__getitem__方法,就可以轻松构建自己的数据集,并用默认数据管道进行加载。

分工上的不同

1. 获取一个batch数据的步骤

让我们考虑一下从一个数据集中获取一个batch的数据需要哪些步骤。 (假定数据集的特征和标签分别表示为张量X和Y,数据集可以表示为(X,Y), 假定batch大小为m) 1,首先我们要确定数据集的长度n。

结果类似:n = 1000。 2,然后我们从0到n-1的范围中抽样出m个数(batch大小)。

假定m=4, 拿到的结果是一个列表,类似:indices = [1,4,8,9]

3,接着我们从数据集中去取这m个数对应下标的元素。

拿到的结果是一个元组列表,类似:samples = [(X[1],Y[1]),(X[4],Y[4]),(X[8],Y[8]),(X[9],Y[9])]

4,最后我们将结果整理成两个张量作为输出。

拿到的结果是两个张量,类似batch = (features,labels)

其中 features = torch.stack([X[1],X[4],X[8],X[9]])

labels = torch.stack([Y[1],Y[4],Y[8],Y[9]])

上述第1个步骤确定数据集的长度是由 Dataset_len_ 方法实现的。 第2个步骤从0到n-1的范围中抽样出m个数的方法是由DataLoader 的 sampler 和 batch_sampler参数指定的。 sampler参数指定单个元素抽样方法,一般无需用户设置,程序默认在DataLoader的参数shuffle=True时采用随机抽样,shuffle=False时采用顺序抽样。 batch_sampler参数将多个抽样的元素整理成一个列表,一般无需用户设置,默认方法在DataLoader的参数drop_last=True时会丢弃数据集最后一个长度不能被batch大小整除的批次,在drop_last=False时保留最后一个批次。 第3个步骤的核心逻辑根据下标取数据集中的元素 是由 Dataset的 getitem方法实现的。 第4个步骤的逻辑由DataLoader的参数collate_fn指定。一般情况下也无需用户设置。

Python
import torch 
from torch.utils.data import TensorDataset,Dataset,DataLoader
from torch.utils.data import RandomSampler,BatchSampler 


ds = TensorDataset(torch.randn(1000,3),
                   torch.randint(low=0,high=2,size=(1000,)).float())
dl = DataLoader(ds,batch_size=4,drop_last = False)
features,labels = next(iter(dl))
print("features = ",features )
print("labels = ",labels )  

1

Dataset类的使用