深度学习学习笔记DAY01

数据操作与自动求导

Posted by zhaiyunfan on January 24, 2020

前言

正文

这里把笔记性质的一些代码放上来,大年三十去趟爷爷奶奶和姥爷那边,晚点细致整理一下,绝不咕咕咕

import torch

# 创建一个5x3未初始化的Tensor
x = torch.empty(5, 3)
print(x)

# 创建一个5x3随机初始化的Tensor
x = torch.rand(5, 3)
print(x)

# 创建一个全0、5x3、数据类型为long的Tensor
x = torch.zeros(5, 3, dtype=torch.long)
print(x)

# 注意这里是直接把[5.5, 3]作为参数传入,即直接创建一个指定内容的Tensor
x = torch.tensor([5.5, 3])
print(x)

# 根据现有的Tensor创建,可以自定义其形状和数据类型,默认重用输入Tensor的属性
x = x.new_ones(5, 3, dtype=torch.float64)
print(x)
x = torch.randn_like(x, dtype=torch.float)
print(x)

# 可以通过size()函数或者直接访问shape成员来获取Tensor的形状
print(x.size())
print(x.shape)

# 加法的三种形式
# 其一
y = torch.rand(5, 3)
print(x + y)

# 其二
print(torch.add(x, y))
# 也可指定输出
result = torch.empty(5, 3)
torch.add(x, y, out=result)
print(result)

# 其三inplace(保存在y中,需添加后缀_)
y.add_(x)
print(y)

# 索引
# 与原数据共享内存
y = x[0, :]
y += 1
print(y)
print(x[0, :])

# 可以用view()来改变Tensor的形状
y = x.view(15)
z = x.view(-1, 5)   # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size())
# 注意view()返回的新Tensor与源Tensor虽然可能有不同的size,但是是共享data的
# 顾名思义,view仅仅是改变了对这个张量的观察角度,内部数据并未改变
x += 1
print(x)
print(y)    # 也加了1
# 所以如果我们想返回一个真正新的副本(即不共享data内存)该怎么办呢?
# Pytorch还提供了一个reshape()可以改变形状,但是此函数并不能保证返回的是其拷贝,所以不推荐使用。
# 推荐先用clone创造一个副本然后再使用view。
x_cp = x.clone().view(15)
x -= 1
print(x)
print(x_cp)

# 把Tensor转换成Python number
x = torch.randn(1)
print(x)
print(x.item())

# 广播机制,会把形状不同的两个Tensor先自我复制扩展成相同的形状
x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)

# 运算的内存开销
# 前面说了,索引操作是不会开辟新内存的,而像y = x + y这样的运算是会新开内存的,然后将y指向新内存。
# 为了演示这一点,我们可以使用Python自带的id函数:
# 如果两个实例的ID一致,那么它们所对应的内存地址相同;反之则不同。
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y = y + x
print(id(y) == id_before)   # False
# 如果想指定结果到原来的y的内存,我们可以使用前面介绍的索引来进行替换操作。
# 在下面的例子中,我们把x + y的结果通过[:]写进y对应的内存中。
x = torch.tensor([1, 2])
y = torch.tensor([3, 4])
id_before = id(y)
y[:] = y + x
print(id(y) == id_before)   # True
# 我们还可以使用运算符全名函数中的out参数或者自加运算符+=(也即add_())达到上述效果
# 例如torch.add(x, y, out=y)和y += x(y.add_(x))。
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
# 注:虽然view返回的Tensor与源Tensor是共享data的,但是依然是一个新的Tensor
# 因为Tensor除了包含data外还有一些其他属性,二者id(内存地址)并不一致。

# 用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()还可以同时更改数据类型

后记