Pytorch总结一之 数据操作、类型转换、数学计算、自动求梯度

Pytorch总结一

在PyTorch中, torch.Tensor 是存储和变换数据的主要⼯具。如果你之前⽤过NumPy,你会发现TensorNumPy的多维数组⾮常类似。然⽽, Tensor 提供GPU计算和⾃动求梯度等更多功能,这些使 Tensor 更加适合深度学习。

1.数据操作

导入包

import torch
#1.数据操作
x=torch.empty(5,3)   #创建5*3的未初始化tensor
print(x)
# tensor([[8.9082e-39, 1.0194e-38, 9.1837e-39],
#         [4.6837e-39, 9.2755e-39, 1.0837e-38],
#         [8.4490e-39, 1.0194e-38, 1.0194e-38],
#         [4.8674e-39, 9.9184e-39, 9.0000e-39],
#         [1.0561e-38, 1.0653e-38, 4.1327e-39]])

x=torch.rand(5,3)  #随机初始化
print(x)
# tensor([[0.6869, 0.1009, 0.4414],
#         [0.9740, 0.1829, 0.2010],
#         [0.0281, 0.9740, 0.6624],
#         [0.0604, 0.0146, 0.1782],
#         [0.7365, 0.4841, 0.1844]])

x=torch.zeros(5,3,dtype=torch.long)  #long全零tensor
print(x)
# tensor([[0, 0, 0],
#         [0, 0, 0],
#         [0, 0, 0],
#         [0, 0, 0],
#         [0, 0, 0]])

x=torch.tensor([5.5,3]) #直接数据创建
print(x)
#tensor([5.5000, 3.0000])

#还可以通过现有的 Tensor 来创建,此⽅法会默认᯿⽤输⼊ Tensor 的⼀些属性,
#例如数据类型,除⾮⾃定义数据类型。
x=x.new_ones(5,3,dtype=torch.float64)
print(x)
# tensor([[1., 1., 1.],
#         [1., 1., 1.],
#         [1., 1., 1.],
#         [1., 1., 1.],
#         [1., 1., 1.]], dtype=torch.float64)

x=torch.randn_like(x,dtype=torch.float) #指定新的数据类型
print(x)
# tensor([[-0.5007, -1.4208,  0.0125],
#         [-1.2975,  1.5053, -0.2303],
#         [-0.0361,  0.2742,  1.1563],
#         [-0.2017, -1.2620,  1.8696],
#         [ 0.0733,  1.0655, -1.0969]])

#通过 shape 或者 size() 来获取 Tensor 的形状:
print(x.size())
print(x.shape)
# torch.Size([5, 3])
# torch.Size([5, 3])

#others:
# ones(*size) 全1tensor
# eyes(*size) 对角线为1,其他为0
# arange(s,e,step) 从s 到e,步长为step
# linspace(s,e,steps) 从s到e,均匀切分成steps份
# rand/randn(*sizes) 均匀/标准分布
# normal(mean,std)/uniform(from,to) 正态分布/均匀分布
# randperm(m)  随机排列

2. 算术操作

#2.算术操作

#加法:以下形式结果相同
y=torch.rand(5,3)
y1=torch.add(x,y)
y2=x+y
y.add_(x)
y3=y
print(y1)
print(y2)
print(y3)
#均输出:
# tensor([[ 1.4572,  1.1814,  1.0476],
#         [ 0.2844, -0.0457, -0.7777],
#         [ 0.5250,  1.4636, -0.6049],
#         [ 1.2933, -0.8186,  1.4611],
#         [-1.0812,  0.7444,  0.5850]])

3. 索引

#3.索引  索引出来的结果与原数据共享内存,也即修改⼀个,另⼀个会跟着修改。
y=x[0,:]
print(y)
#tensor([ 0.2176, -0.4934,  0.0061])
y+=1
print(y)
print(x[0,:])
# tensor([1.4410, 1.5247, 1.0603])
# tensor([1.4410, 1.5247, 1.0603])    #源tensor也更改了

