在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

移動端arm cpu優(yōu)化學習筆記(一)一步步優(yōu)化盒子濾波

電子設計 ? 來源:電子設計 ? 作者:電子設計 ? 2020-12-10 20:23 ? 次閱讀
盒子濾波算是很基礎和經典的函數,但是在PC上實現的話因為有GPU,借助其強大的算力所以可以很暴力的實現,每個thread計算以某點為中心給定半徑下的區(qū)域大小的和即可。那如果在移動端cpu上如何寫高效的盒子濾波操作呢?
作者:梁德澎

最近一段時間做比較多移動端開發(fā)相關的工作,感覺移動端優(yōu)化相關的對我來說挺有趣的,以前都是在PC上寫代碼,寫代碼的時候對于代碼的性能沒有過多的思考和感覺。但是在移動端上寫代碼明顯能察覺到一段代碼寫的好不好,對于在移動端上運行性能有很大的影響,尤其在一些比較老舊的機型上測試更能有感覺。

然后最近剛好在復現一篇論文,要在MXNet中實現類似盒子濾波(box filter)的操作子,其實就是步長為1的sum pooling,盒子濾波算是很基礎和經典的函數,但是在PC上實現的話因為有GPU,借助其強大的算力所以可以很暴力的實現,每個thread計算以某點為中心給定半徑下的區(qū)域大小的和即可。然后突發(fā)奇想想試試在移動端cpu上試試如何寫高效的盒子濾波操作。

這篇文章就是把我的實踐過程記錄下來,首先給出最簡單的實現然后如何一步步優(yōu)化,到最后給出一個性能優(yōu)化還不錯的版本。由于我正式接觸移動端優(yōu)化的時間不長,很多東西理解的不深,所以有哪里論述不正確的地方請讀者指出。

本文的代碼:
https://github.com/Ldpe2G/ArmNeonOptimization/tree/master/boxFilter

1.首先來看下Boxfilter最簡單最直觀的實現

void BoxFilter::filter(float *input, int radius, int height, int width, float *output) {
  for (int h = 0; h < height; ++h) {
    int height_sift = h * width;
    for (int w = 0; w < width; ++w) {
      int start_h = std::max(0, h - radius);
      int end_h = std::min(height - 1, h + radius);
      int start_w = std::max(0, w - radius);
      int end_w = std::min(width - 1, w + radius);

      float tmp = 0;
      for (int sh = start_h; sh <= end_h; ++sh) {
        for (int sw = start_w; sw <= end_w; ++ sw) {
          tmp += input[sh * width + sw];
        }
      }
      output[height_sift + w] = tmp;
    }
  }
}

對每個點,計算給定半徑下區(qū)域的和,需要注意下邊界的處理。

其時間復雜度是 O( height x width x (radius x 2 + 1) x (radius x 2 + 1) ),

這個最簡單的實現在輸入大小固定的情況下,半徑越大耗時越大,有很多重復計算的地方,相鄰元素在計算各自區(qū)域內和的時候其實是有重疊的。然后第一個優(yōu)化的思路就是boxfilter的計算是行列可分離的,具體可參考[4]。

2.Boxfilter優(yōu)化第一版

void BoxFilter::fastFilter(float *input, int radius, int height, int width, float *output) {
  float *cachePtr = &(cache[0]);
  // sum horizonal
  for (int h = 0; h < height; ++h) {
    int sift = h * width;
    for (int w = 0; w < width; ++w) {
      int start_w = std::max(0, w - radius);
      int end_w = std::min(width - 1, w + radius);

      float tmp = 0;
      for (int sw = start_w; sw <= end_w; ++ sw) {
        tmp += input[sift + sw];
      }

      cachePtr[sift + w] = tmp;
    }
  }

  // sum vertical
  for (int h = 0; h < height; ++h) {
    int shift = h * width;
    int start_h = std::max(0, h - radius);
    int end_h = std::min(height - 1, h + radius);

    for (int sh = start_h; sh <= end_h; ++sh) {
      int out_shift = sh * width;
      for (int w = 0; w < width; ++w) {
        output[out_shift + w] += cachePtr[shift + w];
      }
    }
  }
}

