Estou fazendo alguns benchmarks com CUDA, C ++, C #, Java e usando o MATLAB para verificação e geração de matriz. Quando executo a multiplicação de matrizes com o MATLAB, 2048x2048
matrizes ainda maiores são multiplicadas quase instantaneamente.
1024x1024 2048x2048 4096x4096
--------- --------- ---------
CUDA C (ms) 43.11 391.05 3407.99
C++ (ms) 6137.10 64369.29 551390.93
C# (ms) 10509.00 300684.00 2527250.00
Java (ms) 9149.90 92562.28 838357.94
MATLAB (ms) 75.01 423.10 3133.90
Somente a CUDA é competitiva, mas achei que pelo menos o C ++ seria um pouco próximo e não 60 vezes mais lento. Também não sei o que pensar sobre os resultados do C #. O algoritmo é o mesmo que C ++ e Java, mas há um salto gigante 2048
de 1024
.
Como o MATLAB está realizando a multiplicação de matrizes tão rápido?
Código C ++:
float temp = 0;
timer.start();
for(int j = 0; j < rozmer; j++)
{
for (int k = 0; k < rozmer; k++)
{
temp = 0;
for (int m = 0; m < rozmer; m++)
{
temp = temp + matice1[j][m] * matice2[m][k];
}
matice3[j][k] = temp;
}
}
timer.stop();
Respostas:
Aqui estão meus resultados usando a Caixa de ferramentas de computação paralela MATLAB R2011a + em uma máquina com um Tesla C2070:
O MATLAB usa bibliotecas altamente otimizadas para multiplicação de matrizes, e é por isso que a multiplicação simples de matrizes MATLAB é tão rápida. A
gpuArray
versão usa MAGMA .Atualize usando o R2014a em uma máquina com um Tesla K20c e o novo
timeit
egputimeit
funções:Atualizar usando o R2018b em uma máquina WIN64 com 16 núcleos físicos e um Tesla V100:
(Nota: em algum momento (eu esqueço exatamente))
gpuArray
do MAGMA para o cuBLAS - o MAGMA ainda é usado em algumasgpuArray
operações)fonte
Esse tipo de pergunta é recorrente e deve ser respondida com mais clareza do que "MATLAB usa bibliotecas altamente otimizadas" ou "MATLAB usa o MKL" pela primeira vez no Stack Overflow.
História:
A multiplicação de matrizes (juntamente com a matriz de vetores, multiplicação de vetores e muitas das decomposições de matrizes) é (são) os problemas mais importantes na álgebra linear. Os engenheiros têm resolvido esses problemas com os computadores desde os primeiros dias.
Não sou especialista em história, mas aparentemente naquela época todo mundo reescreveu sua versão do FORTRAN com loops simples. Alguma padronização surgiu com a identificação de "kernels" (rotinas básicas) que a maioria dos problemas de álgebra linear precisava para ser resolvida. Essas operações básicas foram padronizadas em uma especificação chamada: Subprogramas Básicos de Álgebra Linear (BLAS). Os engenheiros poderiam então chamar essas rotinas BLAS padrão e bem testadas em seu código, facilitando muito o trabalho.
BLAS:
O BLAS evoluiu do nível 1 (a primeira versão que definiu operações de vetor escalar e vetor de vetor) para o nível 2 (operações de matriz vetorial) para o nível 3 (operações de matriz matricial) e forneceu mais e mais "kernels" para padronizar mais e mais das operações fundamentais de álgebra linear. As implementações originais do FORTRAN 77 ainda estão disponíveis no site da Netlib .
Para um melhor desempenho:
Assim, ao longo dos anos (principalmente entre os lançamentos BLAS nível 1 e nível 2: início dos anos 80), o hardware mudou, com o advento das operações de vetor e hierarquias de cache. Essas evoluções permitiram aumentar substancialmente o desempenho das sub-rotinas BLAS. Diferentes fornecedores surgiram com a implementação de rotinas BLAS, cada vez mais eficientes.
Não conheço todas as implementações históricas (eu não nasci ou era criança na época), mas duas das mais notáveis surgiram no início dos anos 2000: o Intel MKL e o GotoBLAS. Seu Matlab usa o Intel MKL, que é um BLAS muito bom e otimizado, o que explica o ótimo desempenho que você vê.
Detalhes técnicos sobre multiplicação de matrizes:
Então, por que o Matlab (o MKL) é tão rápido
dgemm
(multiplicação matriz-matriz geral de dupla precisão)? Em termos simples: porque usa vetorização e bom cache de dados. Em termos mais complexos: veja o artigo fornecido por Jonathan Moore.Basicamente, quando você executa sua multiplicação no código C ++ que você forneceu, você não é totalmente compatível com o cache. Como suspeito que você tenha criado uma matriz de ponteiros para matrizes de linha, seus acessos no loop interno à k-ésima coluna de "matice2":
matice2[m][k]
são muito lentos. De fato, quando você acessamatice2[0][k]
, você deve obter o k-ésimo elemento da matriz 0 da sua matriz. Na próxima iteração, você deve acessarmatice2[1][k]
, que é o k-ésimo elemento de outra matriz (a matriz 1). Então, na próxima iteração, você acessa outra matriz, e assim por diante ... Como a matriz inteiramatice2
não pode se encaixar nos caches mais altos (seus8*1024*1024
bytes são grandes), o programa deve buscar o elemento desejado da memória principal, perdendo muito Tempo.Se você acabou de transpor a matriz, para que os acessos estivessem em endereços de memória contíguos, seu código já seria executado muito mais rápido, porque agora o compilador pode carregar linhas inteiras no cache ao mesmo tempo. Apenas tente esta versão modificada:
Assim, você pode ver como a localidade do cache aumentou o desempenho do seu código de maneira bastante substancial. Agora real
dgemm
implementações exploram isso em um nível muito extenso: elas realizam a multiplicação em blocos da matriz definida pelo tamanho do TLB (tradução ao lado do buffer de tradução, longa história: o que pode ser efetivamente armazenado em cache), para que sejam transmitidos ao processador exatamente a quantidade de dados que pode processar. O outro aspecto é a vetorização, eles usam as instruções vetorizadas do processador para obter o melhor rendimento de instruções, o que você realmente não pode fazer com o código C ++ de plataforma cruzada.Finalmente, as pessoas que afirmam que é por causa do algoritmo de Strassen ou Coppersmith – Winograd estão erradas, esses dois algoritmos não são implementáveis na prática, devido às considerações de hardware mencionadas acima.
fonte
É por isso . O MATLAB não executa uma multiplicação de matriz ingênua, fazendo um loop sobre cada elemento da maneira que você fez no seu código C ++.
É claro que estou assumindo que você acabou de usar em
C=A*B
vez de escrever uma função de multiplicação.fonte
O Matlab incorporou o LAPACK há algum tempo, então suponho que a multiplicação da matriz deles use algo pelo menos tão rápido. O código-fonte e a documentação do LAPACK estão prontamente disponíveis.
Você também pode ler o artigo de Goto e Van De Geijn "Anatomia da multiplicação de matrizes de alto desempenho" em http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.1785&rep=rep1&type=pdf
fonte
A resposta é que as bibliotecas LAPACK e BLAS tornam o MATLAB incrivelmente rápido nas operações da matriz, e não qualquer código proprietário do pessoal do MATLAB.
Use as bibliotecas LAPACK e / ou BLAS no seu código C ++ para operações de matriz e você deverá obter desempenho semelhante ao MATLAB. Essas bibliotecas devem estar disponíveis gratuitamente em qualquer sistema moderno e as partes foram desenvolvidas ao longo de décadas na academia. Observe que existem várias implementações, incluindo algumas de código fechado, como o Intel MKL .
Uma discussão sobre como o BLAS obtém alto desempenho está disponível aqui.
BTW, é uma dor grave na minha experiência chamar bibliotecas LAPACK diretamente de c (mas vale a pena). Você precisa ler a documentação MUITO com precisão.
fonte
Ao fazer a multiplicação de matrizes, você usa o método de multiplicação ingênuo, que leva tempo de
O(n^3)
.Existem algoritmos de multiplicação de matrizes que são necessários
O(n^2.4)
. O que significa que non=2000
seu algoritmo requer ~ 100 vezes mais computação que o melhor algoritmo.Você deve realmente verificar a página da Wikipedia para obter multiplicação de matrizes para obter mais informações sobre as maneiras eficientes de implementá-la.
fonte
Dependendo da sua versão do Matlab, acredito que ele já esteja usando sua GPU.
Outra coisa; O Matlab mantém o controle de muitas propriedades da sua matriz; se sua diagonal, hermética e assim por diante, e especializa seus algoritmos baseados nela. Talvez seja especializado com base na matriz zero que você está passando, ou algo assim? Talvez seja o cache de chamadas de função repetidas, o que atrapalha o seu tempo? Talvez otimize produtos matriciais não utilizados repetidos?
Para evitar que essas coisas aconteçam, use uma matriz de números aleatórios e certifique-se de forçar a execução imprimindo o resultado na tela ou no disco ou algo assim.
fonte
A.*B
ele. Portanto, o OP está quase certamente brincando com alguma coisa.O MATLAB usa uma implementação altamente otimizada do LAPACK da Intel, conhecida como Intel Math Kernel Library (Intel MKL) - especificamente a função dgemm . A velocidade Esta biblioteca aproveita os recursos do processador, incluindo instruções SIMD e processadores com vários núcleos. Eles não documentam qual algoritmo específico eles usam. Se você ligar para o Intel MKL a partir do C ++, deverá ter um desempenho semelhante.
Não tenho certeza de qual biblioteca o MATLAB usa para multiplicação de GPU, mas provavelmente algo como nVidia CUBLAS .
fonte
A resposta geral para "Por que o matlab é mais rápido em executar xxx do que outros programas" é que o matlab possui muitas funções otimizadas.
Os outros programas usados frequentemente não possuem essas funções, portanto as pessoas aplicam suas próprias soluções criativas, que são surpreendentemente mais lentas que o código otimizado profissionalmente.
Isso pode ser interpretado de duas maneiras:
1) A maneira comum / teórica: o Matlab não é significativamente mais rápido, você está apenas fazendo o benchmark errado
2) A maneira realista: Para esse material, o Matlab é mais rápido na prática, porque linguagens como c ++ são usadas com muita facilidade de maneiras ineficazes.
fonte
O forte contraste não se deve apenas à incrível otimização do Matlab (como já foi discutido por muitas outras respostas), mas também à maneira como você formulou a matriz como um objeto.
Parece que você fez da matriz uma lista de listas? Uma lista de listas contém ponteiros para listas que contêm os elementos da matriz. Os locais das listas contidas são atribuídos arbitrariamente. Como você está repetindo seu primeiro índice (número da linha?), O tempo de acesso à memória é muito significativo. Em comparação, por que você não tenta implementar a matriz como uma única lista / vetor usando o seguinte método?
E
O mesmo algoritmo de multiplicação deve ser usado para que o número de flop seja o mesmo. (n ^ 3 para matrizes quadradas de tamanho n)
Estou pedindo para cronometrar para que o resultado seja comparável ao que você tinha anteriormente (na mesma máquina). Com a comparação, você mostrará exatamente o quão significativo o tempo de acesso à memória pode ser!
fonte
É lento no C ++ porque você não está usando multithreading. Essencialmente, se A = BC, onde todas são matrizes, a primeira linha de A pode ser calculada independentemente da 2ª linha, etc. Se A, B e C são todos n por n matrizes, você pode acelerar a multiplicação por um fator de n ^ 2, como
a_ {i, j} = soma_ {k} b_ {i, k} c_ {k, j}
Se você usa, digamos, Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ], o multithreading é incorporado e o número de threads é ajustável.
fonte
Porque o MATLAB é uma linguagem de programação desenvolvida inicialmente para álgebra linear numérica (manipulação de matrizes), que possui bibliotecas especialmente desenvolvidas para multiplicações de matrizes. E agora o MATLAB também pode usar as GPUs (unidade de processamento gráfico) para isso adicionalmente.
E se olharmos para os seus resultados de computação:
então podemos ver que não apenas o MATLAB é tão rápido na multiplicação de matrizes: CUDA C (linguagem de programação da NVIDIA) tem resultados melhores que o MATLAB. O CUDA C também possui bibliotecas especialmente desenvolvidas para multiplicações de matrizes e utiliza as GPUs.
Breve história do MATLAB
O que é CUDA C
O CUDA C também usa bibliotecas especialmente desenvolvidas para multiplicações de matrizes como o OpenGL (Open Graphics Library). Ele também usa GPU e Direct3D (no MS Windows).
Comparando velocidades de execução de CPU e GPU
Da introdução ao Guia de programação CUDA C:
Leitura avançada
Subprogramas de Álgebra Linear Básica (BLAS)
Anatomia da multiplicação de matrizes de alto desempenho , de Kazushige Goto e Robert A. Van De Geijn
Algumas caras interessantes
fonte
"additionally"
. Significa: pode ser usado. Isso também significa que a multiplicação normal da matriz ainda usa bibliotecas de software. Você acha que preciso alterar minha postagem para ser mais compreensível? Obrigado por seus comentários!