第83章 搞纯数的这么逆天吗?(爆梗1.5w 2/3求首订)(2 / 5)
“不对啊,你这是打算自己写整个训练框架的cuda底层核函数?
陈工惊讶地说:“这个东西真的不好写,並行编程的难度和我们平时写的c根本就不是一个级別的!”
“普通c代码如果写错了,编译器会直接给你报错,或者运行时给你拋出一个指针异常,你很容易就能定位到,但是cuda编程它跑在gpu那成百上千个线程上的,你很难发现异常出在哪里!”
曾工也在旁边补充:“在cuda里,你的逻辑要是写错了,或者线程索引算歪了,它不会崩溃,也不会报错,编译器还会显示编译成功,然后显卡也会老老实实地跑完。”
“结果呢?它只会给你吐出一堆nan,你想在几万个同时运行的线程里排查出是哪一个线程的哪个寄存器出了问题,那简直是盲人摸象,在里面找不出根源是常有的事,简直是伤不起!”
陈工嘆了口气,劝道:“漆昊,听我一句劝,咱们没必要在这里去浪费时间,写这个的工程门槛太高了,你要做什么,跟我们说,我们一起想办法。”
漆昊不是个轻易服输的人。
更何况,在没有拿到结果之前,他把自己的想法说出来,这两人也只会固守原来的技术路线不会愿意尝试新的。
想要改变根深蒂固的思维,那就只能拿出实际成果出来才行。
直觉告诉他,如果真把他的想法走通了,完成系统任务非常容易!
漆昊笑了笑:“陈工,曾工,谢谢你们提醒,不过既然硬体都买回来了,不试试怎么知道呢?反正现在是春节假期的尾巴,我也没什么別的事,就当是活动活动脑子了。”
见漆昊態度坚决,陈工和曾工对视了一眼,也不再劝阻,只是默默地坐在旁边看著。
漆昊不信邪地开始行动了。
卷积前向传播的公式,偏导数的链式法则这些复杂的数学公式,他可以在脑海中快速拆解。
然而,当他真正將这些数学公式转化为cuda上的代码时,缺乏系统性大规模gpu编程经验的硬伤,瞬间暴露无遗。
他开始不可避免地遇到了各种棘手的难点。
比如显存合併访问的问题。
gpu的线程是以32个为一组进行硬体调度的,如果这32个线程在执行卷积计算时,访问的全局显存地址不是连续的,那么原本一次访存操作就能搞定的数据读取,会被硬体拆分成大量高延迟的访存请求,整个速度直接下跌!
漆昊试著写了第一版lrn核函数,却发现因为图像通道和像素索引的交错,线程束的访存完全错开,调试窗口里的显存带宽利用率低得惨不忍睹,gpu算力被卡在了带宽瓶颈上。
接著更让人头疼的是,在反向传播更新权重时,因为不同的图像区域,不同的batch
样本都在並行计算,当多个线程同时计算完各自的局部偏导数,准备將结果累加到同一个全局显存位置时,就会发生灾难性的写入衝突!
如果使用互斥锁,gpu会瞬间退化为单线程,如果直接使用当时fermi架构上效率並不高的atomicadd,一旦发生高频地址碰撞,线程排队等待的延迟会影响整张卡。
呵呵,又卡死了。
漆昊心塞。
这小玩意跟数学比,一点都不可爱。
看著屏幕上那因为显存衝突和同步问题而不断陷入死锁的测试日誌,漆昊的手指在键盘上停了下来,眉头微微锁起。
他確实低估了现代高性能计算机体系结构在这种细节上的残酷性,数学公式是完美的对称,可晶片不讲道理啊,一不留神就罢工了。
陈工和曾工在旁边默默看著漆昊不断重构代码,又不断地看著测试结果显示异常。
两位资深的工程技术人员轻轻摇了摇头,起身走到实验室的饮水机旁。
曾工接了一杯水,低声对陈工说道:“老陈,看到没?我就说吧。” ↑返回顶部↑
陈工惊讶地说:“这个东西真的不好写,並行编程的难度和我们平时写的c根本就不是一个级別的!”
“普通c代码如果写错了,编译器会直接给你报错,或者运行时给你拋出一个指针异常,你很容易就能定位到,但是cuda编程它跑在gpu那成百上千个线程上的,你很难发现异常出在哪里!”
曾工也在旁边补充:“在cuda里,你的逻辑要是写错了,或者线程索引算歪了,它不会崩溃,也不会报错,编译器还会显示编译成功,然后显卡也会老老实实地跑完。”
“结果呢?它只会给你吐出一堆nan,你想在几万个同时运行的线程里排查出是哪一个线程的哪个寄存器出了问题,那简直是盲人摸象,在里面找不出根源是常有的事,简直是伤不起!”
陈工嘆了口气,劝道:“漆昊,听我一句劝,咱们没必要在这里去浪费时间,写这个的工程门槛太高了,你要做什么,跟我们说,我们一起想办法。”
漆昊不是个轻易服输的人。
更何况,在没有拿到结果之前,他把自己的想法说出来,这两人也只会固守原来的技术路线不会愿意尝试新的。
想要改变根深蒂固的思维,那就只能拿出实际成果出来才行。
直觉告诉他,如果真把他的想法走通了,完成系统任务非常容易!
漆昊笑了笑:“陈工,曾工,谢谢你们提醒,不过既然硬体都买回来了,不试试怎么知道呢?反正现在是春节假期的尾巴,我也没什么別的事,就当是活动活动脑子了。”
见漆昊態度坚决,陈工和曾工对视了一眼,也不再劝阻,只是默默地坐在旁边看著。
漆昊不信邪地开始行动了。
卷积前向传播的公式,偏导数的链式法则这些复杂的数学公式,他可以在脑海中快速拆解。
然而,当他真正將这些数学公式转化为cuda上的代码时,缺乏系统性大规模gpu编程经验的硬伤,瞬间暴露无遗。
他开始不可避免地遇到了各种棘手的难点。
比如显存合併访问的问题。
gpu的线程是以32个为一组进行硬体调度的,如果这32个线程在执行卷积计算时,访问的全局显存地址不是连续的,那么原本一次访存操作就能搞定的数据读取,会被硬体拆分成大量高延迟的访存请求,整个速度直接下跌!
漆昊试著写了第一版lrn核函数,却发现因为图像通道和像素索引的交错,线程束的访存完全错开,调试窗口里的显存带宽利用率低得惨不忍睹,gpu算力被卡在了带宽瓶颈上。
接著更让人头疼的是,在反向传播更新权重时,因为不同的图像区域,不同的batch
样本都在並行计算,当多个线程同时计算完各自的局部偏导数,准备將结果累加到同一个全局显存位置时,就会发生灾难性的写入衝突!
如果使用互斥锁,gpu会瞬间退化为单线程,如果直接使用当时fermi架构上效率並不高的atomicadd,一旦发生高频地址碰撞,线程排队等待的延迟会影响整张卡。
呵呵,又卡死了。
漆昊心塞。
这小玩意跟数学比,一点都不可爱。
看著屏幕上那因为显存衝突和同步问题而不断陷入死锁的测试日誌,漆昊的手指在键盘上停了下来,眉头微微锁起。
他確实低估了现代高性能计算机体系结构在这种细节上的残酷性,数学公式是完美的对称,可晶片不讲道理啊,一不留神就罢工了。
陈工和曾工在旁边默默看著漆昊不断重构代码,又不断地看著测试结果显示异常。
两位资深的工程技术人员轻轻摇了摇头,起身走到实验室的饮水机旁。
曾工接了一杯水,低声对陈工说道:“老陈,看到没?我就说吧。” ↑返回顶部↑