所謂行列可分離就是,把行列分開計算,從代碼里可以看到,對每個元素,首先計算行方向上半徑內的和,然后再計算列半徑內的和,所以這時候的時間復雜度是O(height x width x (radius x 2 + 1) x 2)。

可以看到行列分離之后,時間復雜度減少了不少,尤其半徑越大減少的越多,但是還是有重復計算的地方。而且在固定輸入下時間復雜度還是會隨半徑的變大而變大。那么有沒有方法可以使得計算復雜度不受半徑的影響呢?優(yōu)化思路就是比如在算某一行每個點的半徑區(qū)域內的和時,對于行開頭第一個點,首先計算其半徑內和,然后對于接下來的點,不需要重新計算其半徑區(qū)域內和,而是只需要把前一個元素半徑內的和,按半徑窗口偏移之后減去舊的點和加上新加入的點即可。

3.Boxfilter優(yōu)化第二版

void BoxFilter::fastFilterV2(float *input, int radius, int height, int width, float *output) {
  float *cachePtr = &(cache[0]);
  // sum horizonal
  for (int h = 0; h < height; ++h) {
    int shift = h * width;

    float tmp = 0;
    for (int w = 0; w < radius; ++w) {
      tmp += input[shift + w];
    }

    for (int w = 0; w <= radius; ++w) {
      tmp += input[shift + w + radius];
      cachePtr[shift + w] = tmp;
    }

    int start = radius + 1;
    int end = width - 1 - radius;
    for (int w = start; w <= end; ++w) {
      tmp += input[shift + w + radius];
      tmp -= input[shift + w - radius - 1];
      cachePtr[shift + w] = tmp;
    }

    start = width - radius;
    for (int w = start; w < width; ++w) {
      tmp -= input[shift + w - radius - 1];
      cachePtr[shift + w] = tmp;
    }
  }

  float *colSumPtr = &(colSum[0]);
  for (int indexW = 0; indexW < width; ++indexW) {
    colSumPtr[indexW] = 0;
  } 
  // sum vertical
  for (int h = 0; h < radius; ++h) {
    int shift = h * width;
    for (int w = 0; w < width; ++w) {
      colSumPtr[w] += cachePtr[shift + w];
    }
  }

  for (int h = 0; h <= radius; ++h) {
    float *addPtr = cachePtr + (h + radius) * width;
    int shift = h * width;
    float *outPtr = output + shift; 
    for (int w = 0; w < width; ++w) {
      colSumPtr[w] += addPtr[w];
      outPtr[w] = colSumPtr[w];
    }
  }

  int start = radius + 1;
  int end = height - 1 - radius;
  for (int h = start; h <= end; ++h) {
    float *addPtr = cachePtr + (h + radius) * width;
    float *subPtr = cachePtr + (h - radius - 1) * width;
    int shift = h * width;
    float *outPtr = output + shift;
    for (int w = 0; w < width; ++w) {
      colSumPtr[w] += addPtr[w];
      colSumPtr[w] -= subPtr[w];
      outPtr[w] = colSumPtr[w];
    }
  }

  start = height - radius;
  for (int h = start; h < height; ++h) {
    float *subPtr = cachePtr + (h - radius - 1) * width;
    int shift = h * width;
    float *outPtr = output + shift; 
    for (int w = 0; w < width; ++w) {
      colSumPtr[w] -= subPtr[w];
      outPtr[w] = colSumPtr[w];
    }
  }
}

