Trackio documentation

المنتجات

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

المنتجات

مقدمة

المنتَج هو حزمة ملفات مُسماة ومُرقّمة الإصدارات مرتبطة بمشروع — نموذج مُدرَّب، مجموعة بيانات، أو مجموعة من مخرجات التقييم. تسجيل الملفات كمنتجات (بدلاً من تركها على القرص) يمنحك:

  • إدارة الإصدارات — في كل مرة تسجّل فيها تحت الاسم نفسه، يسجّل Trackio إصدارًا جديدًا (v0، v1، …). يتم إزالة التكرار من المحتوى المتطابق، لذا فإن إعادة تسجيل الملفات دون تغيير تعيد استخدام الإصدار الموجود مسبقًا.
  • المستعرات — مؤشرات متحركة مثل latest (تُعيَّن تلقائيًا) أو مؤشراتك الخاصة (prod، best) التي تُحل دائمًا إلى إصدار واحد.
  • النسب — ترتبط المخرجات بالتشغيلات التي أنتجتها واستهلكتها، مما يتيح لك تتبع التشغيل الذي أنشأ النموذج والتشغيلات التي استخدمته.

تعمل المخرجات بشكل كامل دون اتصال مع التخزين المحلي، وتُزامَن مع مساحة Hugging Face (أو خادم مُستضاف ذاتياً) عند تهيئتها، تماماً كما هو الحال مع المقاييس.

تسجيل عنصر

أسرع طريقة هي تسجيل ملف أو مجلد مباشرةً. يؤدي هذا إلى إنشاء عنصر جديد، وإضافة المسار، وتسجيله كإخراج للتشغيل الحالي:

import trackio

trackio.init(project="my_project")

# ... training ...

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

عند تمرير مسار، يكون الاسم الافتراضي للمنتج name هو run-<run_id>-<basename> ويكون النوع الافتراضي type هو "unspecified". قم بتمرير name وtype لتحديدهما صراحةً:

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

أنواع المخرجات

نوع type للمنتج هو نص تصنيفي حر. لا يفرض Trackio قائمة ثابتة من الأنواع، لكن الاتفاقيات الشائعة هي:

النوعاستخدمه ل
"model"نقاط التفتيش للنماذج، أوزان المكيّفات، مُجزّئات الرموز، إعدادات النماذج
"dataset"مجموعات بيانات التدريب أو التحقق أو الاختبار أو المولّدة
"evaluation"مخرجات التقييم، التنبؤات، نتائج المعايير المرجعية، ملفات الدرجات
"report"الرسوم البيانية والمخططات والجداول ودفاتر الملاحظات أو حزم التحليل القابلة للقراءة من قبل البشر
"unspecified"القيمة الافتراضية عند عدم تقديم أي نوع

استخدم أسماء أنواع مستقرة داخل المشروع حتى تتمكن من تصفية المخرجات بشكل متسق، واستخدم trackio.use_artifact(..., type="...") للتأكد من أن التشغيل يستهلك النوع المتوقع من المخرجات.

بناء عنصر بشكل صريح

للحصول على تحكم أدق — ملفات متعددة، مسارات منطقية مخصصة، وصف، أو بيانات وصفية — أنشئ Artifact، وأضف الملفات إليه، ثم سجّله:

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)

بعد التسجيل، يُثبَّت العنصر وتُملأ حقوله version وaliases وsize وmanifest:

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

الإصدارات والرموز

يُنشئ كل سجل تحت اسم موجود الإصدار الرقمي التالي وينقل المستعار latest إليه. يمكنك تعيين مستعاراتك الخاصة باستخدام aliases=:

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

المُستعَرات هي مؤشرات متحركة: عند تسجيل إصدار جديد بنفس المُستعَر، يُعاد توجيهه. مُحدِّدات الإصدارات (v0، v1، …) محجوزة ولا يمكن استخدامها كمُستعَرات.

إذا سجّلت محتوى مطابقًا لإصدار موجود، يعيد Trackio استخدام ذلك الإصدار بدلاً من إنشاء إصدار جديد. أي aliases صريحة تمررها ستُدار عليه، لكن يُترك latest في مكانه — فإعادة تسجيل محتوى مطابق (أو أقدم) لن تحركه إلى الوراء أبدًا.

