zoukankan      html  css  js  c++  java
  • 为什么使用服务器CPU运算Tensorflow、Pytorch代码会导致近百个逻辑核心的CPU使用率高达100%呢

    可能现在搞机器学习的人如果使用过服务器(Intel Xeon系列CPU)都会遇到过这样的一个问题,就是使用普通的家用电脑(Intel i7 之类的)跑Tensorflow 、Pytorch代码虽然只有8物理核心或者10物理核心的CPU来跑代码,其CPU使用率都不一定会达到100%,然而我们使用服务器(Xeon CPU)跑同样的代码,几十个物理核心的CPU其使用率立刻升高到100%,就这造成了十分要人迷惑的现象。

    大致的总结以下这个现象就是:

    同样的Tensorflow、PyTorch代码使用家用10核心左右的CPU其使用率为百分之几十,但是如果使用服务器(Xeon 系统)100核心左右的CPU其使用率不但没有降低反而升高甚至可能达到100%。

    其实这个问题我一开始也没有想明白,按道理来说CPU资源更多了同样的代码跑起来其使用率应该会下降而不是上升,而这一下是大幅度上升甚至飙到了接近100%。后来分析了一下Tensorflow和Pytorch的代码的计算任务类别和CPU的指令集就发现原因所在了。

    首先,我们需要知道 Tensorflow、Pytorch运行的代码一般都是矢量计算或是叫向量计算。

    其次,我们需要知道 服务器CPU向量计算一般使用 avx-512 什么的,而家用CPU进行向量计算一般都是用AVX2指令集。换句话就是说家用电脑做向量计算性能较低,由于指令集不支持所以CPU使用率上不去,但是服务器cpu对向量计算支持较好,一旦用服务器CPU进行向量计算其性能会有大幅度提升,而且会充分利用CPU的资源,因此使用服务器CPU进行同样的向量计算其使用率不仅没有降低反而会有大幅度的提升,甚至会达到100%的可能利用率,当然伴随着服务器CPU使用率的高数值,整体的计算时间也会得到大幅缩短。

    具体例子:linux ,  top命令后

    CPU: xeon GOLD版本

    上面的是服务器上运行的两个程序,都是pytorch的代码。

    服务器90个核心,单cpu使用率为  4797,其整体CPU利用率为4797/9000约等于50%,单cpu使用率为  100,其整体CPU利用率为100/9000约等于1%。

    其中,第一个程序跑的是一个三层的CNN网络,网络训练使用的是CPU,此时为使用CPU进行矢量计算。

    第二个程序跑的是一个五层的CNN网络,网络训练使用的是GPU,此时为使用GPU进行矢量计算,CPU仅进行标量计算。

    由此可以看到即使使用服务器CPU进行一个计算量不太大的向量计算就可以完全使用掉45个左右的逻辑CPU,而此时一个只进行标量计算的任务其CPU使用率最多消耗掉一个CPU核心。

    再举一个例子:

    代码:

    import ctypes
    import time
    import multiprocessing
    import numpy as np
    
    #NUM_PROCESS = multiprocessing.cpu_count()
    NUM_PROCESS = 4
    
    size = 1000000
    
    
    def worker(index):
        main_nparray = np.frombuffer(shared_array_base[index], dtype=ctypes.c_double)
        for i in range(10000):
            main_nparray[:] = index + i
        return index
    
    
    if __name__ == "__main__":
        shared_array_base = []
        for _ in range(NUM_PROCESS):
            shared_array_base.append(multiprocessing.Array("d", size, lock=False))
    
        pool = multiprocessing.Pool(processes=NUM_PROCESS)
    
        a = time.time()
        result = pool.map(worker, range(NUM_PROCESS))
        b = time.time()
        print(b-a)
        #print(result)
    
    
        for i in range(NUM_PROCESS):
            main_nparray = np.frombuffer(shared_array_base[i], dtype=ctypes.c_double)
            print(main_nparray)
            print(type(main_nparray))
            print(main_nparray.shape)

    代码为使用4个核心(4个进程)进行多进程向量计算。

    使用家用i7 主频4.6Ghz的CPU,运行时间:

    16.208305835723877 秒

    使用服务器 Xeon 系列   2.3 Ghz的CPU ,运行时间:

    4.703573226928711   秒

    可以看到即使是服务器CPU主频为家用CPU的一半,而且都是使用相同物理核心的个数,最后服务器进行向量计算的时间不仅比家用CPU的快甚至还快了3倍速度左右。

    看来使用服务器CPU进行向量计算即使主频低最终性能也完全碾压家用CPU,当然如果是进行标量计算的话这时就要看主频了,如果进行标量计算那么家用CPU将会比服务器CPU快不到一倍,因为此时看的主要是主频大小了。

    虽然使用服务器CPU进行向量计算可以大幅度提高计算效率,但是我们需要知道以下几个问题:

    1.   使用服务器CPU(如果不是天河超算,太湖之光什么的,不是那种非一致内存访问的服务器架构,而仅仅是那种一个服务器主板上安装两个Xeon版本CPU的话),你所能利用的向量计算的CPU计算资源的上限比较低,换句话说就是你一个几十万的服务器你要是用CPU跑两个三层网络的CNN基本可以保证服务器使用率达到100%,此时服务器上如果用人用GPU进行计算,那GPU的使用率会从100%掉到5%以内,其原因就是CPU被占满没有计算资源给GPU计算做调度了。

    也就是说如果你不是使用什么太湖之光,华为昇腾这种非一致内存访问的服务器架构,你只需要跑一些简单的向量计算代码整个服务器就不能做别的了,就像我现在负责管理的GPU计算服务器,经常需要看看有没有人一下子偷偷的把CPU全部吃掉,毕竟随便找个向量计算的代码就轻松把几十万的服务器CPU全部吃掉,此时你就是有16个泰坦GPU在计算都得歇菜,因为你CPU已经没有计算能力了。

    当然,如果你是独占使用服务器,那另一说。

    2.   由于像Xeon这种CPU的向量计算上限比较低,如果你是做机器学习中的感知学习,那么你用CPU计算并不会给你提升太多速度(假设你服务器上同时还有泰坦显卡的情况),这个时候完全可以用GPU计算,因为如果矢量计算量大过某一值后GPU的向量计算能力是要高于CPU的,毕竟GPU的向量计算核心都是几千上万个,Xeon的CPU再好毕竟向量计算核心也就百十个。

    当然,如果你要是做决策学习的话,而且是那种在线的(online reinforcement learning), 那么使用CPU进行向量计算是要快于GPU的,因为此时向量计算的量正好是CPU快于GPU的时候(一般决策学习,reinforcement learning的向量计算不太大,一般三层CNN就差不多了),而且如果是online的,需要实时与CPU的仿真环境交互的话,那么使用CPU进行决策学习确实要比GPU快,当然这也是一直我想要解决的问题,就是如何使GPU进行决策学习的性能高于CPU呢?这是我的一个想解决的问题。但是即使使用CPU进行决策学习要快于GPU但是对服务器整体CPU使用率的大幅度占用还是很有可能影响其他人使用的,这也是我们需要注意的一个问题,比较第一个问题中我们也说明了使用CPU进行向量计算会大幅度占用CPU的整体计算资源。

    =====================================================

    本博客是博主个人学习时的一些记录,不保证是为原创,个别文章加入了转载的源地址还有个别文章是汇总网上多份资料所成,在这之中也必有疏漏未加标注者,如有侵权请与博主联系。
  • 相关阅读:
    Java基础学习篇---------static
    Java基础学习篇---------this、object的学习
    Java基础学习篇---------String、集合的学习
    Java基础学习篇---------多态
    Java基础学习篇---------继承
    Java基础学习篇---------封装
    Java基础学习篇---------多线程
    Handler主线程和子线程相通信
    Handler的使用
    c# DataGridView操作
  • 原文地址:https://www.cnblogs.com/devilmaycry812839668/p/15136260.html
Copyright © 2011-2022 走看看