top of page

Eseguire un modello gated di HuggingFace su una GPU che vuoi tu sul cloud Modal.com

5 giorni fa
Tempo di lettura: 6 min

Se sei curioso di capire come scaricare un modello gated da Hugging Face, farlo girare su una GPU in cloud e ottenere testo a partire da un semplice prompt, questo post è per te.

Ti guiderò passo-passo, spezzettando il codice in “pezzi Lego” e spiegando perché ogni riga è necessaria, quali alternative puoi provare e come evitare gli errori più comuni.

Nota: il modello usato nell’esempio è Qwen/Qwen3.8-Flash-Next, ma il procedimento vale per qualunque modello presente su Hugging Face.

🎯 Obiettivi del tutorial

  • Capire le parti fondamentali di un’app Modal: configurare dipendenze, secret (token) e GPU.

  • Scrivere la funzione di inference che genera testo.

  • Eseguire il tutto in locale oppure in un notebook Jupyter.

  • Sperimentare con varianti: CPU, modelli più piccoli, parametri di generazione, ecc.


1. Dipendenze e import – “Che roba devo installare?”


import os                  # legge le variabili d’ambiente (es. il token HF)
import modal               # SDK di Modal (client, decoratori, ecc.)
from modal import Image    # costruisce l’immagine Docker

🎯 Quick hint

modal è la libreria che ti permette di dichiarare funzioni remote, immagini Docker e secret senza scrivere un Dockerfile.

È il servizio dove puoi far girare i modelli da testare, configurando le GPU da utilizzare.

Prima visita: https://modal.com

  1. Registrati creando un account.

  2. In alto a destra clicca sul tuo avatar e scegli “Settings” (Impostazioni).

  3. Nella barra laterale sinistra seleziona “API Tokens”, poi premi “New Token” (Nuovo token).

Sul tuo PC esegui:

modal token set --token-id ak-qualcosaqui --token-secret as-qualcosaqui

2. Configurazione dell’app Modal – “Diamo un nome al progetto”


app = modal.App("app Modal")   # Nome dell’app (può essere qualsiasi stringa)

Un modal.App è un workspace che raggruppa funzioni, secret e immagini.

Il nome è solo un’etichetta leggibile da te; scegli qualcosa che ti ricordi facilmente, per esempio:

app = modal.App("mia-gpt-demo")

2.1 Definizione dell’immagine Docker

image = (
    Image.debian_slim()
    .pip_install(
        "torch",          # PyTorch → inferenza dei modelli
        "transformers",   # 🤗 Transformers → API high-level
        "accelerate",     # gestione device-mapping (GPU/CPU)
    )
)

🎯 Quick hint

  • Image.debian_slim() è la base leggera (Debian Slim) sulla quale installeremo le librerie Python necessarie: torch, transformers e accelerate.

  • Declarativo: non devi scrivere un Dockerfile; Modal lo crea in background.

  • Cache: la prima volta che avvii lo script, Modal scarica tutti i pacchetti e li mette in cache. Le esecuzioni successive partono quindi molto più velocemente. 🚀


2.2 Secret con il token di Hugging Face

secrets = [modal.Secret.from_name("huggingface-token")]

🎯 Quick hint

  • Una Secret è un dizionario cifrato di chiavi/valori, per esempio HF_TOKEN=hf_XXXXX.

  • Viene iniettata come variabile d’ambiente dentro il container remoto.

Perché usare due chiavi?

transformers nelle versioni più recenti legge HUGGINGFACE_HUB_TOKEN, mentre le versioni più vecchie cercano HF_TOKEN.

Inserendole entrambe garantiamo la massima compatibilità.


2.3 GPU e nome del modello

GPU = "T4"                                    # tipo di GPU da richiedere
MODEL_NAME = "Qwen/Qwen3.8-Flash-Next"        # percorso “owner/repo” su Hugging Face

🎯 Quick hint

  • GPU è opzionale: se la tua workspace non ha quota GPU, commenta gpu=GPU più avanti.

  • MODEL_NAME è il percorso completo che transformers.from_pretrained() comprende, per esempio:

MODEL_NAME = "meta-llama/Llama-3.2-3B"

3. La funzione di inference – “Il cuore dell’app”

@app.function(
    image=image,
    secrets=secrets,
    gpu=GPU,          # rimuovi se usi solo CPU
    timeout=1800,     # 30 min max per l’esecuzione
)
def generate(prompt: str) -> str:

3.1 Controllo del token


hf_token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_HUB_TOKEN")

if hf_token is None:
    raise RuntimeError(
        "Nessun token HF trovato – controlla la secret `huggingface-token`."
    )
  • Fail-fast: se il token manca, lo script si ferma subito invece di fallire più tardi durante il download del modello.