استخدام عنصر

تقوم use_artifact() بجلب عنصر (artifact) وتسجيله كـ مدخل للتشغيل الحالي، وهو ما يُنشئ خط النسب (lineage) بين التشغيل المستهلك والعنصر الذي استخدمه:

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

مرّر type للتأكيد على نوع المخرَج، مع رفع استثناء إذا لم يتطابق:

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

تنزيل الملفات

يعيد use_artifact كائن Artifact يمكنك تنزيل ملفاته باستخدام download():

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

بشكل افتراضي، تُكتب الملفات إلى ./.trackio/artifact-downloads/<project>/<name>_v<version>/، مع استخدام اسم المشروع كمفتاح حتى لا تتعارض المخرجات المتشابهة في الاسم من مشاريع مختلفة؛ يمكنك تمرير root لاختيار مجلد آخر. الدالة download() تعمل بشكل متماثل (idempotent) — حيث يتم تخطي الملفات الموجودة مسبقًا — وعندما يكون التشغيل مدعومًا بواسطة Space، يتم جلب أي ملف مفقود محليًا من الخادم البعيد.

المرجع إلى بيانات خارجية

بعض البيانات كبيرة جدًا بحيث لا يمكن نسخها، أو أنها موجودة بالفعل في تخزين دائم لا ترغب في تكراره. يسجّل add_reference مثل هذه البيانات عبر URI في قائمة البيانات دون تخزين أي بايتات في تخزين Trackio، مما يتيح لك الحصول على الإصدارات، وإزالة التكرار، والرموز المستعارة، ونسب البيانات إلى مصدرها، على بيانات لا تتحرك أبدًا:

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)

المخططات المدمجة هي file:// وhttp(s):// وhf:// — جميعها تُقدَّم عبر التبعيات الموجودة مسبقًا في Trackio. أي مخطط آخر (s3://، gs://، عناوين Azure blob، ...) مدعوم عن طريق تسجيل معالج مخصص؛ راجع الإشارة إلى مخازن أخرى أدناه للحصول على أمثلة كاملة لـ S3 وGCS وAzure. عند استخدام checksum=True (القيمة الافتراضية)، يستكشف Trackio المصدر لملء size والتحقق من صحة البيانات:

  • يتم تجزئة file:// باستخدام تدفق إلى sha256، وتُقرأ حجمها من القرص.
  • hf:// يستخدم LFS sha256 (أو معرّف git blob)؛ بينما http(s):// يستخدم ETag الخاص بالخادم.

يُخزَّن كل رمز تحقق في حقل digest واحد — وهو sha256 للإحالات المحلية/إحالات LFS، أو ETag المزوّد للإحالات عبر HTTP أو مخازن الكائنات.

