Trackio documentation

Artefactos

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Artefactos

Introducción

Un artifact es un conjunto de archivos con nombre y versión asociado a un proyecto: un modelo entrenado, un conjunto de datos o una serie de resultados de evaluación. Registrar archivos como artifacts (en lugar de dejarlos en el disco) te permite:

  • Versionado — cada vez que registras con el mismo nombre, Trackio registra una nueva versión (v0, v1, …). El contenido idéntico se deduplica, por lo que volver a registrar archivos sin cambios reutiliza la versión existente.
  • Alias — punteros móviles como latest (asignado automáticamente) o los propios (prod, best) que siempre se resuelven a una única versión.
  • Origen — los artefactos están vinculados a las ejecuciones que los generaron y consumieron, por lo que puedes rastrear qué ejecución creó un modelo y qué ejecuciones lo utilizaron.

Los artefactos funcionan completamente sin conexión contra el almacenamiento local y se sincronizan con un Space de Hugging Face (o un servidor autoalojado) cuando se configura uno, exactamente como las métricas.

Registro de un artefacto

La forma más rápida es registrar un archivo o directorio directamente. Esto crea un nuevo artefacto, añade la ruta y lo registra como una salida de la ejecución actual:

import trackio

trackio.init(project="my_project")

# ... training ...

trackio.log_artifact("checkpoints/model.safetensors", type="model")

Cuando se pasa una ruta, el name del artefacto predeterminado es run-<run_id>-<basename> y type predeterminado es "unspecified". Pasa name y type para establecerlos explícitamente:

trackio.log_artifact("checkpoints/", name="my-model", type="model")

Tipos de artefactos

El type del artefacto es una cadena de categoría libre. Trackio no aplica una lista fija de tipos, pero las convenciones comunes son:

TipoÚsalo para
"model"Puntos de control de modelos, pesos de adaptadores, tokenizadores, configuraciones de modelos
"dataset"Conjuntos de datos de entrenamiento, validación, prueba o generados
"evaluation"Salidas de evaluación, predicciones, resultados de benchmarks, archivos de puntuación
"report"Figuras, gráficos, tablas, cuadernos o paquetes de análisis legibles por humanos
"unspecified"El valor predeterminado cuando no se proporciona ningún tipo

Use nombres de tipo estables dentro de un proyecto para poder filtrar artefactos de forma consistente y use trackio.use_artifact(..., type="...") para afirmar que una ejecución está consumiendo el tipo de artefacto esperado.

Construir un artefacto de forma explícita

Para un control más fino (varios archivos, rutas lógicas personalizadas, una descripción o metadatos), construya un Artifact, añádale archivos y luego regístrelo:

artifact = trackio.Artifact(
    name="my-model",
    type="model",
    description="Fine-tuned on the v2 dataset",
    metadata={"base_model": "bert-base", "epochs": 3},
)
artifact.add_file("checkpoints/model.safetensors")
artifact.add_file("checkpoints/config.json")
artifact.add_dir("tokenizer/")

logged = trackio.log_artifact(artifact)

Tras el registro, el artefacto se congela y se rellenan su version, sus aliases, su size y su manifest:

print(logged.version)   # "v0"
print(logged.aliases)   # ("latest",)

Versiones y alias

Cada registro bajo un nombre existente crea la siguiente versión entera y mueve el alias latest a ella. Asigna tus propios alias con aliases=:

trackio.log_artifact(artifact, aliases=["prod", "best"])

Los alias son punteros móviles: registrar una nueva versión con el mismo alias lo vuelve a apuntar a ella. Los especificadores de versión (v0, v1, …) están reservados y no se pueden usar como alias.

Si registras contenido idéntico a una versión existente, Trackio reutiliza esa versión en lugar de crear una nueva. Cualquier aliases explícito que pases sigue rotando sobre ella, pero latest se deja donde está: volver a registrar contenido idéntico (o más antiguo) nunca lo mueve hacia atrás.

Usando un artefacto

use_artifact() obtiene un artefacto y lo registra como una entrada para la ejecución actual, lo que es lo que construye la línea de sucesión entre una ejecución que consume y el artefacto que utilizó:

