3.1.4 其它有关Tensor的话题
这部分的内容不好专门划分一小节,但是笔者认为仍值得读者注意,故而将其放在这一小节。
GPU/CPU
tensor可以很随意的在gpu/cpu上传输。使用tensor.cuda(device_id)
或者tensor.cpu()
。另外一个更通用的方法是tensor.to(device)
。
In [119]:
a = t.randn(3, 4)
a.device
Out[119]:
device(type='cpu')
In [120]:
if t.cuda.is_available():
a = t.randn(3,4, device=t.device('cuda:1'))
# 等价于
# a.t.randn(3,4).cuda(1)
# 但是前者更快
a.device
In [121]:
device = t.device('cpu')
a.to(device)
Out[121]:
tensor([[-1.8934, 0.8776, 2.3714, -0.0861],
[-0.2218, 1.7379, 0.5166, 0.2940],
[ 1.1621, 0.6702, -0.4791, -0.7298]])
注意
- 尽量使用
tensor.to(device)
, 将device
设为一个可配置的参数,这样可以很轻松的使程序同时兼容GPU和CPU - 数据在GPU之中传输的速度要远快于内存(CPU)到显存(GPU), 所以尽量避免频繁的在内存和显存中传输数据。
持久化
Tensor的保存和加载十分的简单,使用t.save和t.load即可完成相应的功能。在save/load时可指定使用的pickle
模块,在load时还可将GPU tensor映射到CPU或其它GPU上。
In [122]:
if t.cuda.is_available():
a = a.cuda(1) # 把a转为GPU1上的tensor,
t.save(a,'a.pth')
# 加载为b, 存储于GPU1上(因为保存时tensor就在GPU1上)
b = t.load('a.pth')
# 加载为c, 存储于CPU
c = t.load('a.pth', map_location=lambda storage, loc: storage)
# 加载为d, 存储于GPU0上
d = t.load('a.pth', map_location={'cuda:1':'cuda:0'})
向量化
向量化计算是一种特殊的并行计算方式,相对于一般程序在同一时间只执行一个操作的方式,它可在同一时间执行多个操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量上。向量化可极大提高科学运算的效率,Python本身是一门高级语言,使用很方便,但这也意味着很多操作很低效,尤其是for
循环。在科学计算程序中应当极力避免使用Python原生的for循环
。
In [123]:
def for_loop_add(x, y):
result = []
for i,j in zip(x, y):
result.append(i + j)
return t.Tensor(result)
In [124]:
x = t.zeros(100)
y = t.ones(100)
%timeit -n 10 for_loop_add(x, y)
%timeit -n 10 x + y
10 loops, best of 3: 997 µs per loop
The slowest run took 5.80 times longer than the fastest. This could mean that an intermediate result is being cached.
10 loops, best of 3: 4.91 µs per loop
可见二者有超过几十倍的速度差距,因此在实际使用中应尽量调用内建函数(buildin-function),这些函数底层由C/C++实现,能通过执行底层优化实现高效计算。因此在平时写代码时,就应养成向量化的思维习惯,千万避免对较大的tensor进行逐元素遍历。
此外还有以下几点需要注意:
- 大多数
t.function
都有一个参数out
,这时候产生的结果将保存在out指定tensor之中。 t.set_num_threads
可以设置PyTorch进行CPU多线程并行计算时候所占用的线程数,这个可以用来限制PyTorch所占用的CPU数目。t.set_printoptions
可以用来设置打印tensor时的数值精度和格式。 下面举例说明。
In [125]:
a = t.arange(0, 20000000)
print(a[-1], a[-2]) # 32bit的IntTensor精度有限导致溢出
b = t.LongTensor()
t.arange(0, 20000000, out=b) # 64bit的LongTensor不会溢出
b[-1],b[-2]
tensor(19999999) tensor(19999998)
Out[125]:
(tensor(19999999), tensor(19999998))
In [126]:
a = t.randn(2,3)
a
Out[126]:
tensor([[ 1.2645, 0.0270, -0.7174],
[ 0.4271, 0.0869, 0.6367]])
In [127]:
t.set_printoptions(precision=10)
a
Out[127]:
tensor([[ 1.2645452023, 0.0270472951, -0.7174307108],
[ 0.4270690084, 0.0868919790, 0.6366676688]])