يتم توسيع مُعرِّف URI الذي يشير إلى مجلد (file://) أو مسار مستودع (hf://) إلى مرجع واحد لكل كائن، حيث يُسمّى كل مرجع بمساره النسبي بالنسبة للبداية (تحت name= عند تقديمه). ويحدد max_objects (الافتراضي 10,000) الحد الأقصى للتوسيع ويرفع خطأً إذا تم تجاوزه.

عند تعذّر الحصول على قيمة التحقق — على سبيل المثال خادم لا يحتوي على ETag — يتم تسجيل المرجع على أي حال، باستخدام المعرّف URI نفسه كـdigest، ويُصدر تحذير. الاستثناء هو مسار محلي file:// غير موجود: فهو يثير خطأً بدلاً من أن يُسجَّل، لأن غياب ملف محلي هو في الغالب خطأ — استخدم add_file لتحضير ملف محلي. مرّر checksum=False لتخطّي قيمة التحقق لكل كائن — فيُسجّل كائن واحد معرّف URI الخاص به فقط — وname= لتعيين المسار المنطقي.

تأتي هوية إصدار المرجع من معرّفه الموحّد (URI) وحجمه وdigest، لذا فإن إعادة تسجيل مراجع متطابقة يؤدي إلى إزالة التكرار والاحتفاظ بإصدار واحد فقط، بينما يؤدي تغيير المعرّف الموحّد أو الحجم أو رمز التحقق إلى إنشاء إصدار جديد — تمامًا كما هو الحال مع محتوى الملف. وبما أن المعرّف الموحّد يُستخدم كـdigest، فإن الهوية تتبع المعرّف الموحّد وليس المحتوى.

تُسجَّل معرفات الموارد الموحدة (URIs) كما هي حرفيًا، ويمكن مزامنة قوائم البيانات (manifests) مع مجموعة بيانات على Hugging Face. إن كان المعرّف الموحّد (URI) يحتوي على بيانات اعتماد — مثل رابط https:// مُوقَّع مسبقًا أو رمز SAS من Azure — فسيتم كشف تلك البيانات اعتماد لأي شخص يمكنه قراءة مجموعة البيانات، لذلك يُصدر add_reference تحذيرًا عندما يبدو أن سلسلة الاستعلام في المعرّف الموحّد (URI) مُوقَّعة؛ ويُفضَّل استخدام المعرّف الموحّد (URI) القياسي غير المُوقَّع للكائن (مثل s3://bucket/key).

لا يتم رفع البايتات المرجعية أبدًا إلى مساحة أو دلو، لكنها يمكن أن تُجلب عند الطلب. يقوم download() بتنزيل كل كائن مُشار إليه إلى المجلد (عبر httpx2 أو huggingface_hub أو المعالج المسجّل لديك)، مما قد ينقل كمية كبيرة من البيانات. قبل الجلب، يُعاد فحص مصدر كل كائن ومقارنة مجموعته التجريبية الحالية بتلك المسجلة — فأي عدم تطابق يُصدر تحذيرًا بأن المصدر ربما تغيّر، لكن التنزيل يستمر. يُكتب كل كائن بشكل ذرّي، ويُتخطى أي كائن موجود مسبقًا على القرص دون إعادة فحص المصدر، لذا فإن الاستدعاءات المتكررة رخيصة التكلفة وقابلة للتكرار:

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

للتعامل مع المؤشرات بدون تنزيل، اقرأها من الأداة بدلاً من ذلك:

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

تُطلق استثناءً عند وصول download() إلى مرجع غير قابل للجلب (ملف محلي مفقود، أو عنوان URL غير قابل للوصول، أو مخطط لا يوجد له معالج مسجّل).

المرجع إلى مخازن أخرى (S3، GCS، Azure)

لا يتضمن Trackio عمدًا أي واجهات برمجة تطبيقات (SDK) لمزودي الخدمات السحابية. للإشارة إلى كائنات في مخزن لا يتعامل معه بشكل أصلي، قم بإنشاء فئة فرعية من trackio.ReferenceHandler وسجّل مثيلًا لها باستخدام trackio.register_reference_handler. تنفّذ المعالج أربع طرق:

  • matches(scheme, uri) — ما إذا كان هذا المعالج مسؤولاً عن عنوان URI. تُستشار المعالجات المسجلة قبل المعالجات المدمجة، لذا يمكن لمعالج أن يدّعي استضافة محددة على https:// (كما تفعل مثال Azure أدناه) قبل المعالج العام لـ HTTP.
  • resolve(uri, checksum, max_objects) — استكشاف المصدر وإرجاع قائمة من إدخالات trackio.ResolvedReference: إدخال واحد مع relkey=None لكائن واحد، أو إدخال واحد لكل كائن (مع ضبط relkey على مسار الكائن النسبي بالنسبة للبداية) عندما يشير المعرّف الموحّد للموقع إلى بداية. اضبط size وdigest عندما يمكن استكشاف المصدر (يعمل ETag المزوّد بشكل جيد كملخص — تعامل Trackio مع ملخصات المراجع كرموز غير شفافة)؛ أعد قيمتهما كـNone لتسجيل المراجعة دون ملخص، وفي هذه الحالة تعود Trackio إلى استخدام المعرّف الموحّد للموقع كملخص وتصدر تحذيراً.
  • fetch(uri, dest) — تنزيل الكائن الواحد الموجود في uri إلى المسار المحلي dest (يُستدعى بواسطة Artifact.download()).
  • hint() — رسالة قابلة للتنفيذ من سطر واحد تظهر في التحذير عندما لم يُنتج resolve أي قيمة تجزئة.

يجب ترميز المفاتيح المكتشفة أثناء توسيع البادئة باستخدام الترميز المئوي عند تركيب uri لكل عنصر (وفك ترميزها في fetch)، لأن عناوين URI في قائمة التشغيل قد لا تحتوي على مسافات.

S3 ( s3:// ، عبر 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 (gs://، عبر 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-storage-blob + azure-identity )

تُعرَّف كتل Azure عبر عناوين https:// بسيطة (https://<account>.blob.core.windows.net/<container>/<blob>)، لذا يدّعي هذا المعالج هذه العناوين بناءً على لاحقة المضيف — فبتسجيله يصبح له الأولوية على معالج HTTP العام الخاص بـ 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())

ترفع هذه المعالجات استثناءً عندما لا يمكن فحص المصدر؛ وإذا كنت تفضل تسجيل مرجع غير مُتحقق من صحته في تلك الحالة (على سبيل المثال، عند فهرسة بيانات خلف مصادقة لا يمكنك الوصول إليها وقت التسجيل)، فالتقط خطأ المزوّد داخل resolve وأعد [trackio.ResolvedReference(relkey=None, uri=uri)] — سيعود Trackio إلى استخدام URI كملخص ويصدر تحذيرًا، مستخدمًا hint() الخاص بك.

سجّل المُعالِجات في كل عملية تضيف أو تُحمِّل مثل هذه المراجع: يحتاج Artifact.download() إلى المُعالِج لجلب البايتات، وسيُطلق استثناءً أي عنوان URI لا يوجد له مُعالِج مسجَّل في مخططه.

تصفح المخرجات في لوحة التحكم

تُدرج تبويب Artifacts في لوحة التحكم (الذي يظهر بمجرد امتلاك المشروع لمخرجات) المخرجات مجمّعة حسب النوع، مع عرض مستعرات كل إصدار وحجمه وعدد الملفات. عند تحديد إصدار، يظهر بيان ملفاته — انقر على ملف لتنزيله — بالإضافة إلى بياناته الوصفية ونسبه: التشغيل الذي أنتجه والتشغيلات التي استخدمته، حيث يربط كل منها إلى صفحة تفاصيل التشغيل.

تحتوي كل نسخة أيضًا على قسم Lineage يعرض رسمًا بيانيًا تفاعليًا لنسب النسخة: حيث تمثل إصدارات المخرجات والتشغيلات عقدًا، مع أسهم من التشغيل إلى المخرجات التي سجّلها ومن المخرج إلى التشغيلات التي استخدمته. يتم إبراز النسخة المحددة. ولإبقاء الرسوم البيانية الكبيرة قابلة للقراءة، تُجمَع خمس عقد متشابهة أو أكثر ذات اتصالات متطابقة (مثل العديد من نقاط التفتيش التي سجّلها تشغيل واحد) في عقدة cluster واحدة تعرض العدد — انقر على العنقود للبحث في أعضائه واستخراج أفراد منها مرة أخرى إلى الرسم البياني. اسحب للتحريك، واستخدم Ctrl/Cmd + التمرير (أو أزرار +/−) للتكبير والتصغير، وانقر على أي عقدة لفتح ملخص يحتوي على رابط إلى ذلك التشغيل أو إصدار المخرج.

تعرض صفحات تفاصيل التشغيل نفس النسب من الاتجاه المعاكس، مع أقسام المخرجات والمداخل تربط بالعودة إلى تبويب المخرجات.

التخزين عن بُعد

عندما يستهدف تشغيلك مساحة Hugging Face أو خادمًا مُستضافًا ذاتيًا (انظر تتبع)، تكون ملفات المخرجات مُعرَّفة بالمحتوى وتُرفع مرة واحدة: يتخطى Trackio الكتل التي يمتلكها الخادم بالفعل، لذا فإن إعادة تسجيل الملفات المشتركة عملية رخيصة. يتم حفظ بيانات وصفية المخرجات والكتل إلى جانب بيانات تشغيلك الأخرى في مجموعة بيانات HF أو الدلو المُهيأ.

Update on GitHub