在科研中,大多數論文其實還是看精度和效果的,對于速度其實沒有那么高的追求,很多人用速度評價自己演算法的復雜度很低,但實際上這是不準確的,當然在精度占優的情況下,能夠提高速度,給自己的實驗結果增彩,
關于演算法程式的加速,在動手前先要按照如下流程進行思考,以決定從哪里入手加速,
- 演算法優化,指降低演算法計算復雜度,設計新演算法快速求解,比如Hungarian匹配演算法,或犧牲一些記憶體,預計算一些重復計算的程序,減少程式層面的復雜度,
- 語言更換,指將自己演算法遷移到更加底層的演算法,越是低級的演算法,執行速度越快,常見地,將Matlab、Python等解釋性代碼移植到C++平臺,往往有5-20倍的加速效果,
- 演算法并行,指將自己演算法的獨立計算部分,分成幾塊,利用CPU指令集、多核或GPU的特性實作加速,多核并行和CUDA并行最為常見,
- 匯編加速,將自己的一片代碼指定為自己設計的匯編語言,多種C++編譯器實際上也是將語言轉換為匯編代碼,對匯編進行加速在嵌入式中常見,(該方法對平臺有需求,并不常見)
- 硬體加速,利用特殊硬體處理特殊演算法,降低CPU架構的復雜度,常見的就是FPGA,
- 光學加速,利用引數制作特定的光散射模型,輸入目標光源直接得到輸出結果,(離譜的加速方式,目前停留在概念)
強烈注意:
所有的優化,都是在自己演算法流程不變的前提下進行優化,因為優化后的程式,高度面向程序,如果演算法某個流程要換以達到更高精度,則改動作業量較大,
下面我對每種加速方法進行詳細的說明(本文只列舉加速方法,并給出幾種參考示例,并不會詳細講解如何使用,僅介紹思想),
👇加速方法詳解
- 1 演算法優化
- 2 語言更換
- 3 演算法并行
- 3.1 指令集加速
- 3.2 CPU 多核編程
- 3.3 CUDA 編程加速
- 3.4 TensorRT 加速深度學習
- 4 匯編加速
- 5 硬體加速
- 6 光學加速
- 7 總結
1 演算法優化
演算法優化分為兩種型別:① 降低演算法復雜度;② 減少重復計算程序,
- 降低演算法復雜度,在求解最優值時候,我們最容易想到的就是暴力求解,當資料量特別大的時候,這種方法耗時就例外高,在查找、最有匹配中,有大量的優化演算法解決這類問題(圖論、資料結構、演算法導論介紹了很多方法), \newline 例如,匈牙利演算法(Hungarian Algorithm)與KM演算法(Kuhn-Munkres Algorithm)是在多目標跟蹤的論文中見到的兩種演算法,他們都是用來解決多目標跟蹤中的資料關聯問題,匈牙利演算法與KM演算法都是為了求解二分圖的最大匹配問題,下圖就是其中的二分圖,二分圖呢就是能分成兩組,U,V,其中,U上的點不能相互連通,只能連去V中的點,同理,V中的點不能相互連通,只能連去U中的點,這樣,就叫做二分圖,在影像中,可以把二分圖理解為視頻中連續兩幀中的所有檢測框,第一幀所有檢測框的集合稱為U,第二幀所有檢測框的集合稱為V,同一幀的不同檢測框不會為同一個目標,所以不需要互相關聯,相鄰兩幀的檢測框需要相互聯通,最終將相鄰兩幀的檢測框盡量完美地兩兩匹配起來,而求解這個問題的最優解就要用到匈牙利演算法或者KM演算法,
- 減少重復計算程序,這個一般來說具體演算法具體分析,一般要么是記錄共用的中間變數,要么就是把與輸入無關的資料,在初始化變數時候計算好,簡單來說,擬合引數時候,我們經常會用到公式 A x = b Ax=b Ax=b的形式,即 x = ( A ′ A ) ? 1 A ′ b x=(A'A)^{-1}A'b x=(A′A)?1A′b,這時候,定義 A = ( a 1 , a 2 , . . . , a n ) ′ A=(a_1,a_2,...,a_n)' A=(a1?,a2?,...,an?)′,那么 A ′ A = ∑ i = 1 n a 1 T a 1 A'A=\sum_{i=1}^na_1^Ta_1 A′A=∑i=1n?a1T?a1?的形式,如果能預計算 a 1 T a 1 a_1^Ta_1 a1T?a1?的話,每次獲得這個矩陣經過有限次加法即可,
2 語言更換
越是高級的語言,開發效率越高,執行速度越慢,
- 盡量用當前語言的官方庫,官方庫往往對演算法做了足夠的加速,
- 將部分簡單函式編譯成C++進行呼叫,比如Python呼叫C++,或Matlab呼叫C++,
- 對并行性較強的,且用了少量STL庫的演算法使用CUDA加速,
- 大矩陣運算考慮Eigen,cublas等專用庫,
- 對并行性較強,且用了大量STL庫的演算法使用多核并行加速,
- 將高級代碼轉換為C++專案,這也是最簡單的轉換方法了,這樣開發出的演算法非常容易落地,
3 演算法并行
并行思想從小到大可以總結為:指令集開發→多核并行→CUDA并行,在深度學習中,TensorRT是一種更高級的CNN網路加速方法,
3.1 指令集加速
指令集加速,一般是針對CPU架構進行的底層優化,常見于OpenCV和Tensorflow的CPU版本,之所以OpenCV是個經典的開源影像框架,很大原因是因為其在多個平臺上執行效率很高,其中底層的優化,比如指令集優化,起到了關鍵作用,
資料并行的兩種實作在計算機體系中,資料并行有兩種實作路徑:
- MIMD(Multiple Instruction Multiple Data,多指令流多資料流),MIMD的表現形式主要有多發射、多執行緒、多核心,在當代設計的以處理能力為目標驅動的處理器中,均能看到它們的身影,
- SIMD(Single Instruction Multiple Data,單指令流多資料流),隨著多媒體、大資料、人工智能等應用的興起,為處理器賦予SIMD處理能力變得愈發重要,因為這些應用存在大量細粒度、同質、獨立的資料操作,而SIMD天生就適合處理這些操作,SIMD本身并不是一種指令集,而是一種處理思想,現在的一些指令集都支持SIMD,(簡單來說,計算1000維向量的點積,乘法是獨立的,多核心不值得,這時候就可以利用指令集一次性計算4次或8次乘法,同樣的,之后的加法也同樣可以用指令集計算)
CPU指令集的發展(針對Intel的x86指令集系列):
- MMX指令集 (Multi Media eXtension, 多媒體擴展指令集),MMX指令集率先在Pentium處理器中使用,MMX指令集支持算數、比較、移位等運算,MMX指令集的向量暫存器是64bit,
- SSE指令集(Streaming SIMD Extensions,單指令多資料流擴展),所有的SSE系列指令的向量暫存器都是128bit,也就是一次性可以計算4個int,SSE最早出現在1999年,在之后的近10年內,推出了SSE,SSE2,SSE3,SSE4.1,SSE4.2,
- AVX指令集(Advanced Vector Extensions,高級向量擴展),AVX指令集是在之前的SSE128位擴展到和256位的單指令多資料流,AVX出現在2008年,之后出了AVX2,2014年,AVX-512將資料bit由256bit擴展到了512bit,AVX是目前比較常用的指令集,256位的型別可以一次計算4個double,有效的提升性能,
利用CPU-Z軟體可以查看電腦的CPU資訊,
關于指令集的使用,在博客《論文閱讀——橢圓檢測 2020:Arc Adjacency Matrix-Based Fast Ellipse Detection》給出的原始碼中,使用了AVX指令集對代碼進行處理,為了方便理解使用,我們以計算橢圓的采樣點為例,其中 x o , y o , R , r , θ x_o,y_o,R,r,\theta xo?,yo?,R,r,θ分別為橢圓的中心點、長短軸及旋轉角, c o s t , s i n t cost,sint cost,sint表示橢圓引數方程用于采樣,指令集的檔案參考Intel? C++ Compiler XE 12.1 User and Reference Guides ,
{ x = R c o s θ c o s t ? r s i n θ s i n t + x o y = R s i n θ c o s t + r c o s θ s i n t + y o \left\{\begin{array}{l}x = Rcos\theta cost-rsin\theta sint + x_o\\y = Rsin\theta cost + r cos\theta sint + y_o\end{array}\right. {x=Rcosθcost?rsinθsint+xo?y=Rsinθcost+rcosθsint+yo??
則利用指令集計算采樣點的方法如下所示,顯然原來需要計算VALIDATION_NUMBER次采樣點的程序,現在僅需要VALIDATION_NUMBER/8次(sizeof(__m256) / sizeof(float)=8),
// 初始化旋轉變換矩陣,這里angleRot = \theta
const float _ROT_TRANS[4] = { R * cos(angleRot), -r * sin(angleRot),
R * sin(angleRot), r * cos(angleRot) };
// Estimate the sampling points number N. Note: N = RoundEllipseCircum;
// Use SSE to faster the step of ellipse validation.
// 考慮到指令集實際上一次性計算8個資料,
// 則_mm256_set1_ps的目的是用一個float初始化一個__m256
// 舉個例子:假如需要初始化的float為k,則呼叫_mm256_set1_ps之后得到
// [k,k,k,k,k,k,k,k]
__m256 _rot_trans_0 = _mm256_set1_ps(_ROT_TRANS[0]),
_rot_trans_1 = _mm256_set1_ps(_ROT_TRANS[1]),
_rot_trans_2 = _mm256_set1_ps(_ROT_TRANS[2]),
_rot_trans_3 = _mm256_set1_ps(_ROT_TRANS[3]);
__m256 x_center = _mm256_set1_ps(xyCenter[0]),
y_center = _mm256_set1_ps(xyCenter[1]);
__m256 tmp_x, tmp_y, tmp_wx, tmp_wy, tmp_w;
for (int i = 0; i < VALIDATION_NUMBER; i += sizeof(__m256) / sizeof(float))
{
// 一次性讀取256位資料,實際上就是加載8個float到base_x,base_y
// 這里的base_x = cost, base_y = sint
__m256 base_x = _mm256_load_ps(vldBaseDataX + i);
__m256 base_y = _mm256_load_ps(vldBaseDataY + i);
// calculate location x
// _mm256_mul_ps 計算乘法:計算每個float的乘法,_mm256_add_ps
// 舉個例子:兩個__m256資料為[k1,k2,...,k8], [p1,p2,...,p8]
// 呼叫_mm256_mul_ps之后,得到[k1p1,k2p2,...,k8p8]
// 呼叫_mm256_add_ps之后,得到[k1+p1,k2+p2,...,k8+p8]
tmp_x = _mm256_add_ps(
_mm256_mul_ps(_rot_trans_0, base_x),
_mm256_mul_ps(_rot_trans_1, base_y));
tmp_x = _mm256_add_ps(tmp_x, x_center);
// calculate location y
tmp_y = _mm256_add_ps(
_mm256_mul_ps(_rot_trans_2, base_x),
_mm256_mul_ps(_rot_trans_3, base_y));
tmp_y = _mm256_add_ps(tmp_y, y_center);
// Save location x, y
// _mm256_storeu_ps的目的是將計算后的8個float存入float矩陣中
_mm256_storeu_ps(sample_x + i, tmp_x);
_mm256_storeu_ps(sample_y + i, tmp_y);
}
其實后期測驗速度發現,實際加速效果沒有特別明顯,畢竟用了大量中間變數,且函式的呼叫傳遞了引數,指令集實際上在匯編中用的多,如果在代碼中內嵌指令集可能效果會更好,
參考資料:
1 C/C++指令集介紹以及優化(主要針對SSE優化)
3.2 CPU 多核編程
多核編程可以理解為就是多執行緒編程,總體上可以分為三個部分:OpenMP并行,opencv并行和多執行緒并行,在設計相關代碼時候,切記變數可以被多個執行緒訪問,但同一時間只能被一個執行緒修改,如果多個執行緒想修改同一個變數,可使用原子操作或加鎖, 當然,多核編程不止這些,還有tbb,mkl等等,
- OpenMP 并行,這種并行辦法是最簡單的一種并行方法,直接在for回圈前面添加
#pragma omp parallel for即可,程式會自動將for回圈分解,值得注意的是,該方法是在for回圈前開始創建執行緒,結束后并銷毀,這個程序會產生一些時間消耗,大約在3-5ms之間,做實時性應用開發的時候需要注意這個問題,下面給出了一個并行示例,當然openmp有多種操作函式,感興趣去找對應的開發教程即可,
#include <iostream>
#include <omp.h>
using namespace std;
int main() {
omp_set_num_threads(4);
#pragma omp parallel for
for (int i = 0; i < 3; i++)
printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
getchar();
}
// i = 0, I am Thread 0
// i = 1, I am Thread 1
// i = 2, I am Thread 2
- OpenCV 并行, OpenCV提供了一種并行計算函式
parallel_for_,內部集成多種并行框架,在c++11中,可以不必定一個類去繼承并行計算回圈體類ParallelLoopBody,可以直接使用,
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Parallel_My : public ParallelLoopBody
{
public:
Parallel_My (Mat &img, const float x1, const float y1, const float scaleX, const float scaleY)
: m_img(img), m_x1(x1), m_y1(y1), m_scaleX(scaleX), m_scaleY(scaleY){}
virtual void operator ()(const Range& range) const
{
for (int r = range.start; r < range.end; r++) //process of for loop
{
/***
這里寫每個執行緒要做的事情
***/
}
}
Parallel_My& operator=(const Parallel_My &) {
return *this;
};
private:
Mat &m_img;
float m_x1, m_y1, m_scaleX, m_scaleY;
};
int main()
{
Mat Img(480, 640, CV_8U1);
float x1 = -2.1f, x2 = 0.6f, y1 = -1.2f, y2 = 1.2f;
float scaleX = mandelbrotImg.cols / (x2 - x1), scaleY = mandelbrotImg.rows / (y2 - y1);
#ifdef CV_CXX11 // 使用lambda函式的示例
parallel_for_(Range(0, Img.rows*tImg.cols), [&](const Range& range)
{
for (int r = range.start; r < range.end; r++) //這是需要并行計算的for回圈
{
// 自己補充函式
}
});
#else // 默認情況下需要定義一個類,將引數全部傳進去,
Parallel_My parallel_my0(Img, x1, y1, scaleX, scaleY);
parallel_for_(Range(0, Img.rows*Img.cols), parallel_my0);
#endif
}
- 多執行緒并行,上述的兩種方法是針對一個for回圈來解決的,但是整個演算法不可能就由一個for回圈構成,如果每個for回圈都這么做的話,創建執行緒的開銷巨大,因此,多執行緒并行主要就是解決這類問題的,初始化時候創建好執行緒,之后主執行緒串聯演算法,子執行緒解決for回圈問題,執行緒可能會使用同步,加鎖等手段逐步執行,最侄訓得輸出結果,創建多執行緒時候,系統本身就會將不同執行緒分到不同核心上,有自己的調度手段,所以該方法加速效果很明顯,就是過于面向程序,不方便后續的改進,
參考資料:
1 opencv 并行計算函式 parallel_for_的使用
3.3 CUDA 編程加速
CUDA加速其實是最好的加速手段,CUDA最大的特性就是核心數特別多,一般是幾千個,相比于CPU,加速倍數高達20-200倍之間,特別是推出的Jetson NX系列嵌入式卡,核心數在128-512之間,推進了更多演算法的落地應用,
如果想學習CUDA,我非常推薦下真本書,基礎的都涵蓋了,看完之后基本就能動手寫程式了,
CUDA開發主要還是有C語言風格,C++用的很少,切記一點避免在CUDA中動態分配記憶體,最好通過引數傳遞記憶體指標,
下面給出一個向量加法示例,來簡單說明CUDA的用法,
#define N (33*1024)
// 核函式就是表示每個CUDA核心執行的函式,用關鍵字__global__ 表示
__global__ void add(int *a,int *b,int *c)
{
int tid = threadIdx.x + blockIdx.x*blockDim.x;
while(tid < N){
c[tid] = a[tid] + b[tid];
tid += blockDim.x*gridDim.x;
}
}
int main(void)
{
int a[N],b[N],c[N];
int *dev_a,*dev_b,*dev_c;
//在GPU上分配記憶體
cudaMalloc((void**)&dev_a,N*sizeof(int));
cudaMalloc((void**)&dev_b,N*sizeof(int));
cudaMalloc((void**)&dev_c,N*sizeof(int));
//在CPU上為陣列'a'和陣列'b'賦值
for(int i=0;i<N;i++){
a[i] = i;
b[i] = i*i;
}
//將陣列‘a’和陣列‘b’復制到GPU記憶體中
cudaMemcpy(dev_a,a,N*sizeof(int),cudaMemcpyHostToDevice);
cudaMemcpy(dev_b,b,N*sizeof(int),cudaMemcpyHostToDevice);
add<<<128,128>>>(dev_a,dev_b,dev_c);
//將陣列‘C’從GPU復制到CPU中
cudaMemcpy(c,dev_c,N*sizeof(int),cudaMemcpyDeviceToHost);
//驗證GPU計算結果
for(int i=0;i<N;i++){
if(a[i]+b[i] != c[i]){
printf("error:%d+%d=%d\n",a[i],b[i],c[i]);
}
}
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}
我曾經加速過經典導向濾波程式WGIF演算法,導向濾波核心是以每個像素為核心,根據周圍像素做濾波處理,在原始Matlab上的運算速度大約是20s左右,經過CUDA加速后,僅需要80ms即可跑完一張圖片,
在CPU上多執行緒開發遇到的一些同步、執行緒通信問題CUDA下都有,
對于一些常數記憶體,也就是不需要被修改的記憶體,CUDA給了很多種形式用于快速訪問:
- 常量記憶體,限制為64kb
- 紋理記憶體,多數應用于二維矩陣的訪問,
當然,更加詳細的用法,去看書即可,這里只是簡單介紹,
3.4 TensorRT 加速深度學習
TensorRT早期叫法叫GIE (GPU Inference Engine, GPU推理引擎),從名字上就知道這個東西用于推理(也就是測驗程序),Tensor可以理解為高維陣列,在TensorRT中,所有的資料都被組成最高四維的陣列,如果對應到CNN中其實就是 { N , C , H , W } \{N, C, H, W\} {N,C,H,W},N表示batch size,即多少張圖片或者多少個推斷(Inference)的實體;C表示channel數目;H和W表示影像或feature maps的高度和寬度,RT表示的是Runtime,
在深度學習的落地應用中,主要就是輸入圖片,推斷結果,模型如果做得不好,沒有做優化,可能需要500多ms才推斷完一張圖片,延遲較高,導致系統靈活性變弱,下圖紅色部分指的就是TensorRT要干的事,

推斷的幾種特性:
- 網路權值已經固定下來,無后向傳播程序,因此可以:
- 模型固定,可以對計算圖進行優化
- 輸入輸出大小固定,可以做memory優化
- batch size要小一些,GPU利用率可能低些,
- 可使用低精度技術推斷,深度學習網路引數一般為
float32型別,這也是最小的浮點型別,很多研究表明可以用低精度,如半長(16)的float型別FP16,也可以用8位的整型(INT8)來做推斷,研究結果表明沒有特別大的精度損失,尤其對CNN,二值權值目前也在研究中,只不過FP16和INT8的研究使用相對來說比較成熟,低精度推斷的優點很明顯:速度快、記憶體低,

而TensorRT所做的優化,主要有以下幾點:
- 合并了一些固定順序層,比如合并了卷積層、batchnorm層和激活層,取名為CBR層,
- 取消無用層,比如concat層,實際上就是拼接特征,這里做了優化,
- TensorRT在多種嵌入式設備都提供了驅動支持,
下面給出的一種網路,就非常適合用TensorRT優化,

總的來說,盡管TensorRT做了很多優化,但加速效果普遍在20%左右,做好剪枝或改變資料型別可以提升2-3倍的性能,TensorRT只是在計算上優化了,想變得更快還是得想辦法設計出一個更加輕量的網路,
參考資料:
1 高性能深度學習支持引擎實戰——TensorRT
4 匯編加速
用匯編加速的方法往往指的是C/C++與匯編混合編程,盡管多種編譯器均有優化等級選項,但是越是高級的語言,時間損耗越多,
什么時候使用匯編加速呢? 一般有兩種情況需要嵌入匯編代碼:
- ① 升級專案,專案原始版本是匯編代碼,現在需要用C++開發,重寫匯編代碼注定耗時,直接呼叫匯編是個很好的解決方案,
- ② 不同的語言對演算法一半都有特定的處理方法,比如Matlab之類盡量使用矩陣運算,C++盡量使用指標訪問等,如果有個頻繁呼叫的演算法,在匯編上有獨特的計算方法,那么直接在C++呼叫這個匯編函式,可以達到加速效果,
如何嵌入匯編代碼呢? 方法很簡單,使用關鍵字__asm來加入一段匯編語言的程式,C++下具體的格式為:__asm{ 指令 [;指令] /* comments */ ... 指令}
在C語言下,格式為:
asm [ volatile ] (
assembler template
[ : output operands ] /* optional /
[ : input operands ] / optional /
[ : list of clobbered registers ] / optional */
);
下面給一個示例(VS x64似乎不支持匯編擴展,我僅僅是見別人的演算法中用過,自己沒開發過),
#include <stdio.h>
/* 賦值 */
static int value_assignment(int input) {
int ret = 0;
asm volatile(
/* ret = input */
"movl %1, %0\n" /* 通過占位符指定互動的變數 : %0:ret %1:input*/
:"=r"(ret)
:"r"(input)
);
return ret;
}
int main() {
int input = 1;
int ret = value_assignment(input);
printf("input = %d\n", input);
printf("ret = %d\n", ret);
return 0;
}
// 列印結果:
// input = 1
// ret = 1
5 硬體加速
前面介紹了各種通過編程加速的方法,核心是將演算法進行并行化處理,總的來說
- 多核并行,啟動并行時需要開多執行緒,需要少量的時間(<10ms),因此僅適用耗時較長的演算法(>100ms)的并行,
- CUDA并行,演算法不可避免串行程序,因此許多時間在記憶體和顯存之間的拷貝,
- CPU指定集,小規模加速,但僅限于各種基本運算操作(加減乘除、位運算等),
如今,FPGA是日趨熱門的一種加速方法,與軟體加速不同,該方法是直接將演算法設計在電路上,變成專有模塊進行并行,

FPGA是目前新的一種低功耗加速設備,雖然通用的CPU主頻很高,但做某個特定運算(如影像處理中的Sobel)可能需要很多個時鐘周期;而FPGA可以通過編程重組電路,直接生成專用電路,加上電路并行性,可能做這個特定運算只需要一個時鐘周期,舉例來說,CPU主頻3GHz,FPGA主頻500MHz,若做某個特定運算CPU需要15個時鐘周期,FPGA只需一個,則耗時情況: CPU:15/3GHz =5ns; FPGA:1/500MHz =2ns,可以看到,FPGA做這個特定運算速度比CPU塊,能幫助加速,
以影像處理中常見的Sobel演算法來說,在FPGA上的實作可以參考A FPGA based implementation of Sobel edge detection,達到這個速度已經可以與opencv的sobel速度媲美了,

在一些經典演算法中,比如橢圓檢測,也是可以利用FPGA的,比如論文《Effective ellipse detection method in limited-performance embedded system》,就是FPGA和DSP的一種結合,利用FPGA進行預處理,利用DSP處理串行操作,以實作實時處理,

6 光學加速
目前來說,顯卡的性能受制于能耗和物理極限,每次更新換代,感覺并沒有那么高的性能提升,多卡緩解這類問題,但是功耗實在太大,
而光衍射深度神經網路,提出了一種非常新奇的思想,Science發表了加州大學洛杉磯分校(UCLA)研究人員的最新研究:All-optical machine learning using diffractive deep neural networks,他們使用 3D 列印打造了一套 “全光學” 人工神經網路,可以分析大量資料并以光速識別目標,它使用來自物體的光散射來識別目標,研究團隊先用計算機進行模擬,然后用 3D 列印機打造出 8 平方厘米的聚合物層,每個晶圓表面都是不平整的,目的是為了衍射來自目標的光線,
以手寫數字識別為例,設計了一個五層的DNN,訓練之后測驗,實作了91.75%的分類精度,根據這些數值結果,我們將這個5層的DNN 設計3D列印出來,每一層的面積為8cm×8cm,然后在衍射網路的輸出平面定義10個檢測器區域,

光學電路深度學習是一項重大突破,光的延遲非常低,所需的功耗也是極低,如果未來的加工工藝更加成熟,未來將是一個非常幫的突破,
參考資料:
1 Science重磅!用光速實作深度學習,跟GPU說再見
7 總結
我認為作為科研作業者,應該掌握一些基本的加速方法,比如多執行緒、CUDA之類,很多專業,跑一些演算法,用Matlab跑好幾分鐘甚至好幾個小時才能出結果,大大降低了科研效率,這些開發語言完全可以套上C++的外殼進行加速,
在工業機械領域,很看重實時性,如果自己設計出的演算法效果又好,又能落地,那多完美,
當然,大多數的加速方法破壞了面向物件這個性質,高度程序化,所以,一般是當自己的程式確定不改了,實驗做完了,再去考慮加速,讓你的效果更上一層樓,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/277013.html
標籤:其他
