Ir al contenido

Datasets con Croissant

El EU AI Act Art. 10 exige que los proveedores de sistemas de alto riesgo establezcan prácticas de gobernanza de datos que incluyan la descripción de las características del dataset de entrenamiento y evaluación. El Anexo IV §2 solicita, concretamente, información sobre la procedencia y características de los datos. Venturalítica materializa este requisito mediante manifiestos Croissant: el dataset no se referencia por una ruta de fichero sino por un manifiesto estructurado declarado en sei.yaml, cuyo digest queda anclado en el bundle de evidencia firmado.


Cargar un dataset directamente con pd.read_csv("data/file.csv") no produce ningún artefacto de procedencia: no hay descripción de campos, no hay atributos sensibles declarados, no hay hash verificable, y el código de evaluación mezcla lógica de carga con lógica de medición.

Un manifiesto Croissant (especificación mlcommons.org/croissant/1.0) desacopla la descripción del dataset de su consumo:

  • Describe la distribución (fileObject, sha256), el esquema (recordSet, field) y los metadatos de responsabilidad de IA (rai:dataBiases, rai:sensitiveData).
  • El eval lo materializa mediante mlcroissant.Dataset, no read_csv. El nombre del campo de carga pasa a ser una referencia al manifiesto, no una ruta hardcodeada.
  • El digest del manifiesto entra en el bundle de evidencia firmado → cualquier cambio en la descripción del dataset rompe la firma y queda trazado en git.

El campo dataset.croissant apunta al manifiesto relativo a la raíz del repositorio:

sei.yaml (extracto)
dataset: { croissant: data/german_credit.croissant.json }

Este campo es la única referencia al dataset que el motor necesita. sei run incluye el digest del manifiesto en el bundle; sei status lo verifica contra sei.lock.


Estructura mínima de un manifiesto Croissant para sei

Sección titulada «Estructura mínima de un manifiesto Croissant para sei»

El ejemplo siguiente es un extracto representativo del manifiesto real german_credit.croissant.json del escenario loan. Muestra los tres bloques obligatorios para la trazabilidad del Anexo IV §2:

data/german_credit.croissant.json (extracto)
{
"@context": { "@vocab": "https://schema.org/", "cr": "http://mlcommons.org/croissant/",
"rai": "http://mlcommons.org/croissant/RAI/", "dct": "http://purl.org/dc/terms/" },
"@type": "sc:Dataset",
"conformsTo": "http://mlcommons.org/croissant/1.0",
"name": "german-credit-eval",
"description": "UCI German Credit (1000 solicitudes) — eval-set del loan. Atributos protegidos: gender, age.",
"citeAs": "UCI Machine Learning Repository, Statlog (German Credit Data), dataset #144.",
"license": "https://creativecommons.org/licenses/by/4.0/",
"url": "https://archive.ics.uci.edu/dataset/144",
"rai:dataBiases": "Desbalance por sexo en la tasa base de aprobacion (motiva los controles de fairness).",
"rai:sensitiveData": "gender, age (atributos protegidos para evaluacion de sesgo).",
"distribution": [
{
"@type": "cr:FileObject",
"@id": "german_credit.csv",
"name": "german_credit.csv",
"contentUrl": "german_credit.csv",
"encodingFormat": "text/csv",
"sha256": "eba521d4cf4573eae070dac58e535d1e730e66e996f76ba0180d9d1b608eb043"
}
],
"recordSet": [
{
"@type": "cr:RecordSet",
"@id": "applications",
"name": "applications",
"field": [
{ "@type": "cr:Field", "@id": "applications/age", "name": "age", "dataType": "sc:Integer",
"source": { "fileObject": { "@id": "german_credit.csv" }, "extract": { "column": "age" } } },
{ "@type": "cr:Field", "@id": "applications/gender", "name": "gender", "dataType": "sc:Text",
"source": { "fileObject": { "@id": "german_credit.csv" }, "extract": { "column": "gender" } } },
{ "@type": "cr:Field", "@id": "applications/target", "name": "target", "dataType": "sc:Integer",
"source": { "fileObject": { "@id": "german_credit.csv" }, "extract": { "column": "target" } } }
]
}
]
}

Los tres bloques tienen funciones distintas desde el punto de vista regulatorio:

BloqueFunción para el Anexo IV §2
Metadatos raíz (name, description, license, url, citeAs)Procedencia y citación del dataset
rai:dataBiases, rai:sensitiveDataCaracterísticas de los datos (Art. 10(2)(f) y (g))
distribution[].sha256Integridad verificable; el motor ancla este hash
recordSet / fieldEsquema declarado; mlcroissant lo usa para materializar el DataFrame

Cómo el eval carga el dataset vía Croissant

Sección titulada «Cómo el eval carga el dataset vía Croissant»

El eval agnóstico (compliance_eval.py) carga el dataset mediante mlcroissant.Dataset, no read_csv. El manifiesto actúa como contrato de carga:

compliance_eval.py (extracto — carga vía Croissant)
import mlcroissant as mlc
CROISSANT = "data/german_credit.croissant.json"
def load_applications(croissant_path: str = CROISSANT) -> pd.DataFrame:
ds = mlc.Dataset(jsonld=croissant_path)
df = pd.DataFrame(list(ds.records(record_set="applications")))
df = df.rename(columns=lambda c: c.split("/", 1)[1] if "/" in c else c)
return df

mlcroissant lee el manifiesto, valida el sha256 del fichero CSV contra el valor declarado en distribution, y materializa el recordSet como registros Python. El código de evaluación nunca referencia la ruta del CSV directamente; lo hace a través del manifiesto.


Cuando sei run ejecuta el pipeline, el motor calcula el digest del manifiesto Croissant y lo incluye en el bundle de evidencia firmado (.sei/bundle.json). sei.lock almacena ese digest junto al del código de tratamiento y del modelo:

Verificar la integridad del manifiesto
sei status --repo .
# → comprueba el digest del Croissant contra sei.lock; si el manifiesto cambió,
# la sección dataset aparece como stale y sei run reancla

Este mecanismo garantiza que cualquier modificación del manifiesto — incluso un cambio en rai:dataBiases o en el sha256 de la distribución — quede registrada en la historia git del bundle. La nube renderiza este digest como parte de la sección §2 del Anexo IV.