Pular para o conteúdo principal

Llama de ajuste fino 4: Um guia com projeto de demonstração

Saiba como fazer o ajuste fino do modelo Llama 4 Scout Instruct em um conjunto de dados de raciocínio médico usando GPUs RunPod.
Atualizado 10 de abr. de 2025  · 12 min lido

A Meta acaba de lançar a série Llama 4, que inclui dois modelos avançados: Llama 4 Scout e Llama 4 Maverick. Ambos são de peso aberto, mas o ajuste fino do Llama 4 Scout requer quatro GPUs H100, e o Llama 4 Maverick precisa de oito. Isso significa que somente empresas com recursos substanciais podem se dar ao luxo de ajustá-los.

Neste blog, mostrarei a você como fazer o ajuste fino do Llama 4 Scout por apenas US$ 10 usando a plataforma RunPod. Você aprenderá:

  1. Como configurar o RunPod e criar um pod multi-GPU
  2. Como carregar o modelo e o tokenizador
  3. Como preparar e processar o conjunto de dados
  4. Como configurar o treinador e testar o modelo
  5. Como comparar modelos
  6. Como você pode salvar o modelo no repositório Hugging Face?

Mantemos nossos leitores atualizados sobre as últimas novidades em IA enviando o The Median, nosso boletim informativo gratuito de sexta-feira que detalha as principais histórias da semana. Inscreva-se e fique atento em apenas alguns minutos por semana:

Configuração do Runpod

Vá para o RunPod e crie uma conta. Depois disso, vá para a seção Runpod Billing (Cobrança da Runpod) e adicione US$ 25 usando o cartão de crédito. Você também pode pagar com criptomoeda.

faturamento do runpod para ajustar a lhama 4

Navegue até a seção Meus pods para começar a configurar seu pod. O pod funciona como um servidor virtual que fornece a você as CPUs, GPUs, memória e armazenamento necessários para suas tarefas.

runpods meu menu de pods

Selecionaremos 3 GPUs H200 SXM, que fornecerão memória suficiente para carregar o modelo , quantizar e fazer o ajuste fino no novo conjunto de dados. Como alternativa, você pode usar a função Unsloth para executar o modelo em um único H100 - no entanto, essa abordagem não funcionou bem para mim.

Para configurar seu pod, siga estas etapas:

  1. Selecione a GPU H200 SMX.
  2. Dê um nome à sua cápsula.
  3. Escolha o modelo "RunPod PyTorch 2.8.0".
  4. Altere a contagem de GPUs para 3.
  5. Clique no botão "Deploy On-Demand".

implantação do runpod sob demanda para o ajuste fino do llama 4

Editaremos o nosso pod aumentando o tamanho do disco do contêiner para 300 GB e adicionando a variável de ambiente HF_TOKEN, que é o token de acesso Hugging Face que você usa. Esse token é essencial para carregar e salvar o modelo com eficiência.

runpod adicionando tokens de Hugging Face

Você levará algum tempo para configurar o contêiner. Quando tudo estiver configurado, clique no botão "Connect" (Conectar) e inicie a instância do JupyterLab.

runpod criando uma instância do jupyterlab

Crie um novo notebook e comece a usar esse novo ambiente, semelhante à sua configuração local.

Criação de instância de laboratório jupyter a partir do runpod

Ajuste fino do Llama 4 usando o conjunto de dados de raciocínio médico

Nesta seção, aprenderemos a lidar com desafios comuns ao fazer o ajuste fino do novo modelo Llama 4, como problemas de falta de memória e bugs na biblioteca Transformers. Também abordaremos como carregar, ajustar e salvar o adaptador LoRA sem problemas. Ao seguir essas etapas, você pode se concentrar no processo de ajuste fino sem se preocupar com obstáculos técnicos.

1. Configuração

Instalaremos os pacotes Python necessários para que você possa fazer o ajuste fino dos modelos de linguagem grandes. 