trackio.init(project="my_project")

artifact = trackio.use_artifact("my-model")          # resolves to :latest
artifact = trackio.use_artifact("my-model:v2")       # pin a version
artifact = trackio.use_artifact("my-model:prod")     # resolve an alias

Pasa type para afirmar el tipo del artefacto, lanzando una excepción si no coincide:

artifact = trackio.use_artifact("my-model", type="model")

Descarga de archivos

use_artifact devuelve un Artifact cuyos archivos materializas con download():

artifact = trackio.use_artifact("my-model:latest")
path = artifact.download()
# files are now under ./.trackio/artifact-downloads/my_project/my-model_v2/

Por defecto, los archivos se escriben en ./.trackio/artifact-downloads/<project>/<name>_v<version>/, organizados por proyecto para que los artefactos con el mismo nombre de proyectos diferentes no colisionen; pase root para elegir otro directorio. download() es idempotente: se omiten los archivos que ya están presentes, y cuando la ejecución está respaldada por un Space, cualquier archivo que falte localmente se descarga del remoto.

Referencia a datos externos

Algunos datos son demasiado grandes para copiarlos o ya residen en un almacenamiento duradero que no deseas duplicar. add_reference registra dichos datos por URI en el manifiesto sin almacenar ningún byte en el almacenamiento de Trackio, por lo que aún obtienes versionado, deduplicación, alias y linaje sobre datos que nunca se mueven:

artifact = trackio.Artifact(name="training-set", type="dataset")
artifact.add_reference("file:///mnt/nvme/datasets/corpus.parquet")
artifact.add_reference("file:///mnt/nvme/datasets/shards/")            # a directory — expands to one entry per file
artifact.add_reference("https://example.com/data/eval.json")
artifact.add_reference("hf://datasets/username/my-dataset/train.parquet")
trackio.log_artifact(artifact)

Los esquemas integrados son file://, http(s):// y hf://, todos servidos por las dependencias existentes de Trackio. Cualquier otro esquema (s3://, gs://, URLs de Azure blob, …) se admite registrando un controlador personalizado; consulte Referencia a otros almacenes a continuación para ejemplos completos de S3, GCS y Azure. Con checksum=True (el valor predeterminado), Trackio explora la fuente para completar size y un checksum:

  • file:// se hahea en streaming a un sha256; su tamaño se lee desde el disco.
  • hf:// utiliza el sha256 de LFS (o el id del blob de git); http(s):// utiliza el ETag del servidor.

Cada suma de verificación se almacena en un único campo digest: el sha256 para referencias locales/LFS, o el ETag del proveedor para referencias HTTP o de almacén de objetos.