#others:
# torch.index_select(input,dim,index)  在指定维度dim上选取,比如某些行,某些列
# torch.masked_select(input,mask)  a(a>0),使用Bytetensor进行选取
# torch.non_zero(input)  非0元素的下标
# torch.gather(input,dim,index)  根据index,在dim维度上选取数据,输出的size跟index一样

4. 改变形状

#4.改变形状,
y=x.view(15)
z=x.view(-1,5) #-1所指的维度可以根据其他维度的值推出来
print(x.size(),y.size(),z.size())
#torch.Size([5, 3]) torch.Size([15]) torch.Size([3, 5])

#注意 view() 返回的新tensor与源tensor共享内存(其实是同⼀个tensor),即一个变两个都变
x_cp=x.clone().view(15)
x-=1
print(x)
print(x_cp)
# tensor([[ 0.6842,  1.8774, -1.4890],
#         [-2.3937, -0.7941, -1.1918],
#         [-2.4145, -0.8577, -1.0604],
#         [-1.4423,  0.2233, -1.1764],
#         [-0.4029, -1.5999, -0.7380]])
# tensor([ 1.6842,  2.8774, -0.4890, -1.3937,  0.2059, -0.1918, -1.4145,  0.1423,
#         -0.0604, -0.4423,  1.2233, -0.1764,  0.5971, -0.5999,  0.2620])

#item() , 它可以将⼀个标量 Tensor 转换成⼀个Python number:
x=torch.randn(1)
print(x)
print(x.item())
# tensor([-1.6042])
# -1.6041609048843384

5.线性代数

#5.线性代数
# torch.trace()  对角线元素之和,矩阵的迹
# torch.diag()  对角线元素
# torch.triu()/tril()  矩阵的上三角/下三角,可指定偏移量
# torch.mm()/torch.bmm()  矩阵乘法,batch的矩阵乘法
# torch.addmm()/addbmm/addmv/addr/badbmm  矩阵运算
# torch.t() 转置
# torch.dot()/torch.cross() 内积/外积
# torch.inverse()  求逆矩阵
# torch.svd() 奇异值分解

6. 广播机制

#6.广播机制 当对两个形状不同的 Tensor 按元素运算时,可能会触发⼴播(broadcasting)机制:
# 先适当复制元素使这两个 Tensor 形状相同后再按元素运算。
x=torch.arange(1,3).view(1,2)
print(x)
#tensor([[1, 2]])
y=torch.arange(1,4).view(3,1)
print(y)
print(x+y)
# tensor([[1],
#         [2],
#         [3]])
# tensor([[2, 3],
#         [3, 4],
#         [4, 5]])

7. 运算的内存开销

#7.运算的内存开销
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x                  #开辟新内存
print(id(y) == id_before) # False

x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x               #不开辟新内存
print(id(y) == id_before) # True

#the same as:
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
torch.add(x, y, out=y) # y += x, y.add_(x) #规定输出
print(id(y) == id_before) # True

8. 数据类型转换

#8.数据类型转换
tensor = torch.Tensor(3, 5)
print(tensor.type())   #torch.FloatTensor

# torch.long() 将tensor投射为long类型
newtensor = tensor.long()
print(newtensor.type()) #torch.LongTensor

#others:
newtensor = tensor.half()
newtensor = tensor.int()
newtensor = tensor.double()
newtensor = tensor.float()
newtensor = tensor.char()
newtensor = tensor.byte()
newtensor = tensor.short()

#8.1 tensor转numpy
a = torch.ones(5)
b = a.numpy()
print(a, b)
#tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]

a += 1
print(a, b)
#tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]

b += 1
print(a, b)
# tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]

#8.2 numpy转tensor  使⽤ from_numpy() 将NumPy数组转换成 Tensor :
import numpy as np
a=np.ones(5)
b=torch.from_numpy(a)
print(a,b)
# [1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)

a+=1
print(a,b)
#[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

9. tersor on GPU

