Este artigo foi traduzido do documento em inglês Preparando seu acelerador de hardware para TVM com UMA
Os autores são Michael J. Klaiber , Christoph Gerum , Paul Palomero Bernardo .
Mais documentos da TVM em chinês podem ser acessados → TVM Chinese Station
Esta seção apresenta a Universal Modular Accelerator Interface (UMA). A UMA fornece uma API fácil de usar para integrar novos aceleradores de hardware ao TVM.
Este tutorial detalha como usar UMA para disponibilizar seu acelerador de hardware diretamente para TVM. Embora não haja uma solução única para esse problema, a UMA pretende fornecer uma API Python pura e estável para integrar vários tipos de aceleradores de hardware ao TVM.
Este tutorial apresentará a API UMA por meio de três casos de uso de complexidade crescente. Esses casos de uso apresentam três aceleradores de simulação Vanilla, Strawberry e Chocolate e os integram ao TVM usando UMA.
baunilha
Vanilla é um acelerador simples que consiste em uma matriz de MACs e não possui memória interna. Ele só pode lidar com a camada Conv2D, todas as outras camadas são executadas na CPU, enquanto também coordenam o vanilla. CPU e Vanilla compartilham memória.
A interface C do Vanilla vanilla_conv2dnchw(…) é usada para executar operações Conv2D (incluindo o mesmo preenchimento), recebe ponteiros para o mapa de recursos de entrada, pesos e resultados e as dimensões do Conv2D: oc, iw, ih, ic, kh e kw .
int vanilla_conv2dnchw(float* ifmap, float* weights, float* result, int oc, int iw, int ih, int ic, int kh, int kw);
O script uma_cli cria esqueletos de código com chamadas de API (UMA-API) para novos aceleradores.
Vanilla é usado assim: (–tutorial vanilla adiciona todos os arquivos adicionais necessários para esta parte do tutorial)
pip install inflection
cd $TVM_HOME/apps/uma
python uma_cli.py --add_hardware vanilla_accelerator --tutorial vanilla
uma_cli.py gera esses arquivos no diretório vanilla_accelerator.
backend.py
codegen.py
conv2dnchw.cc
passes.py
patterns.py
run.py
strategies.py
Vanilla back-end
O back-end gerado pelo vanilla está localizado em vanilla_accelerator/backend.py :
class VanillaAcceleratorBackend(UMABackend):
"""VanillaAccelerator 的 UMA 后端。"""
def __init__(self):
super().__init__()
self._register_pattern("conv2d", conv2d_pattern())
self._register_tir_pass(PassPhase.TIR_PHASE_0, VanillaAcceleratorConv2DPass())
self._register_codegen(fmt="c", includes=gen_includes)
@property
def target_name(self):
return "vanilla_accelerator"
Definir o padrão de migração
Para especificar a migração Conv2D para Vanilla, ela é descrita em vanilla_accelerator/patterns.py como um padrão de fluxo de dados de retransmissão (DFPattern).
def conv2d_pattern():
pattern = is_op("nn.conv2d")(wildcard(), wildcard())
pattern = pattern.has_attr({"strides": [1, 1]})
return pattern
Para mapear o operador Conv2D do gráfico de cálculo de entrada para a chamada de função subjacente do Vanilla vanilla_conv2dnchw(...), o passe TIR VanillaAcceleratorConv2DPass é registrado no VanillaAcceleratorBackend (discutido posteriormente).
Codegen
O arquivo vanilla_accelerator/codegen.py define o código C estático que é adicionado ao código C resultante gerado pelo C-Codegen da TVM em gen_includes com o propósito de incluir vanilla_conv2dnchw(), a biblioteca subjacente para Vanilla.
def gen_includes() -> str:
topdir = pathlib.Path(__file__).parent.absolute()
includes = ""
includes += f'#include "{topdir}/conv2dnchw.cc"'
return includes
Conforme mostrado no VanillaAcceleratorBackend acima, ele pode ser registrado com o UMA usando self._register_codegen.
self._register_codegen(fmt="c", includes=gen_includes)
Construir uma rede neural e executá-la no vanilla
Para demonstrar os recursos do UMA, o código C é gerado para uma única camada Conv2D e executado em um acelerador de baunilha. O arquivo vanilla_accelerator/run.py fornece uma demonstração da execução de uma camada Conv2D usando a API C do Vanilla.
def main():
mod, inputs, output_list, runner = create_conv2d()
uma_backend = VanillaAcceleratorBackend()
uma_backend.register()
mod = uma_backend.partition(mod)
target = tvm.target.Target("vanilla_accelerator", host=tvm.target.Target("c"))
export_directory = tvm.contrib.utils.tempdir(keep_for_debug=True).path
print(f"Generated files are in {export_directory}")
compile_and_run(
AOTModel(module=mod, inputs=inputs, outputs=output_list),
runner,
interface_api="c",
use_unpacked_api=True,
target=target,
test_dir=str(export_directory),
)
main()
Executar vanilla_accelerator/run.py irá gerar arquivos de saída em Model Library Format (MLF).
Resultado de saída:
Generated files are in /tmp/tvm-debug-mode-tempdirs/2022-07-13T13-26-22___x5u76h0p/00000
Confira os arquivos gerados:
Resultado de saída:
cd /tmp/tvm-debug-mode-tempdirs/2022-07-13T13-26-22___x5u76h0p/00000
cd build/
ls -1
codegen
lib.tar
metadata.json
parameters
runtime
src
Para avaliar o código C gerado, consulte codegen/host/src/default_lib2.c.
cd codegen/host/src/
ls -1
default_lib0.c
default_lib1.c
default_lib2.c
Em default_lib2.c, você pode ver que o código gerado chama a C-API do Vanilla e então executa uma camada Conv2D:
TVM_DLL int32_t tvmgen_default_vanilla_accelerator_main_0(float* placeholder, float* placeholder1, float* conv2d_nchw, uint8_t* global_workspace_1_var) {
vanilla_accelerator_conv2dnchw(placeholder, placeholder1, conv2d_nchw, 32, 14, 14, 32, 3, 3);
return 0;
}
morango
em breve
chocolate
em breve
Busque informações da comunidade
Se este tutorial não for adequado para o seu acelerador, adicione seus requisitos ao tópico UMA no fórum TVM. Ficaríamos felizes em estender este tutorial para fornecer mais orientações, por exemplo, como aproveitar a interface UMA para disponibilizar uma variedade maior de aceleradores de hardware AI diretamente para TVM.
Referência
[ UMA-RFC] UMA: Universal Modular Accelerator Interface , TVM RFC, junho de 2022.
[DFPattern] Correspondência de padrões no Relay
Baixe o código-fonte do Python: uma.py
Baixe o Jupyter Notebook: uma.ipynb
O texto acima é todo o conteúdo do documento, clique para ver mais documentos da TVM em chinês .