Connect with us

Configurando Treinamento, Ajuste Fino e Inferência de LLMs com GPUs NVIDIA e CUDA

Ferramentas de IA 101

Configurando Treinamento, Ajuste Fino e Inferência de LLMs com GPUs NVIDIA e CUDA

mm
Nvidia GPU in Ubuntu Basics of GPU Parallel Computing GPU Based LLM Training Machine

O campo da inteligência artificial (IA) testemunhou avanços notáveis nos últimos anos, e no coração disso está a poderosa combinação de unidades de processamento gráfico (GPUs) e plataforma de computação paralela.

Modelos como GPT, BERT, e mais recentemente Llama, Mistral são capazes de entender e gerar texto humano com fluência e coerência sem precedentes. No entanto, treinar esses modelos requer vastas quantidades de dados e recursos computacionais, tornando as GPUs e o CUDA ferramentas indispensáveis nessa empreitada.

Este guia abrangente o levará pelo processo de configuração de uma GPU NVIDIA no Ubuntu, cobrindo a instalação de componentes de software essenciais, como o driver NVIDIA, CUDA Toolkit, cuDNN, PyTorch e mais.

A Ascensão de Frameworks de IA Acelerados por CUDA

O aprendizado de máquina profundo acelerado por GPU foi impulsionado pelo desenvolvimento de frameworks de IA populares que aproveitam o CUDA para computação eficiente. Frameworks como TensorFlow, PyTorch e MXNet têm suporte integrado ao CUDA, permitindo a integração transparente da aceleração de GPU em pipelines de aprendizado de máquina.

De acordo com o Estudo de Desempenho de Produtos de Aprendizado de Máquina Profundo do Centro de Dados da NVIDIA, modelos de aprendizado de máquina profundo acelerados por CUDA podem alcançar um desempenho até 100 vezes mais rápido em comparação com implementações baseadas em CPU.

A tecnologia de GPU de Instância Múltipla (MIG) da NVIDIA, introduzida com a arquitetura Ampere, permite que um único GPU seja partitionado em várias instâncias seguras, cada uma com seus próprios recursos dedicados. Essa funcionalidade permite o compartilhamento eficiente de recursos de GPU entre vários usuários ou cargas de trabalho, maximizando a utilização e reduzindo os custos gerais.

Acelerando a Inferência de LLM com NVIDIA TensorRT

Embora as GPUs tenham sido instrumentais no treinamento de LLMs, a inferência eficiente é igualmente crucial para implantar esses modelos em ambientes de produção. O NVIDIA TensorRT, um otimizador e tempo de execução de inferência de aprendizado de máquina de alto desempenho, desempenha um papel vital na aceleração da inferência de LLM em GPUs habilitadas para CUDA.

De acordo com as medições de desempenho da NVIDIA, o TensorRT pode fornecer até 8 vezes mais desempenho de inferência e 5 vezes menos custo total de propriedade em comparação com a inferência baseada em CPU para grandes modelos de linguagem, como o GPT-3.

O compromisso da NVIDIA com as iniciativas de código aberto foi uma força motriz por trás da adoção generalizada do CUDA na comunidade de pesquisa de IA. Projetos como cuDNN, cuBLAS e NCCL estão disponíveis como bibliotecas de código aberto, permitindo que pesquisadores e desenvolvedores aproveitem todo o potencial do CUDA para seus modelos de aprendizado de máquina.

Instalação

Ao configurar o desenvolvimento de IA, usar os drivers e bibliotecas mais recentes nem sempre é a melhor escolha. Por exemplo, embora o driver NVIDIA mais recente (545.xx) suporte o CUDA 12.3, as bibliotecas PyTorch e outras podem não suportar ainda essa versão. Portanto, usaremos o driver de versão 535.146.02 com CUDA 12.2 para garantir a compatibilidade.

Etapa de Instalação

1. Instalar Driver NVIDIA

Primeiro, identifique o modelo da sua GPU. Para este guia, usamos a GPU NVIDIA. Visite a página de download do driver NVIDIA, selecione o driver apropriado para a sua GPU e anote a versão do driver.

Para verificar pacotes de GPU pré-construídos no Ubuntu, execute:


sudo ubuntu-drivers list --gpgpu

Reinicie o computador e verifique a instalação:


nvidia-smi

2. Instalar CUDA Toolkit

O CUDA Toolkit fornece o ambiente de desenvolvimento para criar aplicativos acelerados por GPU de alto desempenho.

