Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python torch如何在几乎零的时间内将两个10000*10000矩阵相乘?为什么速度从349毫秒下降到999µ;s_Python_Performance_Jupyter Notebook_Pytorch - Fatal编程技术网

Python torch如何在几乎零的时间内将两个10000*10000矩阵相乘?为什么速度从349毫秒下降到999µ;s

Python torch如何在几乎零的时间内将两个10000*10000矩阵相乘?为什么速度从349毫秒下降到999µ;s,python,performance,jupyter-notebook,pytorch,Python,Performance,Jupyter Notebook,Pytorch,以下是Jupyter的摘录: 在[1]中: 导入火炬,numpy作为np,datetime cuda=火炬装置(“cuda”) 在[2]中: ac=torch.randn(10000,10000).to(cuda) bc=火炬。兰登(10000,10000)。至(cuda) %时间cc=火炬。马特穆尔(ac,bc) 打印(cc[0,0],torch.sum(ac[0,:]*bc[:,0])) 墙壁时间:349毫秒 张量(17.0374,device='cuda:0')张量(17.0376,d

以下是Jupyter的摘录:

[1]
中:

导入火炬,numpy作为np,datetime
cuda=火炬装置(“cuda”)
[2]
中:

ac=torch.randn(10000,10000).to(cuda)
bc=火炬。兰登(10000,10000)。至(cuda)
%时间cc=火炬。马特穆尔(ac,bc)
打印(cc[0,0],torch.sum(ac[0,:]*bc[:,0]))
墙壁时间:349毫秒

张量(17.0374,device='cuda:0')张量(17.0376,device='cuda:0'))

时间较短,但仍然合理(1e12乘法为0.35秒)

但如果我们重复同样的话:

ac=torch.randn(10000,10000).to(cuda)
bc=火炬。兰登(10000,10000)。至(cuda)
%时间cc=火炬。马特穆尔(ac,bc)
打印(cc[0,0],torch.sum(ac[0,:]*bc[:,0]))
壁时间:999µs

张量(-78.7172,装置='cuda:0')张量(-78.7173,装置='cuda:0'))

1e12
1ms
中进行乘法

为什么时间从349ms变为1ms

信息:

  • 在GeForce RTX 2070上测试
  • 可以在Google Colab上复制

  • 我猜是GPU内存缓存。每次运行后,请尝试torch.cuda.empty_cache()

    已在讨论PyTorch:上对此进行了讨论

    我想强调该帖子中的两条评论:

    • 发件人:
    […]GPU异步执行所有操作,因此您需要插入适当的屏障,使基准测试正确无误

    • 发件人:
    我相信现在cublas句柄是惰性分配的,这意味着需要cublas的第一个操作将有创建cublas句柄的开销,这包括一些内部分配。因此,除了在计时循环之前调用一些需要cublas的函数之外,没有其他方法可以避免它


    基本上,您必须
    synchronize()
    才能进行正确的测量:

    导入火炬
    x=火炬。兰登(10000,10000)。至(“cuda”)
    w=torch.randn(10000,10000)至(“cuda”)
    #确保在开始测量时间之前完成上下文初始化
    torch.cuda.synchronize()
    %时间y=x.mm(w.t());torch.cuda.synchronize()
    
    CPU时间:用户288毫秒,系统191毫秒,总计479毫秒

    墙壁时间:492毫秒

    x=torch.randn(10000,10000).to(“cuda”)
    w=torch.randn(10000,10000)至(“cuda”)
    #确保在开始测量时间之前完成上下文初始化
    torch.cuda.synchronize()
    %时间y=x.mm(w.t());torch.cuda.synchronize()
    
    CPU时间:用户237毫秒,系统231毫秒,总计468毫秒

    墙壁时间:469毫秒

    医生说:

    torch.cuda.synchronize()
    
    等待CUDA设备上所有流中的所有内核完成

    事实上,这告诉Python:停止,等待操作完全完成

    否则,
    %时间将在发出命令后立即返回。

    这将是测试时间的正确方法。注意两次
    torch.cuda.synchronize()
    第一次等待张量在cuda上移动,第二次等待命令在GPU上完成

    import torch
    
    x = torch.randn(10000, 10000).to("cuda")
    w = torch.randn(10000, 10000).to("cuda")
    torch.cuda.synchronize()
    
    %timeit -n 10 y = x.matmul(w.t()); torch.cuda.synchronize() #10 loops, best of 3: 531 ms per loop
    

    我也想过,但是
    ac
    bc
    应该是随机的。这在某种程度上仍然有效吗?我只是尝试了一下,
    empty\u cache(…)
    在这种情况下没有效果。只释放未使用的缓存内存,因此您可能希望滑入
    delac;德尔bc;在
    清空\u缓存之前删除cc
    。也可能是pytorch从GPU请求更多内存,因此您可能希望在操作前后进行监视。@a_guest我还尝试了
    del
    变量,但仍然是相同的计时。。。这不是我的问题,但我对为什么会这样感兴趣happens@a_guest是的,如果没有同步(…)
    ,则计时不可靠。我以社区维基的形式发布了一个答案,因为它基本上来自于讨论PyTorch线程。在Google Colab上尝试了这个代码,看起来大约
    400 ms
    是一个合理的持续时间。我认为这是正确的答案。@Iyunb事实上,我在答案上发布的测量值来自Google Colab:)顺便说一句,答案是一个社区wiki,因为它基本上来自与另一个用户(一位访客)进行了一次小讨论后的讨论PyTorch线程关于另一个答案的评论。CUDA最佳实践指南的这一部分可能与此相关:它明确解释了异步调用的问题以及可能需要的同步化。进行矩阵乘法的明显方法是O(N^3),但是否有一种更快的方法,可能是O(N^2*log(N))在O(N^(2*log(N)))中没有已知的方法来实现这一点。从理论上讲,有一些方法可以更快地实现这一点,但在实践中,它们是不可用的,除了一种方法,它取N**(log(7)/log(2)),约为N**2.81,但由于大常数和数值稳定性问题,甚至没有使用它。谢谢。这可能是我记错的。