Observação:

  • A versão mais recente da biblioteca Transformers tem um bug de incompatibilidade de incorporação que foi relatado no GitHub que foi relatado no repositório do GitHub. Para evitar esse problema, instalaremos a versão 4.51.0. 
  • O servidor Hugging Face fornece acesso à integração xet que é mais rápida do que Git-LFS. Essa integração aumentará a velocidade de download em três vezes.
%%capture
!pip install transformers==4.51.0
%pip install -U datasets 
%pip install -U accelerate 
%pip install -U peft 
%pip install -U trl 
%pip install -U bitsandbytes
%pip install huggingface_hub[hf_xet]

Carregue a chave de API da variável de ambiente variável de ambiente para que você faça login no Hugging Face. Ao fazer login, você pode obter acesso a modelos fechados e também salvar modelos e tokenizadores ajustados.

from huggingface_hub import login
import os

hf_token = os.environ.get("HF_TOKEN")
login(hf_token)

2. Carregando o modelo e o tokenizador

Carregue o Llama-4-Scout-17B-16E-Instruct com quantização de 4 bits para uso eficiente da memória. Certifique-se de que você definiu device_map como auto para usar todas as três GPUs H200. 

Observação: Verifique se você tem acesso ao modelo, pois esse modelo é fechado e exige que você preencha o formulário acessando o site meta-llama/Llama-4-Scout-17B-16E-Instruct URL.

import os
import torch
from transformers import AutoTokenizer, Llama4ForConditionalGeneration, BitsAndBytesConfig


model_id = "meta-llama/Llama-4-Scout-17B-16E-Instruct"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=False,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)


model = Llama4ForConditionalGeneration.from_pretrained(
    model_id,
    device_map="auto", 
    torch_dtype=torch.bfloat16,
    quantization_config=bnb_config,
    trust_remote_code=True,
)

model.config.use_cache = False
model.config.pretraining_tp = 1

Saída do jupyterlab ao carregar o modelo de batedor llama 4

Também carregaremos o tokenizador usando o mesmo ID de modelo.

# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)

Ao executar o comando abaixo, você pode verificar a quantidade de memória restante para configurar o treinador e ajustar o modelo.

!nvidia-smi

Saída do jupyterlab para mostrar quanta memória nos resta para o ajuste fino da lhama 4

3. Carregamento e processamento dos dados

Criaremos um estilo de prompt para o modelo, incluindo um prompt do sistema com espaços reservados para a pergunta, cadeia de pensamentoe resposta. Esse prompt ajudará o modelo a pensar passo a passo e a dar respostas claras e precisas.

train_prompt_style = """Below is an instruction that describes a task, paired with an input that provides further context. 
Write a response that appropriately completes the request. 
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning. 
Please answer the following medical question. 

### Question:
{}

### Response:
<think>
{}
</think>
{}"""

Em seguida, criaremos a função Python para gerar a coluna “text” usando o estilo do prompt de treinamento e as colunas do conjunto de dados.

EOS_TOKEN = tokenizer.eos_token  # Must add EOS_TOKEN

def formatting_prompts_func(examples):
    inputs = examples["Question"]
    complex_cots = examples["Complex_CoT"]
    outputs = examples["Response"]
    texts = []
    for question, cot, response in zip(inputs, complex_cots, outputs):
        # Append the EOS token to the response if it's not already there
        if not response.endswith(tokenizer.eos_token):
            response += tokenizer.eos_token
        text = train_prompt_style.format(question, cot, response)
        texts.append(text)
    return {"text": texts}

Carregaremos as primeiras 500 amostras do arquivo FreedomIntelligence/medical-o1-reasoning-SFT disponíveis no Hugging Face Hub e, em seguida, aplicaremos a função formatting_prompts_func para criar a coluna “text”.

from datasets import load_dataset


dataset = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT","en", split = "train[0:500]",trust_remote_code=True)
dataset = dataset.map(formatting_prompts_func, batched = True,)
dataset["text"][0]