3.2 Import delle librerie nel container

from transformers import AutoTokenizer, AutoModelForCausalLM, set_seed

🎯 Quick hint

L’import avviene dentro la funzione perché il codice viene eseguito nel container remoto, non sul tuo PC.


3.3 Caricamento del tokenizer

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
  • AutoTokenizer.from_pretrained() scarica il tokenizer dal Hub.

  • Impostiamo pad_token e padding_side per evitare errori di allineamento, anche se in questo esempio eseguiamo una sola frase.


3.4 Caricamento del modello

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    device_map="auto",      # auto-sharding su GPU/CPU
)
  • device_map="auto" distribuisce i pesi tra GPU e CPU se il modello è troppo grande per essere caricato interamente sulla GPU.


3.5 Generazione del testo

set_seed(42)  # risultato deterministico (utile per debugging)

inputs = tokenizer.encode(
    prompt,
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    inputs,
    max_new_tokens=50
)

return tokenizer.decode(
    outputs[0],
    skip_special_tokens=True
)
  • .to("cuda") sposta il tensore sulla GPU; se usi solo CPU, sostituiscilo con .to("cpu").

  • max_new_tokens=50 è il numero massimo di token generati. Puoi alzarlo a 200 o più, a seconda del caso d’uso.

  • skip_special_tokens=True rimuove token speciali come <s>, </s> e simili dal risultato finale.


4. Esecuzione locale (o in notebook) – “Mettiamolo in moto”

if __name__ == "__main__":
    # stampa automatica del risultato di .remote()
    with modal.enable_output():
        # avvia il workspace temporaneo
        with app.run():
            result = generate.remote(
                "Never gonna give you up, never gonna"
            )
            print("\nGenerated text:\n", result)

4.1 Perché app.run()?


  • Crea il workspace temporaneo dove verranno spinte le funzioni remote.

  • Dentro il blocco with, qualsiasi funzione decorata con @app.function è pronta per essere chiamata.


4.2 modal.enable_output()


È una comodità: ogni chiamata .remote() stampa automaticamente il valore restituito sul terminale o nel notebook.

Se non lo usi, .remote() restituisce un ModalFuture (oggetto asincrono) e dovrai chiamare .get() per ottenere il risultato.


4.3 .remote() vs .remote().get()

Metodo

Cosa restituisce

Quando usarlo

generate.remote(prompt)

Stringa (se dentro enable_output) o ModalFuture

In notebook con enable_output()

generate.remote(prompt).get()

Stringa (blocca finché il future è risolto)

Quando vuoi gestire manualmente eccezioni o non usi enable_output()

Errore comune: chiamare .get() su una stringa, perché il risultato è già materializzato da enable_output().

5. Flusso completo – “Dalla preparazione all’output”


5.1 Pre-setup (una tantum)

  1. Crea la secret con il token:

modal secret create huggingface-token HF_TOKEN=hf_XXXXX HUGGINGFACE_HUB_TOKEN=hf_XXXXX
  1. Richiedi l’accesso al modello gated su Hugging Face cliccando “Request access”.

  2. Facoltativamente, configura il token di Modal con:

modal token set --token-id ... --token-secret ...

5.2 Esecuzione dello script

Il file:

  1. definisce app, immagine, secret, ecc.;

  2. entra nel blocco if name == "__main__":;

  3. avvia modal.enable_output() e app.run();

  4. esegue generate.remote(prompt), inviando una richiesta al cluster Modal.


A questo punto Modal:

  1. crea un container con l’immagine Docker definita;

  2. inietta le variabili d’ambiente (HF_TOKEN, HUGGINGFACE_HUB_TOKEN);

  3. controlla il token;

  4. scarica tokenizer e modello;

  5. carica il modello su GPU/CPU;

  6. genera il testo;

  7. restituisce la stringa.

modal.enable_output() stampa il risultato; la variabile result lo contiene anche per eventuali utilizzi successivi.


5.3 Output finale

Vedrai qualcosa del genere:

Generated text:
Never gonna give you up, never gonna ...

6. Possibili variazioni e consigli pratici

Scopo

Come modificare il codice

Testare su CPU

Commenta gpu=GPU nella decorazione e cambia .to("cuda") → .to("cpu").

Ridurre il tempo di download

Usa un modello più piccolo, per esempio facebook/opt-125m, oppure verifica la cache locale (~/.cache/huggingface).

Aumentare la lunghezza della risposta

Cambia max_new_tokens=50 → max_new_tokens=200 (o più).

Gestire eccezioni