這一版時間復雜度大概是O(height x width x 4 )。不算邊界只看中間部分的計算就是一次加法和一次減法,行方向和列方向都一樣。這里行方向的部分很好理解,因為邊界部分需要特殊處理,比如開始部分只有加,結尾部分只有減法,所以計算分成了3部分。列方向計算的話按照常規(guī)思路,那就是按一列列來處理,可是我們知道數據一般是按照行來存儲的,這樣子跳行取數據,會造成很多次cache miss,這樣子性能肯定會受很大的影響,所以這里用了一個大小是width的向量colSum,來存儲每一列對應點的半徑區(qū)域內的和,然后遍歷的時候還是按照行來遍歷,如果一下子理解不了這個思路的話,可以想象如果width為1的情況,那么應該可以更好的理解。

然后我們來看下實驗結果,這三版boxfilter在輸入是2000x2000的情況下,在不同半徑下的運行耗時,測試手機是華為榮耀4C(CHM-TL00),每個函數運行10次取平均為其耗時:

可以看到第二版優(yōu)化的耗時在不同半徑下的表現都很穩(wěn)定,基本不受影響。然后接下來的優(yōu)化思路就是在確定了C++ 的代碼之后可以采用arm Neon Intrinsics來加速了,就是利用向量計算指令同時處理多個數據,把獨立的運算同時做,比寫匯編要容易。

4.Boxfilter優(yōu)化第二版 Neon Intrinsics

int n = width >> 2;
  int re = width - (n << 2);

  int start = radius + 1;
  int end = height - 1 - radius;
  for (int h = start; h <= end; ++h) {
    float *addPtr = cachePtr + (h + radius) * width;
    float *subPtr = cachePtr + (h - radius - 1) * width;
    int shift = h * width;
    float *outPtr = output + shift; 
    int indexW = 0;
    float *tmpOutPtr = outPtr;
    float *tmpColSumPtr = colSumPtr;
    float *tmpAddPtr = addPtr;
    float *tmpSubPtr = subPtr;

    int nn = n;
    int remain = re;
#if __ARM_NEON
    for (; nn > 0; nn--) {
      float32x4_t _add = vld1q_f32(tmpAddPtr);
      float32x4_t _sub = vld1q_f32(tmpSubPtr);
      float32x4_t _colSum = vld1q_f32(tmpColSumPtr);

      float32x4_t _tmp = vaddq_f32(_colSum, _add);
      _tmp = vsubq_f32(_tmp, _sub);

      vst1q_f32(tmpColSumPtr, _tmp);
      vst1q_f32(tmpOutPtr, _tmp);

      tmpAddPtr += 4;
      tmpSubPtr += 4;
      tmpColSumPtr += 4;
      tmpOutPtr += 4;
    }
#endif // __ARM_NEON
    for (; remain > 0; --remain) {
      *tmpColSumPtr += *tmpAddPtr;
      *tmpColSumPtr -= *tmpSubPtr;
      *tmpOutPtr = *tmpColSumPtr;
      tmpAddPtr ++;
      tmpColSumPtr ++;
      tmpOutPtr ++;
      tmpSubPtr ++;
    }
  }

上面的代碼是截取列方向中間計算部分來展示如何使用arm Neon Intrinsics函數,完整代碼可以看
https://github.com/Ldpe2G/ArmNeonOptimization/blob/master/boxFilter/src/boxFilter.cpp#L143
行方向是沒辦法并行的,因為相鄰元素有依賴。而列方向上則可以,所以在列方向上做neon加速。
以上代碼其實挺好理解的,vld1q/_f32指令就是加載4個浮點數,然后vaddq/_f32,為把兩個float32x4/_t向量相加,相當于同時計算了4個輸出,然后再把結果用vst1q/_f32存回去對應的地址,然后所有參與運算的地址都是每次加4,具體可以參考官網文檔

然后來看下這版優(yōu)化的耗時如何:

可以看到耗時又少了一點,但是收益已經不大了。然后還想嘗試進一步優(yōu)化把Intrinsics部分改寫成內聯匯編試試。

5.Boxfilter優(yōu)化第二版 Neon Assembly

