栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

pytorch学习记录(1)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

pytorch学习记录(1)

可以使⽤类似NumPy的索引操作来访问 Tensor 的⼀部分,需要注意的是:索引出来的结果与
原数据共享内存,也即修改⼀个,另⼀个会跟着修改。
ex1:
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
y = x[0, :]
y += 1
print(y)
print(x[0, :]) # 源tensor也被改了;

即print(y)和print(x[0, :])输出相同,在使用中注意torch中有很多这种共享内存的操作
ex2:
⽤ view() 来改变 Tensor 的形状:
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
y = x.view(15) z = x.view(-1, 5) # -1所指的维度可以根据其他维度的值推出来
print(x.size(), y.size(), z.size());

注意 view() 返回的新tensor与源tensor共享内存(其实是同⼀个tensor),也即更改其中的⼀个,另
外⼀个也会跟着改变。(顾名思义,view仅仅是改变了对这个张量的观察⻆度)

所以如果我们想返回⼀个真正新的副本(即不共享内存)该怎么办呢?Pytorch还提供了⼀
个 reshape() 可以改变形状,但是此函数并不能保证返回的是其拷⻉,所以不推荐使⽤。推荐先
⽤ clone 创造⼀个副本然后再使⽤ view 。
ex3
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
x_cp = x.clone().view(15) x -= 1
print(x)
print(x_cp);

使⽤ clone 还有⼀个好处是会被记录在计算图中,即梯度回传到副本时也会传到源 Tensor 。
另外⼀个常⽤的函数就是 item() , 它可以将⼀个标量 Tensor 转换成⼀个Python number:

当对两个形状不同的 Tensor 按元素运算时,可能会触发⼴播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。例如:
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
x = torch.arange(1, 3).view(1, 2)
print(x) y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y);
输出
tensor([[1, 2]])
tensor([[1],
 		[2],
 		[3]])
tensor([[2, 3],
		[3, 4],
 		[4, 5]])

前⾯说了,索引、 view 是不会开辟新内存的,⽽像 y = x + y 这样的运算是会新开内存的,然后
将 y 指向新内存。为了演示这⼀点,我们可以使⽤Python⾃带的 id 函数:如果两个实例的ID⼀致,那
么它们所对应的内存地址相同;反之则不同。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
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 对应的内存中。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
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) )。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
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;

tensor和numpy之间相互转换
我们很容易⽤ numpy() 和 from_numpy() 将 Tensor 和NumPy中的数组相互转换。但是需要注意的⼀
点是: 这两个函数所产⽣的的 Tensor 和NumPy中的数组共享相同的内存(所以他们之间的转换很
快),改变其中⼀个时另⼀个也会改变!!!
还有⼀个常⽤的将NumPy中的array转换成 Tensor 的⽅法就是 torch.tensor() , 需要注意的
是,此⽅法总是会进⾏数据拷⻉(就会消耗更多的时间和空间),所以返回的 Tensor 和原来的数
据不再共享内存。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
a = torch.ones(5) b = a.numpy()
print(a, b) a += 1
print(a, b) b += 1
print(a, b);

输出
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.]
tensor([2., 2., 2., 2., 2.]) [2. 2. 2. 2. 2.]
tensor([3., 3., 3., 3., 3.]) [3. 3. 3. 3. 3.]

使⽤ from_numpy() 将NumPy数组转换成 Tensor :
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
import numpy as np
a = np.ones(5) b = torch.from_numpy(a)
print(a, b) a += 1
print(a, b) b += 1
print(a, b);
输出
[1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
[2. 2. 2. 2. 2.] tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
[3. 3. 3. 3. 3.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)

所有在CPU上的 Tensor (除了 CharTensor )都⽀持与NumPy数组相互转换。
此外上⾯提到还有⼀个常⽤的⽅法就是直接⽤ torch.tensor() 将NumPy数组转换成 Tensor ,需要
注意的是该⽅法总是会进⾏数据拷⻉,返回的 Tensor 和原来的数据不再共享内存。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
c = torch.tensor(a) a += 1
print(a, c);
输出
[4. 4. 4. 4. 4.] tensor([3., 3., 3., 3., 3.], dtype=torch.float64)

⾃动求梯度
Tensor 是这个包的核⼼类,如果将其属性 .requires_grad 设置为 True ,它将开始追
踪(track)在其上的所有操作(这样就可以利⽤链式法则进⾏梯度传播了)。完成计算后,可以调
⽤ .backward() 来完成所有梯度计算。此 Tensor 的梯度将累积到 .grad 属性中。
注意在 y.backward() 时,如果 y 是标量,则不需要为 backward() 传⼊任何参数;否则,需要
传⼊⼀个与 y 同形的 Tensor 。
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn);
输出
tensor([[1., 1.],
 		[1., 1.]], requires_grad=True)
None
123

这里我们首先创建一个全1的tensor,并且设置一个属性
requires_grad=True
每个 Tensor 都有⼀个 .grad_fn 属性,该属性即创建该 Tensor 的
Function , 就是说该 Tensor 是不是通过某些运算得到的,若是,则 grad_fn 返回⼀个与这些运算相
关的对象,否则是None。Function 是另外⼀个很重要的类。
接下来我们做一个运算操作
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
y = x + 2
print(y)
print(y.grad_fn);
输出
tensor([[3., 3.],
 		[3., 3.]], grad_fn=)

注意x是直接创建的,所以它没有 grad_fn , ⽽y是通过⼀个加法操作创建的,所以它有⼀个为
的 grad_fn 。 像x这种直接创建的称为叶⼦节点,叶⼦节点对应的 grad_fn 是 None 。
print(x.is_leaf, y.is_leaf) # True False,is_leaf是判断当前该tensor是否是一个叶子节点

下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
z = y * y * 3
out = z.mean()
print(z, out);
输出
tensor([[27., 27.],
 		[27., 27.]], grad_fn=) 
tensor(27., grad_fn=)

通过 .requires_grad_() 来⽤in-place的⽅式改变 requires_grad 属性:
下面展示一些 内联代码片。

// A code block
var foo = 'bar';
// An highlighted block
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);
输出
False
True

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/286379.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号