Avvolgi la chiamata in try/except e usa .remote().get() per catturare modal.exceptions.RemoteError.

Parametri di generazione avanzati

Aggiungi temperature, top_p, do_sample, ecc.

Aggiungere altri segreti

secrets = [modal.Secret.from_name("huggingface-token"), modal.Secret.from_name("my-other-secret")]

Parallelizzare più prompt

Definisci una funzione batch_generate(prompts: List[str]) e sfrutta modal.map per eseguire le richieste in parallelo.

Esempio: parametri di generazione avanzati

outputs = model.generate(
    inputs,
    max_new_tokens=100,
    temperature=0.7,
    top_p=0.9,
)

7. Riepilogo – “Cosa fa ogni riga?”

import os, modal
from modal import Image                  # 0️⃣ import necessari

app = modal.App("qwen-gated")            # 1️⃣ workspace

image = (                                # 1.1️⃣ immagine Docker con pip install
    Image.debian_slim()
    .pip_install(
        "torch",
        "transformers",
        "accelerate"
    )
)

secrets = [
    modal.Secret.from_name("huggingface-token")
]                                       # 1.2️⃣ token HF

GPU = "T4"                              # 1.3️⃣ GPU scelta
MODEL_NAME = "Qwen/Qwen3.8-Flash-Next"  # 1.3️⃣ modello da scaricare


@app.function(
    image=image,
    secrets=secrets,
    gpu=GPU,
    timeout=1800
)                                       # 2️⃣ decoratore
def generate(prompt: str) -> str:       # funzione remota

    hf_token = (
        os.getenv("HF_TOKEN")
        or os.getenv("HUGGINGFACE_HUB_TOKEN")
    )

    if hf_token is None:
        raise RuntimeError(
            "Nessun token HF trovato …"
        )

    from transformers import (
        AutoTokenizer,
        AutoModelForCausalLM,
        set_seed
    )

    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
    tokenizer.pad_token = tokenizer.eos_token
    tokenizer.padding_side = "right"

    model = AutoModelForCausalLM.from_pretrained(
        MODEL_NAME,
        device_map="auto"
    )

    set_seed(42)

    inputs = tokenizer.encode(
        prompt,
        return_tensors="pt"
    ).to("cuda")

    outputs = model.generate(
        inputs,
        max_new_tokens=50
    )

    return tokenizer.decode(
        outputs[0],
        skip_special_tokens=True
    )


if __name__ == "__main__":              # 3️⃣ avvio script

    with modal.enable_output():

        with app.run():
            result = generate.remote(
                "Never gonna give you up, never gonna"
            )

            print(
                "\nGenerated text:\n",
                result
            )

8. Checklist finale – “Sono pronto a far girare tutto?”

✅ Verifica

Descrizione

Token Hugging Face

Creato con scope read e inserito in una secret chiamata huggingface-token.

Chiavi nella secret

Contiene almeno HF_TOKEN oppure HUGGINGFACE_HUB_TOKEN.

Accesso al modello gated

Hai cliccato “Request access” → “You have access”.

Quota GPU (opzionale)

Se usi una GPU, la workspace possiede una quota T4; altrimenti commenta gpu=GPU.

Python 3.10+ e Modal installato

pip install modal (e modal token set se usi la CLI).

Secret corretta

modal secret list mostra huggingface-token.

Docker cache

La prima esecuzione scarica circa 5–10 GB; le successive usano la cache.

Se tutti questi punti sono a posto, premi Run (oppure esegui python my_script.py) e guarda il tuo modello parlare! 🎉

🎉 Conclusioni

  • Modal ti permette di trasformare un semplice script Python in un servizio cloud pronto a scalare, senza scrivere Dockerfile o gestire server.

  • Con pochi passi — definire immagine, secret, GPU e funzione — puoi scaricare e usare modelli gated di Hugging Face, anche quelli da 3–4 GB.

  • Il codice è modularissimo: basta cambiare MODEL_NAME, il valore di max_new_tokens o aggiungere parametri per sperimentare molto rapidamente.

Prossimi passi consigliati: Crea una piccola API (con @app.function + FastAPI) per far parlare il modello via web. Prova a fare batch inference su una lista di prompt e osserva le performance su GPU vs CPU. Sperimenta con modelli di generazione immagini (Stable Diffusion) usando lo stesso schema Modal.

Divertiti a far parlare le tue AI e ricorda: con Modal la complessità resta nel cloud, mentre tu rimani concentrato sulla creatività! 🚀✨


 
 
 

Commenti


© 2024 texservice.tech   
-  mail: team@texservice.tech - WA: 353-468-73-15 -

bottom of page