Para uma configuração não LLM/deep learning, você pode usar:


sudo apt install nvidia-cuda-toolkit

No entanto, para garantir a compatibilidade com BitsAndBytes, seguiremos os passos abaixo:

[code language="BASH"]

git clone https://github.com/TimDettmers/bitsandbytes.git
cd bitsandbytes/
bash install_cuda.sh 122 ~/local 1

Verifique a instalação:


~/local/cuda-12.2/bin/nvcc --version

Defina as variáveis de ambiente:


export CUDA_HOME=/home/roguser/local/cuda-12.2/
export LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64
export BNB_CUDA_VERSION=122
export CUDA_VERSION=122

3. Instalar cuDNN

Baixe o pacote cuDNN do site de desenvolvedores da NVIDIA. Instale-o com:


sudo apt install ./cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb

Siga as instruções para adicionar o keyring:


sudo cp /var/cudnn-local-repo-ubuntu2204-8.9.7.29/cudnn-local-08A7D361-keyring.gpg /usr/share/keyrings/

Instale as bibliotecas cuDNN:


sudo apt update
sudo apt install libcudnn8 libcudnn8-dev libcudnn8-samples

4. Configurar Ambiente Virtual Python

O Ubuntu 22.04 vem com Python 3.10. Instale venv:


sudo apt-get install python3-pip
sudo apt install python3.10-venv

Crie e ative o ambiente virtual:


cd
mkdir test-gpu
cd test-gpu
python3 -m venv venv
source venv/bin/activate

5. Instalar BitsAndBytes a Partir do Código Fonte

Navegue até o diretório BitsAndBytes e construa a partir do código fonte:


cd ~/bitsandbytes
CUDA_HOME=/home/roguser/local/cuda-12.2/ \
LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64 \
BNB_CUDA_VERSION=122 \
CUDA_VERSION=122 \
make cuda12x

CUDA_HOME=/home/roguser/local/cuda-12.2/ \
LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64 \
BNB_CUDA_VERSION=122 \
CUDA_VERSION=122 \
python setup.py install

6. Instalar PyTorch

Instale o PyTorch com o seguinte comando:


pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

7. Instalar Hugging Face e Transformers

Instale as bibliotecas transformers e accelerate:


pip install transformers
pip install accelerate

O Poder do Processamento Paralelo

No núcleo, as GPUs são processadores paralelos altamente projetados para lidar com milhares de threads concorrentes de forma eficiente. Essa arquitetura as torna bem adaptadas para as tarefas computacionalmente intensivas envolvidas no treinamento de modelos de aprendizado de máquina profundo, incluindo LLMs. A plataforma CUDA, desenvolvida pela NVIDIA, fornece um ambiente de software que permite que os desenvolvedores aproveitem todo o potencial dessas GPUs, permitindo que eles escrevam código que possa aproveitar as capacidades de processamento paralelo do hardware.
Acelerando LLM Treinamento com GPUs e CUDA.

Treinar grandes modelos de linguagem é uma tarefa computacionalmente exigente que requer o processamento de vastas quantidades de dados de texto e a realização de numerosas operações matriciais. As GPUs, com seus milhares de núcleos e largura de banda de memória alta, são idealmente adaptadas para essas tarefas. Ao aproveitar o CUDA, os desenvolvedores podem otimizar seu código para aproveitar as capacidades de processamento paralelo das GPUs, reduzindo significativamente o tempo necessário para treinar LLMs.

Por exemplo, o treinamento do GPT-3, um dos maiores modelos de linguagem até o momento, foi possível graças ao uso de milhares de GPUs NVIDIA executando código otimizado para CUDA. Isso permitiu que o modelo fosse treinado em uma quantidade sem precedentes de dados, levando ao seu desempenho impressionante em tarefas de linguagem natural.


import torch
import torch.nn as nn
import torch.optim as optim
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Carregue o modelo GPT-2 pré-treinado e o tokenizador
modelo = GPT2LMHeadModel.from_pretrained('gpt2')
tokenizador = GPT2Tokenizer.from_pretrained('gpt2')

# Mova o modelo para a GPU, se disponível
dispositivo = torch.device("cuda" if torch.cuda.is_available() else "cpu")
modelo = modelo.to(dispositivo)

# Defina os dados de treinamento e os hiperparâmetros
dados_treinamento = [...] # Seus dados de treinamento
tamanho_lote = 32
num_epocas = 10
taxa_aprendizado = 5e-5