int n = width >> 2;
  int re = width - (n << 2);

  int start = radius + 1;
  int end = height - 1 - radius;
  for (int h = start; h <= end; ++h) {
    float *addPtr = cachePtr + (h + radius) * width;
    float *subPtr = cachePtr + (h - radius - 1) * width;
    int shift = h * width;
    float *outPtr = output + shift; 
    int indexW = 0;
    float *tmpOutPtr = outPtr;
    float *tmpColSumPtr = colSumPtr;
    float *tmpAddPtr = addPtr;
    float *tmpSubPtr = subPtr;

    int nn = n;
    int remain = re;
#if __ARM_NEON
    asm volatile(
      "0:                       /n"
      "vld1.s32 {d0-d1}, [%0]!  /n"
      "vld1.s32 {d2-d3}, [%1]!  /n"
      "vld1.s32 {d4-d5}, [%2]   /n"
      "vadd.f32 q4, q0, q2      /n"
      "vsub.f32 q3, q4, q1      /n"
      "vst1.s32 {d6-d7}, [%3]!  /n"
      "vst1.s32 {d6-d7}, [%2]!  /n"
      "subs %4, #1              /n"
      "bne  0b                  /n"
      : "=r"(tmpAddPtr), //
      "=r"(tmpSubPtr),
      "=r"(tmpColSumPtr),
      "=r"(tmpOutPtr),
      "=r"(nn)
      : "0"(tmpAddPtr),
      "1"(tmpSubPtr),
      "2"(tmpColSumPtr),
      "3"(tmpOutPtr),
      "4"(nn)
      : "cc", "memory", "q0", "q1", "q2", "q3", "q4"
    );

#endif // __ARM_NEON
    for (; remain > 0; --remain) {
      *tmpColSumPtr += *tmpAddPtr;
      *tmpColSumPtr -= *tmpSubPtr;
      *tmpOutPtr = *tmpColSumPtr;
      tmpAddPtr ++;
      tmpColSumPtr ++;
      tmpOutPtr ++;
      tmpSubPtr ++;
    }
  }

完整版代碼:https://github.com/Ldpe2G/ArmNeonOptimization/blob/master/boxFilter/src/boxFilter.cpp#L331

這里我只對列計算中間部分做了改寫,neon匯編下面的"cc","memory"之后跟的寄存器,是為了告訴編譯器(主要是q開頭的,q和d是一樣的,q表示128位向量寄存器(16個),d表示64位(32個),q0 =(d0 + d1)),這些寄存器會在匯編內被用到,然后編譯器在進入這段代碼之前,要緩存這些寄存器的內容,然后在離開這段匯編之后恢復原來的值。一定要記得寫上用了哪些向量寄存器。

簡單解釋一下,指令的意思,"vld1.s32 {d0-d1}, [%0]! /n",相當等于從tmpAddPtr這個地址連續(xù)讀取4個浮點數到{d0-d1}也就是q0寄存器,浮點數每個32位,乘以四就是128位。最后的感嘆號表示,這個指令完成之后tmpAddPtr地址加4的意思,沒有就是不變。"vadd.f32 q4, q0, q2 /n" 就是把 q0和q2相加的結果放到q4,"vsub.f32 q3, q4, q1 /n" 就是把q4減去q1的結果放到q3,和上面的intrinsics指令對應。
然后vst1.s32就是把寄存器的內容存到tmpOutPtr和tmpColSumPtr地址指向的內存。
最后的subs指令和bne相當于for循環(huán)的功能,最后對nn減一然后bne判斷是否為0, 不為0則繼續(xù)循環(huán)跳到開頭0標記出繼續(xù)執(zhí)行。

匯編指令其實和intrinsics函數有對應的具體可參考官方文檔。

然后我們來看下耗時:

什么鬼,竟然還慢了,一定是我使用的方式不對。去查了下資料,看到這篇博客里面提到,指令vld和vst都是需要消耗兩個時鐘周期,其他指令基本都是一個時鐘周期,但是卻不意味著一個時鐘周期之后能立刻得到結果。那么看下來 vsub.f32 指令依賴 vadd.f32 的結果,所以白白浪費了不少時鐘周期。而且現代的處理器支持雙發(fā)射流水線,也就意味著CPU可以同時拾取兩條數據無關指令,那么能否利用這點來更進一步加速呢。

