Pytorch深度学习01 | 入门预备知识:数据操作之Tensor

1. 信息概要

🙋面向对象:入门深度学习、基于Pytorch的学习者
✍️笔记日期:2024.08.06
💫所需基础:安装miniconda、配置pytorch环境(cpu本文可用)
👀文章内容参考与总结

  1. 基于《动手学深度学习-Pytorch版(2.0.0)》 (Aston Zhang, Zachary C. Lipton etc.) -> 总结笔记,包括张量的定义、性质,介绍如何创建张量、张量的运算方法(形状相同与不同-广播机制)、索引与切片操作,讨论节省内存、Python对象间的转换、GPU与CPU之间的转换关系
  2. 基于 GitHub分享的笔记源码 进行总结、修改与拓展,添加一些必要的注释辅助理解
  3. 环境配置参考课本,创建并激活虚拟环境后执行如下指令
    pip install python=3.9
    pip install torch==1.12.0
    pip install torchvision==0.13.0
    pip install d2l==0.17.6 (可以下载到该书所需的所有包)
  4. 注:所有代码块在运行之前,需要确保已经在开头导入对应的包:import torch

2. 张量

2.1 定义

  • 数值组成的数组,可能由多个维度
  • 具有⼀个轴的张量对应数学上的向量(vector);
  • 具有两个轴的张量对应数学上的矩阵(matrix);
  • 具有两个轴以上的张量没有特殊的数学名称。

2.2 性质

  1. 张量形状:x.shape
  2. 计算张量元素个数:x.numel()
  3. 修改张量形状:x.reshape(3,4) 表示生成3行四列的矩阵
import torch 
print('1.张量的属性')
x = torch.arange(12)
print('x:', x)
print('x shape:', x.shape)  # 访问向量的形状
y = x.reshape(3, 4)  # 改变一个张量的形状而不改变元素数量和元素值
print('y:', y)
print('y.numel():', y.numel())  # 返回张量中元素的总个数

image.png

2.3 张量的创建

  1. 生成某个范围的元素:如 torch.arange(12)表示生成从0开始的前12个元素
  2. 元素全为1:每个元素均为1
  3. 元素全为0:每个元素均为0
  4. 随机采样:每个元素都从均值为0、标准差为1的标准高斯(正态)分布中随机采样
  5. 直接赋值:提供包含数值的Python列表(或嵌套列表),为所需张量中的每个元素赋予确定值
print('2.张量的创建')
# ones 函数创建一个具有指定形状的新张量,并将所有元素值设置为 1
t = torch.ones(4)
print('t:', t)
z = torch.zeros(2, 3, 4)  # 创建一个张量,其中所有元素都设置为0
print('z:', z)
# 创建一个三维张量,第一个维度大小为 2,第二个维度大小为 3,第三个维度大小为 4
# 每个元素都从均值为0、标准差为1的标准高斯(正态)分布中随机采样
w = torch.randn(2, 3, 4)
print('w:', w)
# 直接创建张量:表示一个二维数组,其中包含三个子数组,每个子数组分别代表张量的一行
q = torch.tensor([[1, 2, 3], [4, 3, 2], [7, 4, 3]])
print('q:', q)

image.png

2.4 张量的运算

注意前提:张量的形状相同(.shape的结果相同),除了exp运算与所有元素求和

  1. 加减乘除:+ - * /
  2. 求幂运算:x**y,表示的是x的y次方
  3. 以e为底数的指数运算:torch.exp()
  4. 连结concatenate:把它们端对端地叠起来形成⼀个更⼤的张量。只需提供张量列表并给出沿哪个轴连结。
    对于矩阵而言,分沿dim=0,dim=1两种
  5. 逻辑运算符:判断对应元素是否符合逻辑表达式,返回True or False
  6. 张量所有元素求和:用如 X.sum()的语法