# Defina a função de perda e o otimizador
criterio = nn.CrossEntropyLoss()
otimizador = optim.Adam(modelo.parameters(), lr=taxa_aprendizado)

# Loop de treinamento
for epoca in range(num_epocas):
for i in range(0, len(dados_treinamento), tamanho_lote):
# Prepare as sequências de entrada e saída
entradas, saidas = dados_treinamento[i:i+tamanho_lote]
entradas = tokenizador(entradas, return_tensors="pt", padding=True)
entradas = entradas.to(dispositivo)
saidas = saidas.to(dispositivo)

# Passo para a frente
saidas_modelo = modelo(**entradas, labels=saidas)
perda = saidas_modelo.loss

# Passo para trás e otimização
otimizador.zero_grad()
perda.backward()
otimizador.step()

print(f'Epoca {epoca+1}/{num_epocas}, Perda: {perda.item()}')

Neste exemplo de código, demonstramos o treinamento de um modelo de linguagem GPT-2 usando PyTorch e GPUs CUDA. O modelo é carregado na GPU (se disponível), e o loop de treinamento aproveita o paralelismo das GPUs para realizar passos para a frente e para trás de forma eficiente, acelerando o processo de treinamento.

Bibliotecas Aceleradas por CUDA para Aprendizado de Máquina Profundo

Além da própria plataforma CUDA, a NVIDIA e a comunidade de código aberto desenvolveram uma variedade de bibliotecas aceleradas por CUDA que permitem a implementação eficiente de modelos de aprendizado de máquina profundo, incluindo LLMs. Essas bibliotecas fornecem implementações otimizadas de operações comuns, como multiplicações de matrizes, convoluções e funções de ativação, permitindo que os desenvolvedores se concentrem na arquitetura do modelo e no processo de treinamento em vez de otimizações de baixo nível.

Uma dessas bibliotecas é a cuDNN (CUDA Deep Neural Network library), que fornece implementações altamente ajustadas de rotinas padrão usadas em redes neurais profundas. Ao aproveitar a cuDNN, os desenvolvedores podem acelerar significativamente o treinamento e a inferência de seus modelos, alcançando ganhos de desempenho de até várias ordens de magnitude em comparação com implementações baseadas em CPU.


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.cuda.amp import autocast