A coluna "texto" tem um prompt do sistema, instruções, pergunta, cadeia de pensamento e a resposta. 

Saída do laboratório jupyter ao configurar o llama 4 para ajuste fino

O novo instrutor do STF não aceita tokenizadores, portanto, converteremos o tokenizador em um agrupador de dados e forneceremos ao instrutor o agrupador de dados em vez do tokenizador.

from transformers import DataCollatorForLanguageModeling

data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer,
    mlm=False
)

4. Inferência de modelo antes do ajuste fino

Agora, criaremos um estilo de solicitação de teste que inclui tudo do estilo de solicitação de treinamento, exceto a cadeia de pensamento e a resposta.

prompt_style = """Below is an instruction that describes a task, paired with an input that provides further context. 
Write a response that appropriately completes the request. 
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning. 
Please answer the following medical question. 

### Question:
{}

### Response:
<think>{}"""

Pegaremos a primeira pergunta do conjunto de dados, a converteremos em um prompt usando o estilo de prompt de teste e, em seguida, a prepararemos para que o modelo gere a resposta.

question = dataset[0]['Question']
inputs = tokenizer(
    [prompt_style.format(question, "") + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

A cadeia de raciocínio do modelo é longa, e a resposta que ele fornece é bastante breve, diferindo significativamente do conjunto de dados.

<think>assistant

To approach this question, let's break down the key elements provided and analyze them step by step:

1. **Symptoms**: The patient experiences involuntary urine loss during activities like coughing or sneezing but has no leakage at night. This pattern of urinary incontinence is suggestive of stress urinary incontinence (SUI), which is characterized by the involuntary leakage of urine on effort or exertion, or on sneezing or coughing.

2. **Diagnostic Tests Mentioned**:
   - **Gynecological Exam**: This is likely performed to assess the pelvic anatomy, including the position and support of the urethra and bladder neck, and to check for any pelvic organ prolapse.
   - **Q-tip Test**: This test is used to assess urethral mobility. A Q-tip (cotton swab) is inserted into the urethra, and its angle of movement is measured. Increased mobility (an angle change of more than 30 degrees) is often associated with stress urinary incontinence.

3. **Cystometry (Cystometrogram)**: This test measures the pressure within the bladder during filling and helps assess bladder function, including the residual volume and detrusor muscle contractions. The detrusor muscle is the smooth muscle in the wall of the bladder that contracts to allow urine to be expelled.

Given that the patient likely has stress urinary incontinence (SUI) based on her symptoms:
- **Residual Volume**: In patients with SUI, the bladder usually functions normally, and thus, the residual volume (the amount of urine left in the bladder after urination) is typically not significantly affected. Therefore, one would expect the residual volume to be normal or near-normal.
  
- **Detrusor Contractions**: In SUI, the problem primarily lies with the urethral sphincter mechanism and support rather than with the detrusor muscle itself. Hence, detrusor contractions are usually normal. The patient does not have symptoms suggestive of an overactive bladder (like urgency, urge incontinence, or nocturia), which would be more indicative of detrusor overactivity.

Based on this analysis, cystometry in this patient would most likely reveal:
- A **normal residual volume**, as her symptoms do not suggest a problem with bladder emptying.
- **Normal detrusor contractions**, as her condition (stress urinary incontinence) primarily involves issues with urethral support and continence mechanisms rather than detrusor function.

Therefore, cystometry would likely show that she has a normal residual volume and normal detrusor contractions. 

</think>

The final answer is: $\boxed{Normal residual volume and normal detrusor contractions}$

5. Implementação do LoRA

Agora, implementaremos o LoRA (Low-Rank Adaptation) para um ajuste fino eficiente dos parâmetros e o aplicaremos ao modelo. LoRA é uma técnica projetada para fazer o ajuste fino de grandes modelos de linguagem congelando a maioria dos parâmetros do modelo e treinando apenas um pequeno subconjunto de parâmetros adicionais.

Essa abordagem é eficiente em termos de memória, mais rápida e econômica e, ao mesmo tempo, mantém uma alta precisão comparável ao ajuste fino completo.

from peft import LoraConfig, get_peft_model

# LoRA config
peft_config = LoraConfig(
    lora_alpha=16,                           # Scaling factor for LoRA
    lora_dropout=0.05,                       # Add slight dropout for regularization
    r=64,                                    # Rank of the LoRA update matrices
    bias="none",                             # No bias reparameterization
    task_type="CAUSAL_LM",                   # Task type: Causal Language Modeling
    target_modules=[
        "q_proj",
        "k_proj",
        "v_proj",
        "o_proj",
        "gate_proj",
        "up_proj",
        "down_proj",
    ],  # Target modules for LoRA
)

model = get_peft_model(model, peft_config)

Agora vamos configurar e inicializar o SFTTrainer (Supervised Fine-Tuning Trainer), fornecendo a ele o conjunto de dados, o modelo, o coletor de dados, os argumentos de treinamento e a configuração do LoRA. O SFTTrainer simplifica o processo de ajuste fino ao integrar todos esses componentes em um único fluxo de trabalho otimizado, facilitando o treinamento de grandes modelos de linguagem, como o Llama 4, com o LoRA.

from trl import SFTTrainer
from transformers import TrainingArguments


# Training Arguments
training_arguments = TrainingArguments(
    output_dir="output",
    per_device_train_batch_size=1,
    per_device_eval_batch_size=1,
    gradient_accumulation_steps=2,
    optim="paged_adamw_32bit",
    num_train_epochs=1,
    logging_steps=0.2,
    warmup_steps=10,
    logging_strategy="steps",
    learning_rate=2e-4,
    fp16=False,
    bf16=False,
    group_by_length=True,
    report_to="none"
)

# Initialize the Trainer
trainer = SFTTrainer(
    model=model,
    args=training_arguments,
    train_dataset=dataset,
    peft_config=peft_config,
    data_collator=data_collator,
)

6. Treinamento de modelos

Comece o processo de treinamento executando o seguinte comando:

trainer.train()

Se você mudar para o painel do Pod, verá que o instrutor está utilizando todas as três GPUs para treinamento.

Painel do runpod durante o ajuste fino do Lhama 4

Levamos apenas 7 minutos para ajustar o modelo e, no total, 30 minutos para executar todo o projeto do início ao fim.

jupyterlab output during fine-tuning llama 4

7. Inferência de modelo após o ajuste fino

Agora, testaremos o modelo com ajuste fino usando a mesma amostra de antes para comparar seu desempenho após o ajuste fino. Isso nos ajudará a avaliar o quanto o modelo melhorou em termos de raciocínio e geração de respostas detalhadas.

question = dataset[0]['Question']
inputs = tokenizer(
    [prompt_style.format(question, "") + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

O processo de raciocínio do modelo é preciso, e a resposta é detalhada e lógica:

<think>
Alright, let's think about what's going on with this 61-year-old woman. She's experiencing involuntary urine loss when she coughs or sneezes, which is classic for stress urinary incontinence. But there's no leakage at night, which is interesting. That detail might help us rule out other types of incontinence, like overactive bladder.

Now, let's think about the tests she's had. The gynecological exam and the Q-tip test are usually done to check for any anatomical issues that could be causing her symptoms. If the Q-tip test is positive, it means there's some mobility in the urethra, which can be a sign of stress incontinence.

Okay, so we've got stress urinary incontinence in mind. What does cystometry tell us? It's a test that looks at how well the bladder functions by measuring pressure and volume during filling and voiding. 

For someone with stress incontinence, the cystometry would probably show that her bladder is doing its job properly. The residual volume, which is the amount of urine left in the bladder after she pees, should be normal. This means her bladder is emptying well enough.

Also, with stress incontinence, you wouldn't expect to see abnormal detrusor contractions. These are like muscle spasms in the bladder that can cause urgency and urge incontinence. But in stress incontinence, the problem is more about the urethral support and pressure control during activities, not the bladder muscle itself.

So, putting it all together, the cystometry should show a normal residual volume and no abnormal detrusor contractions. This fits perfectly with what we know about stress urinary incontinence. Yep, that's what I'd expect to see in this case.
</think>
In this scenario, the cystometry would most likely reveal a normal residual volume and no abnormal detrusor contractions. This is because stress urinary incontinence, as indicated by the patient's symptoms and the positive Q-tip test, is primarily related to issues with urethral support and pressure control during activities, not with the bladder muscle's function or emptying ability.

Vamos testar o modelo em uma amostra diferente do conjunto de dados para avaliar melhor seu desempenho.

question = dataset[10]['Question']
inputs = tokenizer(
    [prompt_style.format(question, "") + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

A resposta é lógica, detalhada e demonstra a capacidade do modelo de aplicar o raciocínio médico de forma eficaz:

<think>
Alright, let's break this down. So, we have a 42-year-old guy who's just recovered from pneumonia, and his T3 levels are low. Now, his TSH is slightly elevated at 4.7 µU/mL, which isn't too high but is definitely not normal. T4 is at 6 µg/dL, which is kind of in the middle range, and T3 is 68 ng/dL, which is low. Hmm, these numbers make me think of a condition called sick euthyroid syndrome. It's like when the body gets sick, the thyroid function tests can get all wonky, even if the thyroid itself is working fine.

In this syndrome, T3 usually drops first, and T4 might stay normal or even rise a bit. This makes sense here because his T3 is low, but T4 is still around 6 µg/dL. Now, the TSH is slightly elevated, which is a bit puzzling, but in sick euthyroid syndrome, TSH can be normal or even slightly elevated. So, this fits.

But wait, what about the other hormones? In sick euthyroid syndrome, we often see an increase in reverse T3 (rT3). This is because the body might convert T4 to rT3 instead of T3 when it's stressed. So, if I were to guess, I'd say the reverse T3 level is probably elevated in this case.

This all makes sense because the clinical picture and lab results are lining up nicely with sick euthyroid syndrome. So, if I had to pick an additional hormone that's likely elevated, it would be the reverse T3. Yeah, that seems to fit the scenario perfectly.
</think>
In this scenario, considering the clinical context of a 42-year-old man recovering from pneumonia with decreased T3 levels and slightly elevated TSH, along with normal T4 levels, the likely condition is sick euthyroid syndrome. In this condition, the body often converts T4 to reverse T3 (rT3) instead of T3 during stress or illness. Therefore, the additional hormone level that is likely to be elevated in this patient is reverse T3 (rT3).

8. Salvando o modelo

Agora, enviaremos o modelo ajustado (adaptador LoRA) e o tokenizador para o Hugging Face Hub. Esse processo criará automaticamente um repositório para você e carregará todos os arquivos de modelo necessários, tornando o modelo acessível publicamente para uso ou compartilhamento posterior.

model.push_to_hub("Llama-4-Scout-17B-16E-Instruct-Medical-ChatBot")
tokenizer.push_to_hub("Llama-4-Scout-17B-16E-Instruct-Medical-ChatBot")

Saída do jupyter ao salvar o modelo de lhama 4 com ajuste fino

Quando o processo estiver concluído, você poderá acessar o repositório de modelos no seguinte link: kingabzpro/Llama-4-Scout-17B-16E-Instruct-Medical-ChatBot

Aqui está o notebook complementar que contém todo o código necessário, saídas e instruções detalhadas para ajudar você a ajustar o seu próprio modelo Llama 4.

Conclusão

A criação deste tutorial foi uma experiência desafiadora, porém gratificante. Ao trabalhar com o Llama 4, encontrei vários problemas que destacaram as complexidades do uso desse modelo. Na minha opinião, o Llama 4 ainda não está totalmente otimizado para uso generalizado, especialmente para pessoas que dependem de GPUs de nível de consumidor. Aqui estão alguns dos principais desafios que enfrentei:

  1. Problemas de falta de memória: O Llama 4 requer uma VRAM significativa, o que dificulta a execução ou o ajuste fino em GPUs padrão.
  2. Bugs na biblioteca do Transformers: Houve vários problemas de compatibilidade e bugs na biblioteca ao trabalhar com o Llama 4, o que exigiu solução de problemas e soluções alternativas.
  3. Desafios de quantização: Os modelos quantizados disponíveis no Hugging Face não são compatíveis e exigem muita VRAM. 
  4. Complexidade da configuração: A configuração do ambiente para dar suporte aos novos mecanismos consumiu muito tempo e exigiu um profundo conhecimento do Pytorch e do ecossistema Hugging Face.

Apesar desses desafios, se você seguir este guia passo a passo, poderá fazer o ajuste fino do Llama 4 em qualquer novo conjunto de dados com relativa facilidade.

Para saber mais sobre a Llama 4, confira estes recursos:


Abid Ali Awan's photo
Author
Abid Ali Awan
LinkedIn
Twitter

Sou um cientista de dados certificado que gosta de criar aplicativos de aprendizado de máquina e escrever blogs sobre ciência de dados. No momento, estou me concentrando na criação e edição de conteúdo e no trabalho com modelos de linguagem de grande porte.

Tópicos

Aprenda IA com estes cursos!

Programa

Associate AI Engineer for Developers

0 min
Learn how to integrate AI into software applications using APIs and open-source libraries. Start your journey to becoming an AI Engineer today!
Ver detalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado

Tutorial

Ajuste fino do Llama 3.1 para classificação de textos

Comece a usar os novos modelos Llama e personalize o Llama-3.1-8B-It para prever vários distúrbios de saúde mental a partir do texto.
Abid Ali Awan's photo

Abid Ali Awan

13 min

Tutorial

Guia para iniciantes do LlaMA-Factory WebUI: Ajuste fino dos LLMs

Saiba como fazer o ajuste fino dos LLMs em conjuntos de dados personalizados, avaliar o desempenho e exportar e servir modelos com facilidade usando a estrutura com pouco ou nenhum código do LLaMA-Factory.
Abid Ali Awan's photo

Abid Ali Awan

12 min

Tutorial

Guia de Introdução ao Ajuste Fino de LLMs

O ajuste fino dos grandes modelos de linguagem (LLMs, Large Language Models) revolucionou o processamento de linguagem natural (PLN), oferecendo recursos sem precedentes em tarefas como tradução de idiomas, análise de sentimentos e geração de textos. Essa abordagem transformadora aproveita modelos pré-treinados como o GPT-2, aprimorando seu desempenho em domínios específicos pelo processo de ajuste fino.
Josep Ferrer's photo

Josep Ferrer

11 min

Tutorial

Llama.cpp Tutorial: Um guia completo para inferência e implementação eficientes de LLM

Este guia abrangente sobre o Llama.cpp guiará você pelos fundamentos da configuração do seu ambiente de desenvolvimento, compreendendo suas principais funcionalidades e aproveitando seus recursos para solucionar casos de uso no mundo real.
Zoumana Keita 's photo

Zoumana Keita

11 min

Tutorial

DCLM-7B da Apple: Configuração, exemplo de uso, ajuste fino

Comece a usar o modelo de linguagem grande DCLM-7B da Apple e saiba como configurá-lo, usá-lo e ajustá-lo para tarefas específicas.
Dimitri Didmanidze's photo

Dimitri Didmanidze

9 min

Tutorial

Como fazer o ajuste fino do GPT 3.5: Liberando todo o potencial da IA

Explore o GPT-3.5 Turbo e descubra o potencial transformador do ajuste fino. Saiba como personalizar esse modelo de linguagem avançado para aplicativos de nicho, aprimorar seu desempenho e entender os custos associados, a segurança e as considerações de privacidade.
Moez Ali's photo

Moez Ali

11 min

Ver maisVer mais