print('3.张量的运算')
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
print(x + y)
print(x - y)
print(x * y)
print(x / y)
print(x ** y)  # 运算符是求幂运算
print(torch.exp(x)) # 以e为底数,x为指数的指数运算
```python
###  综合应用:创建、变换、运算
# 指定类型为浮点数和三行四列的矩阵
X = torch.arange(12, dtype=torch.float32).reshape(3, 4)
print('X:', X)
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print('Y:', Y)
# 连结(concatenate) ,将它们端到端堆叠以形成更大的张量
# 对于矩阵,dim=0表示行方向,dim=1表示列方向
print('cat操作 dim=0', torch.cat((X, Y), dim=0))
print('cat操作 dim=1', torch.cat((X, Y), dim=1))
# 通过 逻辑运算符 构建二元张量
print('X == Y', X == Y)
print('X < Y', X < Y)
print('张量所有元素的和:', X.sum())  # 张量所有元素的和

image.png

2.5 广播机制

对于形状不相同的张量运算,我们采用广播机制(broadcasting mechanism)来执⾏按元素操作。
⼯作⽅式如下:
1. 通过适当复制元素来扩展⼀个或两个数组,以便在转换之后,两个张量具有相同的形状
2. 对⽣成的数组执⾏按元素操作。

print('4.广播机制')
a = torch.arange(3).reshape(3, 1)
b = torch.arange(2).reshape(1, 2)
print('a:', a)
print('b:', b)
# 将两个矩阵⼴播为⼀个更⼤的3 × 2矩阵,如下所⽰:矩阵a将复制列,矩阵b将复制⾏,然后再按元素相加
print('a + b:', a + b)

image.png

2.6 索引与切片

  1. 索引方式:方式包括按行、按列索引(结合切片操作实现)与指定具体位置的索引
  2. 写入元素操作:指定某个位置的元素,指定某行、某列的元素
print('5.索引和切片')
X = torch.arange(12, dtype=torch.float32).reshape(3, 4)
print('X:', X)
print('X[-1]:', X[-1])  # 用 [-1] 选择最后一行元素
print('X[1:3]:', X[1:3])  # 用 [1:3] 选择第二行和第三行元素
print('X[1, 2]:', X[1, 2])  # 用 [1, 2] 选择第二行第三列元素
print('X[:,2]', X[:,2])  # 用 [1, 2] 选择第三列元素
X[1, 2] = 9  # 写入元素
print('写入索引为(1,2)[二行三列]位置元素为9后的X:', X)
X[0:2, :] = 12  # 写入元素
print('写入第1、2行的元素为12后的X:', X)

image.png

2.7 节省内存

示例:运⾏⼀些操作可能会导致为新结果分配内存,最好实现原地更新。

当⽤Y = X + Y,我们将取消引⽤Y指向的张量, Y将指向新分配的内存处的张量,但最好是进行原地更新,原因如下:

  1. 在机器学习中,我们可能有数百兆的参数,并且在⼀秒内多次更新所有参数,若是每更新一次就由产生额外的内存,
    是一种不必要的分配内存方式;
  2. 如果我们不原地更新,其他引⽤仍然会指向旧的内存位置,这样我们的某些代码可能会⽆意中引⽤旧的参数。

针对此类运算操作,用 X[:] = X + Y 或 X += Y 来减少操作的内存开销。

print('6.节约内存')
before = id(Y)  # id()函数提供了内存中引用对象的确切地址
Y = Y + X
print(id(Y) == before) # 为False,表明分配了新的内存空间

# 使用 X[:] = X + Y 或 X += Y 来减少操作的内存开销
before = id(X)
X += Y
print(id(X) == before)

before = id(X)
X[:] = X + Y
print(id(X) == before)

image.png

2.8 Python对象间的转换

  1. torch张量与NumPy张量(ndarray)之间的转换
    torch张量和numpy数组将共享它们的底层内存,就地操作更改⼀个张量也会同时更改另⼀个张量。
  2. ⼤⼩为1的张量转换为Python标量
    我们可以调⽤item函数获取张量中的单个元素,以及python其它内置函数如float、int、round等。

print('7.转换为其他 Python对象')
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
print('----A----')
A = Y.numpy()
print(type(A))  # 打印A的类型
print(A)
print('----B----')
B = torch.tensor(A)
print(type(B))  # 打印B的类型
print(B)

a = torch.tensor([3.5])
# 张量的 .item() 方法,用于获取张量中的单个元素的 Python 数值
print(a, a.item(), float(a), int(a))
print('round(a.item():',round(a.item())) # round 四舍五入
print('int(a.item()):',int(a.item())) # int 向下取整

image.png

2.9 GPU与CPU转换

  1. 在GPU与CPU之间的移动:to()方法
  2. 指定设备方法:torch.device(“”)
print('8.张量在GPU上的运算')
### 注意: GPU上才会执行如下代码
if torch.cuda.is_available():
    device = torch.device("cuda")          # GPU
    #device = torch.device("cuda:0")       # 指定第一个GPU
    #device = torch.device("cpu")            # 指定CPU
    y = torch.ones_like(x, device=device)  # 直接创建一个在GPU上的Tensor
    x = x.to(device)                       # 等价于 .to("cuda") 将一个Tensor移动到GPU上
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # 将张量 z 移动到 CPU,并且将其数据类型转换为 torch.double。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值