ニューラルネットワークを実装している間、データセット配列に対して1つの連続したブロックとしてメモリを割り当てると、実行時間が数倍に増加することに気付きました。大きな行列を掛け合わせることは連続したメモリ割り当てでははるかに遅い
メモリ割り当てのこれら2つの方法を比較:-march=native -Ofast
(試みGCCと打ち鳴らす)でコンパイルするときにここ
float** alloc_2d_float(int rows, int cols, int contiguous)
{
int i;
float** array = malloc(rows * sizeof(float*));
if(contiguous)
{
float* data = malloc(rows*cols*sizeof(float));
assert(data && "Can't allocate contiguous memory");
for(i=0; i<rows; i++)
array[i] = &(data[cols * i]);
}
else
for(i=0; i<rows; i++)
{
array[i] = malloc(cols * sizeof(float));
assert(array[i] && "Can't allocate memory");
}
return array;
}
結果である:
[email protected]:~/NN$ time ./test 300 1 0
Multiplying (100000, 1000) and (300, 1000) arrays 1 times, noncontiguous memory allocation.
Allocating memory: 0.2 seconds
Initializing arrays: 0.8 seconds
Dot product: 3.3 seconds
real 0m4.296s
user 0m4.108s
sys 0m0.188s
[email protected]:~/NN$ time ./test 300 1 1
Multiplying (100000, 1000) and (300, 1000) arrays 1 times, contiguous memory allocation.
Allocating memory: 0.0 seconds
Initializing arrays: 40.3 seconds
Dot product: 13.5 seconds
real 0m53.817s
user 0m4.204s
sys 0m49.664s
ここでは、コードは次のとおり https://github.com/michaelklachko/NN/blob/master/test.c
初期化とドット積の両方が連続したメモリの方がはるかに遅いことに注意してください。
私はその反対のことを期待しました。連続したメモリブロックは、多数の別々の小さなブロックよりキャッシュフレンドリでなければなりません。または、少なくともパフォーマンスは似ているはずです(このマシンのRAMは64GBで、その90%は使用されていません)。
編集:ここでは圧縮された自己完結型のコードは(私はまだ文を測定し、書式設定有し、代わりにgithubのバージョンを使用することをお勧めします)です:あなたはあなたの能力や障害に遭遇しているよう
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
float** alloc_2d_float(int rows, int cols, int contiguous){
int i;
float** array = malloc(rows * sizeof(float*));
if(contiguous){
float* data = malloc(rows*cols*sizeof(float));
for(i=0; i<rows; i++)
array[i] = &(data[cols * i]);
}
else
for(i=0; i<rows; i++)
array[i] = malloc(cols * sizeof(float));
return array;
}
void initialize(float** array, int dim1, int dim2){
srand(time(NULL));
int i, j;
for(i=0; i<dim1; i++)
for(j=0; j<dim2; j++)
array[i][j] = rand()/RAND_MAX;
}
int main(){
int i,j,k, dim1=100000, dim2=1000, dim3=300;
int contiguous=0;
float temp;
float** array1 = alloc_2d_float(dim1, dim2, contiguous);
float** array2 = alloc_2d_float(dim3, dim2, contiguous);
float** result = alloc_2d_float(dim1, dim3, contiguous);
initialize(array1, dim1, dim2);
initialize(array2, dim3, dim2);
for(i=0; i<dim1; i++)
for(k=0; k<dim3; k++){
temp = 0;
for(j=0; j<dim2; j++)
temp += array1[i][j] * array2[k][j];
result[i][k] = temp;
}
}
を一切2Dはありませんあなたのコードの配列。 'float **'のようなものは2D配列ではなく、それを指すものでもありません。 2D配列を使用します。 [ask]を参照し、[mcve]を提供してください。 – Olaf
@Olaf:どういう意味ですか?配列の配列を作成していますが、そうではありませんか? – MichaelSB
いいえ、あなたはありません! 'float' **へのポインタの配列を作成します。非常に異なるデータ型。多次元配列について学ぶことをお勧めします。あなたが使っているものは、これからのもので、おそらく**あなたの問題です。 – Olaf