6.Boxfilter優(yōu)化第二版 Neon Assembly 第二版

int start = radius + 1;
  int end = height - 1 - radius;
  for (int h = start; h <= end; ++h) {
    float *addPtr = cachePtr + (h + radius) * width;
    float *subPtr = cachePtr + (h - radius - 1) * width;
    int shift = h * width;
    float *outPtr = output + shift; 
    int indexW = 0;
    float *tmpOutPtr = outPtr;
    float *tmpColSumPtr = colSumPtr;
    float *tmpAddPtr = addPtr;
    float *tmpSubPtr = subPtr;

    int nn = width >> 3;
    int remain = width - (nn << 3);
#if __ARM_NEON
    asm volatile(
      "0:                       /n"
      "pld      [%0, #256]      /n"
      "vld1.s32 {d0-d3}, [%0]!  /n"
      "pld      [%2, #256]      /n"
      "vld1.s32 {d8-d11}, [%2]  /n"

      "vadd.f32 q6, q0, q4      /n"

      "pld      [%1, #256]      /n"
      "vld1.s32 {d4-d7}, [%1]!  /n"

      "vadd.f32 q7, q1, q5      /n"

      "vsub.f32 q6, q6, q2      /n"

      "vsub.f32 q7, q7, q3      /n"

      "vst1.s32 {d12-d15}, [%3]!  /n"

      // 感謝 @隨風漂 指出這里錯誤,用錯了寄存器,輸出結果是錯的
      // "vst1.s32 {d16-d19}, [%2]!  /n" 

      "vst1.s32 {d12-d15}, [%2]!  /n"

      "subs %4, #1              /n"
      "bne  0b                  /n"
      : "=r"(tmpAddPtr), //
      "=r"(tmpSubPtr),
      "=r"(tmpColSumPtr),
      "=r"(tmpOutPtr),
      "=r"(nn)
      : "0"(tmpAddPtr),
      "1"(tmpSubPtr),
      "2"(tmpColSumPtr),
      "3"(tmpOutPtr),
      "4"(nn)
      : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9"
    );

#endif // __ARM_NEON
    for (; remain > 0; --remain) {
      *tmpColSumPtr += *tmpAddPtr;
      *tmpColSumPtr -= *tmpSubPtr;
      *tmpOutPtr = *tmpColSumPtr;
      tmpAddPtr ++;
      tmpColSumPtr ++;
      tmpOutPtr ++;
      tmpSubPtr ++;
    }
  }

完整版代碼:https://github.com/Ldpe2G/ArmNeonOptimization/blob/master/boxFilter/src/boxFilter.cpp#L527

可以看到這里的改進思路就是,把兩條 vadd.f32 指令放一起,然后跟兩條vsub.f32,然后把加載 vsub.f32 要用到部分數據指令 vld1.s32 放到兩個 vadd.f32之間,同時 vld1.s32 指令之前加上 pld 指令。這個指令為什么能加速我問了下做移動端優(yōu)化的同事,pld把數據從內存加載到cache然后下一條指令把數據從 cache加載到寄存器,如果不用pld,數據若不在cache中,那么就是需要直接從內存加載到寄存器,這里會比前者慢很多。

然后我們來看下最終版的耗時:

看表格最終版的耗時比起最原始的實現至少可以加速6~7倍,肯定是還有更好的優(yōu)化方式,比如如果能對輸入做量化把float類型數據轉成8bit整型,那么就可以在單位時間處理更多數據,當然量化到8bit上計算溢出的風險也會增大許多。有時候煉丹煉久了,學習下優(yōu)化也挺好玩的,感覺可以很好的鍛煉下思維和代碼能力,現在深度學習在移動端應用越來越廣泛,訓出來的模型如果部署到移動端之后運行的效率很低那么也是白費功夫。所以感覺對移動端優(yōu)化有一定的了解對于如何設計對移動端更友好的模型還是有幫助的。

