KomputeA estrutura de computação GPU de uso geral para placas gráficas de fornecedor cruzado (AMD, Qualcomm, Nvidia e amigos) |
Junte -se às chamadas Discord & Community? Postagem de blog de documentação ⌨ Exemplos?
Abaixo, você pode encontrar um exemplo de multiplicação de GPU usando as interfaces C ++ e Python Kompute.
Você pode ingressar na discórdia para perguntas / discussão, abrir um problema do GitHub ou ler a documentação.
A interface C ++ fornece acesso de baixo nível aos componentes nativos do Kompute, permitindo otimizações avançadas e a extensão dos componentes.
void kompute ( const std::string& shader) {
// 1. Create Kompute Manager with default settings (device 0, first queue and no extensions)
kp::Manager mgr;
// 2. Create and initialise Kompute Tensors through manager
// Default tensor constructor simplifies creation of float values
auto tensorInA = mgr. tensor ({ 2 ., 2 ., 2 . });
auto tensorInB = mgr. tensor ({ 1 ., 2 ., 3 . });
// Explicit type constructor supports uint32, int32, double, float and bool
auto tensorOutA = mgr. tensorT < uint32_t >({ 0 , 0 , 0 });
auto tensorOutB = mgr. tensorT < uint32_t >({ 0 , 0 , 0 });
std::vector<std::shared_ptr<kp::Memory>> params = {tensorInA, tensorInB, tensorOutA, tensorOutB};
// 3. Create algorithm based on shader (supports buffers & push/spec constants)
kp::Workgroup workgroup ({ 3 , 1 , 1 });
std::vector< float > specConsts ({ 2 });
std::vector< float > pushConstsA ({ 2.0 });
std::vector< float > pushConstsB ({ 3.0 });
auto algorithm = mgr. algorithm (params,
// See documentation shader section for compileSource
compileSource (shader),
workgroup,
specConsts,
pushConstsA);
// 4. Run operation synchronously using sequence
mgr. sequence ()
-> record <kp::OpSyncDevice>(params)
-> record <kp::OpAlgoDispatch>(algorithm) // Binds default push consts
-> eval () // Evaluates the two recorded operations
-> record <kp::OpAlgoDispatch>(algorithm, pushConstsB) // Overrides push consts
-> eval (); // Evaluates only last recorded operation
// 5. Sync results from the GPU asynchronously
auto sq = mgr. sequence ();
sq-> evalAsync <kp::OpSyncLocal>(params);
// ... Do other work asynchronously whilst GPU finishes
sq-> evalAwait ();
// Prints the first output which is: { 4, 8, 12 }
for ( const float & elem : tensorOutA-> vector ()) std::cout << elem << " " ;
// Prints the second output which is: { 10, 10, 10 }
for ( const float & elem : tensorOutB-> vector ()) std::cout << elem << " " ;
} // Manages / releases all CPU and GPU memory resources
int main () {
// Define a raw string shader (or use the Kompute tools to compile to SPIRV / C++ header
// files). This shader shows some of the main components including constants, buffers, etc
std::string shader = ( R"(
#version 450
layout (local_size_x = 1) in;
// The input tensors bind index is relative to index in parameter passed
layout(set = 0, binding = 0) buffer buf_in_a { float in_a[]; };
layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; };
layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; };
layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; };
// Kompute supports push constants updated on dispatch
layout(push_constant) uniform PushConstants {
float val;
} push_const;
// Kompute also supports spec constants on initalization
layout(constant_id = 0) const float const_one = 0;
void main() {
uint index = gl_GlobalInvocationID.x;
out_a[index] += uint( in_a[index] * in_b[index] );
out_b[index] += uint( const_one * push_const.val );
}
)" );
// Run the function declared above with our raw string shader
kompute (shader);
}
O pacote Python fornece uma interface interativa de alto nível que permite a experimentação, garantindo fluxos de trabalho de alto desempenho e desenvolvimento rápido.
from . utils import compile_source # using util function from python/test/utils
def kompute ( shader ):
# 1. Create Kompute Manager with default settings (device 0, first queue and no extensions)
mgr = kp . Manager ()
# 2. Create and initialise Kompute Tensors through manager
# Default tensor constructor simplifies creation of float values
tensor_in_a = mgr . tensor ([ 2 , 2 , 2 ])
tensor_in_b = mgr . tensor ([ 1 , 2 , 3 ])
# Explicit type constructor supports uint32, int32, double, float and bool
tensor_out_a = mgr . tensor_t ( np . array ([ 0 , 0 , 0 ], dtype = np . uint32 ))
tensor_out_b = mgr . tensor_t ( np . array ([ 0 , 0 , 0 ], dtype = np . uint32 ))
assert ( t_data . data_type () == kp . DataTypes . uint )
params = [ tensor_in_a , tensor_in_b , tensor_out_a , tensor_out_b ]
# 3. Create algorithm based on shader (supports buffers & push/spec constants)
workgroup = ( 3 , 1 , 1 )
spec_consts = [ 2 ]
push_consts_a = [ 2 ]
push_consts_b = [ 3 ]
# See documentation shader section for compile_source
spirv = compile_source ( shader )
algo = mgr . algorithm ( params , spirv , workgroup , spec_consts , push_consts_a )
# 4. Run operation synchronously using sequence
( mgr . sequence ()
. record ( kp . OpTensorSyncDevice ( params ))
. record ( kp . OpAlgoDispatch ( algo )) # Binds default push consts provided
. eval () # evaluates the two recorded ops
. record ( kp . OpAlgoDispatch ( algo , push_consts_b )) # Overrides push consts
. eval ()) # evaluates only the last recorded op
# 5. Sync results from the GPU asynchronously
sq = mgr . sequence ()
sq . eval_async ( kp . OpTensorSyncLocal ( params ))
# ... Do other work asynchronously whilst GPU finishes
sq . eval_await ()
# Prints the first output which is: { 4, 8, 12 }
print ( tensor_out_a )
# Prints the first output which is: { 10, 10, 10 }
print ( tensor_out_b )
if __name__ == "__main__" :
# Define a raw string shader (or use the Kompute tools to compile to SPIRV / C++ header
# files). This shader shows some of the main components including constants, buffers, etc
shader = """
#version 450
layout (local_size_x = 1) in;
// The input tensors bind index is relative to index in parameter passed
layout(set = 0, binding = 0) buffer buf_in_a { float in_a[]; };
layout(set = 0, binding = 1) buffer buf_in_b { float in_b[]; };
layout(set = 0, binding = 2) buffer buf_out_a { uint out_a[]; };
layout(set = 0, binding = 3) buffer buf_out_b { uint out_b[]; };
// Kompute supports push constants updated on dispatch
layout(push_constant) uniform PushConstants {
float val;
} push_const;
// Kompute also supports spec constants on initalization
layout(constant_id = 0) const float const_one = 0;
void main() {
uint index = gl_GlobalInvocationID.x;
out_a[index] += uint( in_a[index] * in_b[index] );
out_b[index] += uint( const_one * push_const.val );
}
"""
kompute ( shader )Você pode experimentar os notebooks interativos do COLAB que permitem usar uma GPU gratuita. Os exemplos disponíveis são os exemplos Python e C ++ abaixo:
Experimente o C ++ colab interativo da postagem do blog | Experimente o Python Colab interativo da postagem do blog |
Você também pode conferir as duas palestras seguintes apresentadas na conferência FOSDEM 2021.
Ambos os vídeos têm registros de data e hora que permitirão que você pular para a seção mais relevante para você - a introdução e as motivações para ambas são quase as mesmas, para que você possa pular para o conteúdo mais específico.
Assista ao vídeo para entusiastas do C ++ | Assista ao vídeo para entusiastas do aprendizado de Python e Machine |
A arquitetura principal do Kompute inclui o seguinte:
Para ver um detalhamento completo, você pode ler mais adiante na referência da classe C ++.
| Arquitetura completa | Componentes simplificados de kompute |
|---|---|
(muito pequeno, verifique o diagrama de referência completo nos documentos para obter detalhes) |
O Kompute oferece flexibilidade para executar operações de maneira assífica de vk :: cercas. Além disso, o Kompute permite a alocação explícita de filas, que permitem a execução paralela de operações nas famílias de filas.
A imagem abaixo fornece uma intuição sobre como as seqüências de Kompute podem ser alocadas a diferentes filas para permitir a execução paralela com base no hardware. Você pode ver as mãos no exemplo, bem como a página de documentação detalhada, descrevendo como ela funcionaria usando um NVIDIA 1650 como exemplo.
Kompute foi otimizado para funcionar em ambientes móveis. O sistema de construção permite o carregamento dinâmico da biblioteca compartilhada da Vulkan para ambientes Android, juntamente com um wrapper NDK do Android em funcionamento para os cabeçalhos do CPP.
Para um mergulho profundo completo, você pode ler a postagem do blog "Superalimentando seus aplicativos móveis com o aprendizado de máquina acelerado da GPU no dispositivo". Você também pode acessar o código de exemplo de ponta a ponta no repositório, que pode ser executado usando o Android Studio. |
Além do C ++ Core SDK, você também pode usar o pacote Python de Kompute, que expõe a mesma funcionalidade principal, e suporta interoperabilidade com objetos Python, como listas, matrizes numpy etc.
As únicas dependências são o Python 3.5+ e o cmake 3.4.1+. Você pode instalar o Kompute no pacote Python Pypi usando o seguinte comando.
pip install kp
Você também pode instalar no Master Branch usando:
pip install git+git://github.com/KomputeProject/kompute.git@master
Para mais detalhes, você pode ler a documentação do pacote Python ou a documentação de referência da classe Python.
O sistema de construção fornecido usa cmake , que permite compilações cruzadas de plataforma.
O nível superior Makefile fornece um conjunto de configurações otimizadas para o desenvolvimento, bem como a construção da imagem do Docker, mas você pode iniciar uma construção com o seguinte comando:
cmake -Bbuild
Você também pode adicionar kompute no seu repositório com add_subdirectory - o arquivo cmakelists.txt do exemplo do Android mostra como isso seria feito.
Para uma visão geral mais avançada da configuração do Build, consulte a documentação de mergulho profundo do sistema Build.
Agradecemos a PRs e questões. Se você deseja contribuir com a tag "Boa Primeira Edição", mas mesmo usar os problemas de Kompute e relatar é uma ótima contribuição!
Se você quiser executar com camadas de depuração, poderá adicioná -las com o parâmetro KOMPUTE_ENV_DEBUG_LAYERS como:
export KOMPUTE_ENV_DEBUG_LAYERS="VK_LAYER_LUNARG_api_dump"
Para atualizar a documentação, você precisará:
make push_docs_to_ghpages A execução dos testes de unidade foi significativamente simplificada para os colaboradores.
Os testes são executados na CPU e podem ser acionados usando a interface da linha de comando do ACT (https://github.com/nektos/act) - depois de instalar a linha de comando (e iniciar o daemon do docker), você só precisa digitar:
$ act
[Python Tests/python-tests] Start image=axsauze/kompute-builder:0.2
[C++ Tests/cpp-tests ] Start image=axsauze/kompute-builder:0.2
[C++ Tests/cpp-tests ] ? docker run image=axsauze/kompute-builder:0.2 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[Python Tests/python-tests] ? docker run image=axsauze/kompute-builder:0.2 entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
...
O repositório contém testes de unidade para o código C ++ e Python e pode ser encontrado na pasta test/ e python/test .
Os testes são atualmente executados através do IC usando ações do GitHub. Ele usa as imagens encontradas no docker-builders/ .
Para minimizar os requisitos de hardware, os testes podem ser executados sem uma GPU, diretamente na CPU usando o SwiftShader.
Para obter mais informações sobre como o IC e os testes são configurados, você pode acessar a seção CI, Docker e testes na documentação.
Este projeto começou depois de ver que muitos projetos novos e de renomado ML & DL como Pytorch, Tensorflow, Alibaba DNN, Tencent NCNN - entre outros - se integraram ou estão procurando integrar o suporte à GPU Vulkan SDK para adicionar o suporte a GPU Vulkan para adicionar dispositivos móveis (e entre fornecedores).
O Vulkan SDK oferece uma ótima interface de baixo nível que permite otimizações altamente especializadas - no entanto, ele tem um custo de código altamente detalhado que requer 500-2000 linhas de código para começar a escrever código de aplicativo. Isso resultou em cada um desses projetos que tenham que implementar a mesma linha de base para abstrair os recursos relacionados a não computação do SDK Vulkan. Essa grande quantidade de placa de caldeira não padronizada pode resultar em transferência de conhecimento limitada, maior chance de introdução de bugs de implementação de estrutura exclusivos, etc.
No momento, estamos desenvolvendo o Kompute para não ocultar a interface SDK Vulkan (como é incrivelmente bem projetada), mas para aumentá -la com um foco direto nos recursos de computação GPU da Vulkan SDK. Este artigo fornece uma visão geral de alto nível das motivações do Kompute, juntamente com um conjunto de exemplos práticos que introduzem a computação da GPU e a arquitetura principal do Kompute.