在动手学习深度学习中我碰到有关GPU计算的疑惑,首先给出代码
def corr2d(X, K):
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
def corr2d_multi_in(X, K):
# 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
return sum(corr2d(x, k) for x, k in zip(X, K))
def corr2d_multi_in_out(X, K):
# 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。
# 最后将所有结果都叠加在一起
return torch.stack([corr2d_multi_in(X, k) for k in K], 0)
这三个函数共同实现了多输入多输出通道的互相关运算。
def corr2d_multi_in_out_1x1(X, K):
c_i, h, w = X.shape
c_o = K.shape[0]
X = X.reshape((c_i, h * w))
K = K.reshape((c_o, c_i))
# 全连接层中的矩阵乘法
Y = torch.matmul(K, X)
return Y.reshape((c_o, h, w))
上面的函数是使用全连接层实现1×1卷积核的多输入多输出通道的互相关运算,c_i为输入通道数,c_o为输出通道数。
接下来我们尝试使用GPU比较两种1×1卷积核互相关运算的速度差异。
def try_gpu(i=0):
"""如果存在,则返回gpu(i),否则返回cpu()"""
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')
import time
import torch
X = torch.normal(0, 1, (3, 1920, 1080),device=try_gpu())
K = torch.normal(0, 1, (2, 3, 1, 1),device=try_gpu())
startTime1=time.time()
for i in range(100):
Y1=corr2d_multi_in_out_1x1(X, K)
endTime1=time.time()
print(round((endTime1 - startTime1)*1000, 2),'ms')
164.34 ms
运行时间为164.34ms。
startTime2=time.time()
for i in range(100):
Y2=corr2d_multi_in_out(X, K)
endTime2=time.time()
print(round((endTime1 - startTime1)*1000, 2),'ms')
我继续尝试使用另一种方法计算,但运行半天都没有结果,于是我试着减小计算量。
startTime2=time.time()
Y2 = corr2d_multi_in_out(X, K)
endTime2=time.time()
print(round((endTime2 - startTime2)*1000, 2),'ms')
这个计算量够小了吧,但也是迟迟没有结果,于是我再次减小。
X = torch.normal(0, 1, (3, 192, 108),device=try_gpu())
startTime3=time.time()
Y3 = corr2d_multi_in_out(X, K)
endTime3=time.time()
print(round((endTime3 - startTime3)*1000, 2),'ms')
7757.1 ms
运行结果为7757.1ms!我不敢相信,便改为cpu计算
X = torch.normal(0, 1, (3, 192, 108))
K = torch.normal(0, 1, (2, 3, 1, 1))
startTime4=time.time()
Y4 = corr2d_multi_in_out(X, K)
endTime4=time.time()
print(round((endTime4 - startTime4)*1000, 2),'ms')
1930.15 ms
结果是1930.15ms,比GPU还快!这到底是什么原因,难道是GPU不擅长运行传统for循环吗?