更多AI移動端優(yōu)化的請關注專欄嵌入式AI以及知乎(@梁德澎)。

審核編輯 黃昊宇
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    9200

    瀏覽量

    370442
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10934

    瀏覽量

    213613
  • 人工智能
    +關注

    關注

    1799

    文章

    47989

    瀏覽量

    241565
收藏 人收藏

    評論

    相關推薦

    Arm KleidiCV與OpenCV集成助力移動計算機視覺性能優(yōu)化

    等多種應用中。然而,這些計算機視覺應用可能很難實現最優(yōu)化的延遲性能和處理速度,特別是在內存大小、電池容量和處理能力有限的移動設備上難度更高。 而 Arm KleidiCV 便能在其中大顯身手。該開源庫利用了最新
    的頭像 發(fā)表于 02-24 10:15 ?228次閱讀

    FRED應用:LED發(fā)光顏色優(yōu)化

    。第四個無光線追跡面用于優(yōu)化后的顏色對比。 優(yōu)化變量 優(yōu)化的第一步涉及到變量的定義,本例中,優(yōu)化3個LED光源的光功率。因為沒有對應的光源
    發(fā)表于 01-17 09:39

    如果需要將DDC112U設置為非連續(xù)模式工作,應該如何一步一步正確地設置芯片?

    或狀態(tài)8,如果沒有CONV的切換發(fā)生,是否會直停留在上電時的這個狀態(tài)?如果需要將DDC112U設置為非連續(xù)模式工作,應該如何一步一步正確地設置芯片?
    發(fā)表于 01-09 07:43

    FRED應用:LED發(fā)光顏色優(yōu)化

    。第四個無光線追跡面用于優(yōu)化后的顏色對比。 優(yōu)化變量 優(yōu)化的第一步涉及到變量的定義,本例中,優(yōu)化3個LED光源的光功率。因為沒有對應的光源
    發(fā)表于 01-07 08:51

    沙子變芯片,一步步帶你走進高科技的微觀世界

    在科技飛速發(fā)展的今天,芯片作為現代科技的核心元器件,其制造過程復雜且充滿挑戰(zhàn)。芯片不僅推動了信息技術、人工智能、物聯網等領域的進步,還成為衡量個國家科技實力的重要指標。然而,芯片制造并非易事,從沙子到芯片的每一步都充滿了技術、資金和人才的考驗。本文將詳細解析芯片制造的全
    的頭像 發(fā)表于 12-19 10:44 ?414次閱讀
    沙子變芯片,<b class='flag-5'>一步步</b>帶你走進高科技的微觀世界

    FaceTime成詐騙“幫兇”,蘋果是怎么一步步丟掉“安全”光環(huán)的?

    蘋果想要在AI時代,重新給自己貼上“安全”的標簽,恐怕還學學安卓和鴻蒙。
    的頭像 發(fā)表于 11-03 17:39 ?3017次閱讀
    FaceTime成詐騙“幫兇”,蘋果是怎么<b class='flag-5'>一步步</b>丟掉“安全”光環(huán)的?

    通過展頻進一步優(yōu)化EMI

    電子發(fā)燒友網站提供《通過展頻進一步優(yōu)化EMI.pdf》資料免費下載
    發(fā)表于 09-04 09:32 ?1次下載
    通過展頻進<b class='flag-5'>一步</b><b class='flag-5'>優(yōu)化</b>EMI

    優(yōu)化 FPGA HLS 設計

    優(yōu)化時序 下一步是使用名為InTime 的設計探索工具(https://www.plunify.com/en/free-evaluation/)。(同樣,可以自己編寫腳本來嘗試
    發(fā)表于 08-16 19:56

    昂科芯片燒錄高質量出海 唱響越南一步步新技術研討會

    8月8日,迎來了場科技盛事-2024越南一步步新技術研討會在河內·美利亞酒店隆重舉行。作為芯片燒錄領域的領導者,昂科技術應邀參會,吸引了眾多國內外業(yè)界專家和企業(yè)的關注。
    的頭像 發(fā)表于 08-10 09:20 ?932次閱讀

    散熱第一步是導熱

    一步提高產品的使用壽命。 產品型號有多種規(guī)格可選擇(導熱系數1.0~5.0W/m.K)。 合肥傲琪電子的導熱硅脂、導熱硅膠片還應用于對芯片、主板、功率管(MOS)、變壓器、模塊、PCB板、鋁基板
    發(fā)表于 08-06 08:52

    Arm宣布專為移動游戲設計的圖形優(yōu)化方案

    Arm 近期宣布了其專為移動游戲設計的圖形優(yōu)化方案——Arm Accuracy Super Resolution(ASR),旨在顯著提升游戲畫面的視覺品質,同時有效控制智能手機的功耗。
    的頭像 發(fā)表于 07-12 15:58 ?488次閱讀

    一步解讀英偉達 Blackwell 架構、NVlink及GB200 超級芯片

    和縮減協議(SHARP)?引擎,優(yōu)化網絡內縮減和多播加速,進一步提高通信效率。 NVLink Switch 允許 NVLink 連接跨節(jié)點擴展,形成高帶寬、多節(jié)點GPU集群,實際上創(chuàng)建了數據中心級
    發(fā)表于 05-13 17:16

    Cognizant 將延續(xù)與 Pon IT 的合作,旨在進一步管理和優(yōu)化云服務

    得以繼續(xù)為 Pon IT 旗下各家運營公司提供云平臺托管服務。在下階段的合作中,Cognizant 將繼續(xù)實施進一步優(yōu)化措施,旨在使 Pon IT 從
    的頭像 發(fā)表于 03-27 22:49 ?361次閱讀

    stm32做https的server ,serverkeychange運行時間10多s怎么優(yōu)化?

    stm32做https的server ,serverkeychange這一步運行時間10多s,求優(yōu)化辦法
    發(fā)表于 03-27 08:03

    英偉達官宣新代Blackwell架構,把AI擴展到萬億參數

    基于Chiplet與片間互聯技術,800Gb/s RNIC,1.8TB/s NVLink,英偉達正一步步構建出大型AI超算集群?;ヂ撔识xLLM效率,互聯元年正式開啟。
    的頭像 發(fā)表于 03-19 14:22 ?1201次閱讀
    英偉達官宣新<b class='flag-5'>一</b>代Blackwell架構,把AI擴展到萬億參數
    主站蜘蛛池模板: 日本老师xxxxxxxxx79 | 国产精品一久久香蕉产线看 | 奇米影视大全 | 日韩亚洲人成网站在线播放 | 年轻护士3的滋味 | 女人张开腿男人猛桶视频 | 天堂在线观看视频观看www | 国产成人综合日韩精品婷婷九月 | 天天色天天色天天色 | 好大好硬好深好爽视频h | 一区二区三区中文国产亚洲 | 午夜国产福利 | 日本视频一区二区三区 | 三级黄色在线 | 黄网免费看 | 三级视频网站在线观看播放 | 一级毛片一级毛片一级毛片 | 欧美综合影院 | 日本一本在线视频 | 特级做a爰片毛片免费看 | 日韩一级欧美一级一级国产 | 男人天堂综合网 | 日韩欧美一级 | 男男污肉高h坐便器调教 | 综合激情六月 | 午夜影视体验区 | 五月婷婷丁香在线观看 | 色香视频一sxmv首页 | 国产在线97色永久免费视频 | 六月激情 | 色视频综合| 综合五月天堂 | 日韩免费观看的一级毛片 | 欧美不卡在线视频 | 包你爽综合网 | 五月天婷婷亚洲 | 好大好紧好爽好湿润视频 | 寄宿日记免费看 | 高清性欧美xxx | 男生女生靠逼视频 | 四虎在线视频观看 |