#9. tersor on GPU  ⽤⽅法 to() 可以将 Tensor 在CPU和GPU(需要硬件⽀持)之间相互移动
# 以下代码只有在PyTorch GPU版本上才会执⾏
if torch.cuda.is_available():
    device = torch.device("cuda") # GPU
    y = torch.ones_like(x, device=device) # 直接创建⼀个在GPU上的Tensor
    x = x.to(device) # 等价于 .to("cuda")
    z = x + y
    print(z)
    print(z.to("cpu", torch.double)) # to()还可以同时更改数据类型

# tensor([2, 3], device='cuda:0')
# tensor([2., 3.], dtype=torch.float64)

10. 自动求梯度

#10. 自动求梯度
x = torch.ones(2, 2, requires_grad=True)  #追踪在其上的所有操作
print(x)
print(x.grad_fn)
# tensor([[1., 1.],
#         [1., 1.]], requires_grad=True)
# None

y=x+2
print(y)
print(y.grad_fn)
# tensor([[3., 3.],
#         [3., 3.]], grad_fn=<AddBackward0>)
# <AddBackward0 object at 0x0000020A1B6770A0>   #显示进行了加法操作

#像x这种直接创建的称为叶⼦节点,叶⼦节点对应的 grad_fn 是 None 。
print(x.is_leaf,y.is_leaf) #True False

z = y * y * 3
out = z.mean()
print(z, out)
# tensor([[27., 27.],
#         [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)

#通过 .requires_grad_() 来⽤in-place的⽅式改变 requires_grad 属性
a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
a = ((a * 3) / (a - 1))
print(a.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True
b = (a * a).sum()
print(b.grad_fn)
# <SumBackward0 object at 0x000002513A0B70A0>

10.1. 梯度

out.backward()  # 等价于 out.backward(torch.tensor(1.))

print(x.grad)     #out关于x的梯度 d(out)/dx
# tensor([[4.5000, 4.5000],
#         [4.5000, 4.5000]])

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# 再来反向传播⼀次,注意grad是累加的
out2 = x.sum()
out2.backward()
print(x.grad)
# tensor([[5.5000, 5.5000],
#         [5.5000, 5.5000]])

out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)
# tensor([[1., 1.],
#         [1., 1.]])
# 不允许张量对张量求导,只允许标量对张量求导,求导结果是和⾃变量同形的张量
x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True)
y = 2 * x
z = y.view(2, 2)
print(z)
# tensor([[2., 4.],
#  [6., 8.]], grad_fn=<ViewBackward>)

#现在 y 不是⼀个标量,所以在调⽤ backward 时需要传⼊⼀个和 y 同形的权᯿向量进⾏加权求和得到⼀个标量v。
v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float)
z.backward(v)
print(x.grad)
# tensor([2.0000, 0.2000, 0.0200, 0.0020])  #x.grad 是和 x 同形的张量。

#梯度追踪:
x = torch.tensor(1.0, requires_grad=True)
y1 = x ** 2
with torch.no_grad():
    y2 = x ** 3
y3 = y1 + y2

print(x.requires_grad)
print(y1, y1.requires_grad)  # True
print(y2, y2.requires_grad)  # False
print(y3, y3.requires_grad)  # True
# True
# tensor(1., grad_fn=<PowBackward0>) True
# tensor(1.) False
# tensor(2., grad_fn=<ThAddBackward>) True

#如果我们想要修改 tensor 的数值,但是⼜不希望被 autograd 记录(即不会影响反向传播),
#那么我么可以对 tensor.data 进⾏操作:
x = torch.ones(1,requires_grad=True)
print(x.data) # 还是⼀个tensor
print(x.data.requires_grad) # 但是已经是独⽴于计算图之外
# tensor([1.])
# False

y = 2 * x
x.data *= 100 # 只改变了值,不会记录在计算图,所以不会影响梯度传播
y.backward()
print(x) # 更改data的值也会影响tensor的值
print(x.grad)
# tensor([100.], requires_grad=True)
# tensor([2.])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值