class BlocoResidual(nn.Module):
def __init__(self, canais_entrada, canais_saida, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(canais_entrada, canais_saida, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(canais_saida)
self.conv2 = nn.Conv2d(canais_saida, canais_saida, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(canais_saida)
self.atalho = nn.Sequential()
if stride != 1 or canais_entrada != canais_saida:
self.atalho = nn.Sequential(
nn.Conv2d(canais_entrada, canais_saida, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(canais_saida))

def forward(self, x):
with autocast():
saida = F.relu(self.bn1(self.conv1(x)))
saida = self.bn2(self.conv2(saida))
saida += self.atalho(x)
saida = F.relu(saida)
return saida

Neste trecho de código, definimos um bloco residual para uma rede neural convolucional (CNN) usando PyTorch. O gerenciador de contexto autocast do PyTorch’s Automatic Mixed Precision (AMP) é usado para habilitar o treinamento de precisão mista, que pode fornecer ganhos de desempenho significativos em GPUs CUDA enquanto mantém a alta precisão. A função F.relu é otimizada pela cuDNN, garantindo a execução eficiente em GPUs.

Treinamento Multi-GPU e Distribuído para Escalabilidade

À medida que os LLMs e os modelos de aprendizado de máquina profundo continuam a crescer em tamanho e complexidade, os requisitos computacionais para treinar esses modelos também aumentam. Para atender a esse desafio, pesquisadores e desenvolvedores têm recorrido a técnicas de treinamento multi-GPU e distribuído, que permitem que eles aproveitem o poder de processamento combinado de várias GPUs em várias máquinas.

O CUDA e as bibliotecas associadas, como a NCCL (NVIDIA Collective Communications Library), fornecem primitivas de comunicação eficientes que permitem a transferência de dados e a sincronização transparentes entre várias GPUs, permitindo o treinamento distribuído em uma escala sem precedentes.

</pre>
import torch.distributed as dist

from torch.nn.parallel import DistributedDataParallel as DDP

# Inicialize o treinamento distribuído
dist.init_process_group(backend='nccl', init_method='...')
rank_local = dist.get_rank()
torch.cuda.set_device(rank_local)

# Crie o modelo e mova para a GPU
modelo = MeuModelo().cuda()

# Embale o modelo com DDP
modelo = DDP(modelo, device_ids=[rank_local])

# Loop de treinamento (distribuído)
for epoca in range(num_epocas):
for dados in carregador_treinamento:
entradas, saidas = dados
entradas = entradas.cuda(non_blocking=True)
saidas = saidas.cuda(non_blocking=True)

saidas_modelo = modelo(entradas)
perda = criterio(saidas_modelo, saidas)

otimizador.zero_grad()
perda.backward()
otimizador.step()

Neste exemplo, demonstramos o treinamento distribuído usando o módulo DistributedDataParallel (DDP) do PyTorch. O modelo é embrulhado com o DDP, que lida automaticamente com o paralelismo de dados, a sincronização de gradientes e a comunicação entre várias GPUs usando a NCCL. Essa abordagem permite a escalabilidade eficiente do processo de treinamento em várias máquinas, permitindo que os pesquisadores e desenvolvedores treinem modelos maiores e mais complexos em um tempo razoável.

Implantando Modelos de Aprendizado de Máquina com CUDA

Embora as GPUs e o CUDA tenham sido usados principalmente para treinar modelos de aprendizado de máquina, eles também são cruciais para a inferência eficiente e a implantação. À medida que os modelos de aprendizado de máquina se tornam cada vez mais complexos e intensivos em recursos, a aceleração de GPU é essencial para alcançar o desempenho em tempo real em ambientes de produção.

O TensorRT da NVIDIA é um otimizador e tempo de execução de inferência de aprendizado de máquina de alto desempenho que fornece baixa latência e alto throughput na inferência em GPUs habilitadas para CUDA. O TensorRT pode otimizar e acelerar modelos treinados em frameworks como TensorFlow, PyTorch e MXNet, permitindo a implantação eficiente em várias plataformas, desde sistemas embarcados até centros de dados.


import tensorrt as trt

# Carregue o modelo pré-treinado
modelo = load_model(...)

# Crie o mecanismo do TensorRT
logger = trt.Logger(trt.Logger.INFO)
construtor = trt.Builder(logger)
rede = construtor.create_network()
parser = trt.OnnxParser(rede, logger)

# Analise e otimize o modelo
sucesso = parser.parse_from_file(model_path)
engine = construtor.build_cuda_engine(rede)

# Execute a inferência na GPU
contexto = engine.create_execution_context()
entradas, saidas, bindings, stream = allocate_buffers(engine)

# Defina os dados de entrada e execute a inferência
set_input_data(entradas, input_data)
contexto.execute_async_v2(bindings=bindings, stream_handle=stream.ptr)

# Processo de saída
# ...

Neste exemplo, demonstramos o uso do TensorRT para implantar um modelo de aprendizado de máquina pré-treinado em uma GPU habilitada para CUDA. O modelo é primeiro analisado e otimizado pelo TensorRT, que gera um mecanismo de inferência altamente otimizado personalizado para o modelo e o hardware específico. Esse mecanismo pode então ser usado para realizar a inferência eficiente na GPU, aproveitando o CUDA para computação acelerada.

Conclusão

A combinação de GPUs e CUDA tem sido instrumental nos avanços em grandes modelos de linguagem, visão computacional, reconhecimento de fala e vários outros domínios do aprendizado de máquina. Ao aproveitar as capacidades de processamento paralelo das GPUs e as bibliotecas otimizadas fornecidas pelo CUDA, os pesquisadores e desenvolvedores podem treinar e implantar modelos cada vez mais complexos com alta eficiência.

À medida que o campo da IA continue a evoluir, a importância das GPUs e do CUDA apenas crescerá. Com hardware e otimizações de software ainda mais poderosas, podemos esperar ver avanços ainda maiores no desenvolvimento e na implantação de sistemas de IA, empurrando os limites do que é possível.

Eu passei os últimos cinco anos me imergindo no fascinante mundo de Aprendizado de Máquina e Aprendizado Profundo. Minha paixão e especialização me levaram a contribuir para mais de 50 projetos diversificados de engenharia de software, com um foco particular em IA/ML. Minha curiosidade contínua também me atraiu para o Processamento de Linguagem Natural, um campo que estou ansioso para explorar mais.