Una URI que denota un directorio (file://) o una ruta de repositorio (hf://) se expande en una entrada de referencia por objeto, cada una nombrada por su ruta relativa al prefijo (anidada bajo name= si se proporciona). max_objects (predeterminado 10.000) limita la expansión y genera un error si se excede.

Cuando no se puede obtener ninguna suma de verificación, por ejemplo, un servidor sin ETag, la referencia se registra igualmente, utilizando el propio URI como digest, y se emite una advertencia. La excepción es una ruta local file:// que no existe: en lugar de registrarse, se lanza una excepción, ya que un archivo local ausente casi siempre es un error; use add_file para preparar un archivo local. Pase checksum=False para omitir la suma de verificación por objeto (un solo objeto registrará solo su URI) y name= para establecer la ruta lógica.

La identidad de versión de una referencia proviene de su URI, su tamaño y su digest, por lo que volver a registrar referencias idénticas las deduplica en una sola versión, mientras que un cambio en la URI, el tamaño o la suma de verificación crea una nueva, exactamente como ocurre con el contenido de un archivo. Cuando la URI se utiliza como digest, la identidad sigue, por tanto, a la URI y no al contenido.

Los URI se registran tal cual y los manifiestos pueden sincronizarse con un Dataset de Hugging Face. Un URI que incruste una credencial, como una URL https:// con firma previa o un token SAS de Azure, expondría dicha credencial a cualquier persona que pueda leer el Dataset, por lo que add_reference emite una advertencia cuando la cadena de consulta de un URI parece firmada; se prefiere el URI canónico sin firma del objeto (p. ej. s3://bucket/key).

Los bytes de referencia nunca se suben a un Space ni a un bucket, pero pueden solicitarse bajo demanda. download() descarga cada objeto referenciado en el directorio (vía httpx2, huggingface_hub o el manejador registrado), lo que puede transferir una gran cantidad de datos. Antes de la descarga, se vuelve a explorar la fuente de cada objeto y se compara su suma de verificación actual con la registrada: una discrepancia emite una advertencia de que la fuente pudo haber cambiado, pero la descarga continúa. Cada objeto se escribe de forma atómica, y si uno ya está presente en el disco se omite sin volver a comprobar la fuente, por lo que las llamadas repetidas son económicas e idempotentes:

artifact = trackio.use_artifact("training-set:latest")
path = artifact.download()   # downloads staged files AND referenced objects

Para trabajar con los punteros sin descargarlos, léelos del artefacto en su lugar:

print(artifact.references)                  # [{'path': ..., 'ref': 's3://...', 'size': ..., 'digest': ...}, ...]
print(artifact.get_entry_uri("eval.json"))  # "s3://my-bucket/eval.json"

Una referencia que no se puede recuperar (un archivo local ausente, una URL inaccesible o un esquema sin un manejador registrado) provoca una excepción cuando download() la alcanza.

Referencia a otros almacenes (S3, GCS, Azure)

Trackio no incluye deliberadamente SDK de proveedores de la nube. Para hacer referencia a objetos en un almacén que no gestiona de forma nativa, subclase trackio.ReferenceHandler y registre una instancia con trackio.register_reference_handler. Un handler implementa cuatro métodos:

  • matches(scheme, uri) — si este manejador es propietario de la URI. Los manejadores registrados se consultan antes que los integrados, por lo que un manejador también puede reclamar hosts específicos de https:// (como hace el ejemplo de Azure a continuación) antes que el manejador HTTP genérico.
  • resolve(uri, checksum, max_objects) — explora la fuente y devuelve una lista de entradas trackio.ResolvedReference: una entrada con relkey=None para un objeto único, o una entrada por objeto (con relkey establecido en la ruta del objeto relativa al prefijo) cuando la URI denota un prefijo. Establece size y digest cuando la fuente se puede explorar (el ETag del proveedor funciona bien como digest — Trackio trata los digests de referencia como tokens opacos); devuélvelos como None para registrar la referencia sin checksum, en cuyo caso Trackio usa la URI como digest y emite una advertencia.
  • fetch(uri, dest) — descarga el objeto único en uri a la ruta local dest (llamado por Artifact.download()).
  • hint() — un mensaje accionable de una línea que se muestra en la advertencia cuando resolve no produjo ninguna suma de verificación.

Las claves descubiertas durante la expansión de prefijos deben codificarse con percent al sintetizar la uri de cada entrada (y decodificarse en fetch), ya que las URIs del manifiesto no pueden contener espacios.

S3 ( s3:// , vía boto3 )

from urllib.parse import quote, unquote, urlsplit

import boto3

import trackio


class S3Handler(trackio.ReferenceHandler):
    def matches(self, scheme, uri):
        return scheme == "s3"

    def resolve(self, uri, checksum, max_objects):
        parts = urlsplit(uri)
        bucket, key = parts.netloc, unquote(parts.path.lstrip("/"))
        client = boto3.client("s3")
        if key and not key.endswith("/"):
            head = client.head_object(Bucket=bucket, Key=key)
            return [
                trackio.ResolvedReference(
                    relkey=None,
                    uri=uri,
                    size=int(head["ContentLength"]),
                    digest=head["ETag"].strip('"') if checksum else None,
                )
            ]
        base = key[: key.rfind("/") + 1]
        entries = []
        pages = client.get_paginator("list_objects_v2").paginate(
            Bucket=bucket, Prefix=key
        )
        for page in pages:
            for obj in page.get("Contents", []):
                if obj["Key"].endswith("/"):
                    continue
                if len(entries) >= max_objects:
                    raise ValueError(
                        f"{uri} expands to more than {max_objects} objects; "
                        "pass max_objects= to raise the limit."
                    )
                entries.append(
                    trackio.ResolvedReference(
                        relkey=obj["Key"][len(base):],
                        uri=f"s3://{bucket}/{quote(obj['Key'], safe='/')}",
                        size=int(obj["Size"]),
                        digest=obj["ETag"].strip('"') if checksum else None,
                    )
                )
        return entries

    def fetch(self, uri, dest):
        parts = urlsplit(uri)
        with open(dest, "wb") as f:
            boto3.client("s3").download_fileobj(
                parts.netloc, unquote(parts.path.lstrip("/")), f
            )

    def hint(self):
        return "Configure AWS credentials so the object can be probed for an ETag."


trackio.register_reference_handler(S3Handler())

artifact = trackio.Artifact(name="training-set", type="dataset")
artifact.add_reference("s3://my-bucket/shards/")   # expands to one entry per object
trackio.log_artifact(artifact)

Google Cloud Storage ( gs:// , a través de google-cloud-storage )

from urllib.parse import quote, unquote, urlsplit

from google.cloud import storage

import trackio


class GcsHandler(trackio.ReferenceHandler):
    def matches(self, scheme, uri):
        return scheme == "gs"

    def resolve(self, uri, checksum, max_objects):
        parts = urlsplit(uri)
        bucket, key = parts.netloc, unquote(parts.path.lstrip("/"))
        client = storage.Client()
        if key and not key.endswith("/"):
            blob = client.bucket(bucket).get_blob(key)
            if blob is None:
                raise ValueError(f"No such GCS object: {uri}")
            return [
                trackio.ResolvedReference(
                    relkey=None,
                    uri=uri,
                    size=blob.size,
                    digest=blob.etag.strip('"') if checksum else None,
                )
            ]
        base = key[: key.rfind("/") + 1]
        entries = []
        for blob in client.list_blobs(bucket, prefix=key):
            if blob.name.endswith("/"):
                continue
            if len(entries) >= max_objects:
                raise ValueError(
                    f"{uri} expands to more than {max_objects} objects; "
                    "pass max_objects= to raise the limit."
                )
            entries.append(
                trackio.ResolvedReference(
                    relkey=blob.name[len(base):],
                    uri=f"gs://{bucket}/{quote(blob.name, safe='/')}",
                    size=blob.size,
                    digest=blob.etag.strip('"') if checksum else None,
                )
            )
        return entries

    def fetch(self, uri, dest):
        parts = urlsplit(uri)
        key = unquote(parts.path.lstrip("/"))
        storage.Client().bucket(parts.netloc).blob(key).download_to_filename(
            str(dest)
        )

    def hint(self):
        return "Configure GCP credentials so the object can be probed for an ETag."


trackio.register_reference_handler(GcsHandler())

Azure Blob Storage (vía azure-storage-blob + azure-identity )

Los blobs de Azure se identifican mediante URLs https:// simples (https://<account>.blob.core.windows.net/<container>/<blob>), por lo que este controlador los reclama por sufijo de host: al registrarlo, tiene prioridad sobre el controlador HTTP genérico de Trackio:

from urllib.parse import quote, unquote, urlsplit

from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient

import trackio


class AzureHandler(trackio.ReferenceHandler):
    def matches(self, scheme, uri):
        return scheme in ("http", "https") and urlsplit(
            uri
        ).netloc.lower().endswith(".blob.core.windows.net")

    def _split(self, uri):
        parts = urlsplit(uri)
        container, _, blob_name = parts.path.lstrip("/").partition("/")
        return f"{parts.scheme}://{parts.netloc}", container, unquote(blob_name)

    def _service(self, account_url):
        return BlobServiceClient(account_url, credential=DefaultAzureCredential())

    def resolve(self, uri, checksum, max_objects):
        account_url, container, blob_name = self._split(uri)
        service = self._service(account_url)
        if blob_name and not blob_name.endswith("/"):
            props = service.get_blob_client(container, blob_name).get_blob_properties()
            return [
                trackio.ResolvedReference(
                    relkey=None,
                    uri=uri,
                    size=props.size,
                    digest=props.etag.strip('"') if checksum else None,
                )
            ]
        base = blob_name[: blob_name.rfind("/") + 1]
        entries = []
        container_client = service.get_container_client(container)
        for blob in container_client.list_blobs(name_starts_with=blob_name):
            if blob.name.endswith("/"):
                continue
            if len(entries) >= max_objects:
                raise ValueError(
                    f"{uri} expands to more than {max_objects} objects; "
                    "pass max_objects= to raise the limit."
                )
            entries.append(
                trackio.ResolvedReference(
                    relkey=blob.name[len(base):],
                    uri=f"{account_url}/{container}/{quote(blob.name, safe='/')}",
                    size=blob.size,
                    digest=blob.etag.strip('"') if checksum else None,
                )
            )
        return entries

    def fetch(self, uri, dest):
        account_url, container, blob_name = self._split(uri)
        downloader = (
            self._service(account_url)
            .get_blob_client(container, blob_name)
            .download_blob()
        )
        with open(dest, "wb") as f:
            downloader.readinto(f)

    def hint(self):
        return "Configure Azure credentials so the blob can be probed for an ETag."


trackio.register_reference_handler(AzureHandler())

Estos manejadores lanzan una excepción cuando no se puede inspeccionar la fuente; si prefiere registrar una referencia sin checksum en ese caso (por ejemplo, al catalogar datos detrás de una autenticación a la que no puede acceder en el momento del registro), capture el error del proveedor dentro de resolve y devuelva [trackio.ResolvedReference(relkey=None, uri=uri)] — Trackio usará el URI como digest y emitirá una advertencia, utilizando su hint().

Registre los manejadores en cada proceso que añade o descarga dichas referencias: Artifact.download() necesita el manejador para obtener los bytes, y un URI cuyo esquema no tenga un manejador registrado provocará un error.

Explorar artefactos en el panel de control

La pestaña Artifacts del panel (que se muestra una vez que un proyecto tiene artefactos) lista los artefactos agrupados por tipo, con los alias, el tamaño y la cantidad de archivos de cada versión. Al seleccionar una versión, se muestra su manifiesto de archivos (haz clic en un archivo para descargarlo), además de sus metadatos y su linaje: la ejecución que lo generó y las ejecuciones que lo utilizaron, cada una enlazando a la página de detalles de la ejecución.

Cada versión también tiene una sección Lineage que muestra un gráfico interactivo del linaje de la versión: las versiones de artefactos y las ejecuciones como nodos, con flechas desde una ejecución hacia los artefactos que registró y desde un artefacto hacia las ejecuciones que lo utilizaron. La versión seleccionada se resalta. Para mantener los gráficos grandes legibles, cinco o más nodos similares con conexiones idénticas (por ejemplo, los muchos puntos de control que registró una sola ejecución) se agrupan en un único nodo cluster que muestra la cantidad; haga clic en el cluster para buscar sus miembros y extraerlos individualmente de vuelta al gráfico. Arrastre para desplazarse, use Ctrl/Cmd + rueda del ratón (o los botones +/−) para hacer zoom y haga clic en cualquier nodo para abrir un resumen con un enlace a esa ejecución o versión de artefacto.

Las páginas de detalle de ejecución muestran el mismo linaje desde la dirección opuesta, con las secciones Artefactos de salida y Artefactos de entrada que enlazan de vuelta a la pestaña de Artefactos.

Almacenamiento remoto

Cuando tu ejecución apunta a un Hugging Face Space o a un servidor autoalojado (consulta Track), los archivos de artefactos se identifican por su contenido y se suben una sola vez: Trackio omite los blobs que el servidor ya tiene, por lo que volver a registrar archivos compartidos tiene un coste bajo. Los metadatos y los blobs de los artefactos se persisten junto con los demás datos de tu ejecución en el HF Dataset o bucket configurado.

Update on GitHub