Hub Python Library documentation

فهم التخزين المؤقت

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

فهم التخزين المؤقت

huggingface_hub يستخدم ذاكرة تخزين مؤقت محلية مبنية على الملفات لتخزين الملفات الفردية التي تم تنزيلها من Hub وتجنّب إعادة تنزيل الملفات التي لم تتغير عند تحديث المستودع. بالإضافة إلى ذلك، يخزّن hf_xet ذاكرة تخزين مؤقت للتجزئة وبيانات التجهيز لتحسين عمليات الرفع (انظر تخزين Xet المؤقت).

يتناول هذا الدليل أدوات إدارة ذاكرة التخزين المؤقت الخاصة بلغة بايثون التي يوفرها huggingface_hub. للحصول على نظرة عامة لا تعتمد على لغة معينة حول كيفية عمل نظام ذاكرة التخزين المؤقت في Hugging Face Hub، راجع توثيق Hub حول التخزين المؤقت المحلي.

التخزين المؤقت القائم على الملفات

صُمم نظام التخزين المؤقت في Hugging Face Hub ليكون التخزين المؤقت المركزي المشترك عبر المكتبات التي تعتمد على Hub. وقد تم تحديثه في الإصدار v0.8.0 لمنع إعادة تنزيل الملفات نفسها بين المراجعات.

تم تصميم نظام التخزين المؤقت على النحو التالي:

<CACHE_DIR>
├─ <MODELS>
├─ <DATASETS>
├─ <SPACES>
├─ <KERNELS>

القيمة الافتراضية لـ <CACHE_DIR> هي ~/.cache/huggingface/hub. ومع ذلك، يمكن تخصيصها باستخدام الحجة cache_dir في جميع الطرق، أو عن طريق تحديد متغير البيئة HF_HOME أو HF_HUB_CACHE.

تشارك النماذج ومجموعات البيانات والمساحات والنوى جذرًا مشتركًا. يحتوي كلٌّ من هذه المستودعات على نوع المستودع، والمساحة الاسم (المنظمة أو اسم المستخدم) إن وُجدت، واسم المستودع:

<CACHE_DIR>
├─ models--julien-c--EsperBERTo-small
├─ models--lysandrejik--arxiv-nlp
├─ models--bert-base-cased
├─ datasets--glue
├─ datasets--huggingface--DataMeasurementsFiles
├─ spaces--dalle-mini--dalle-mini

تُحمَّل جميع الملفات الآن من Hub داخل هذه المجلدات. يضمن التخزين المؤقت عدم تحميل الملف مرتين إذا كان موجودًا مسبقًا ولم يتم تحديثه؛ أما إذا تم تحديثه، وكنت تطلب أحدث نسخة من الملف، فسيتم تحميل أحدث نسخة (مع إبقاء النسخة السابقة كما هي في حال احتجت إليها مرة أخرى).

للوصول إلى ذلك، تحتوي جميع المجلدات على الهيكل نفسه:

<CACHE_DIR>
├─ datasets--glue
│  ├─ refs
│  ├─ blobs
│  ├─ snapshots
│  ├─ trees
...

صُمم كل مجلد ليحتوي على ما يلي:

المراجع

تحتوي مجلد refs على ملفات تشير إلى أحدث مراجعة للإشارة المعطاة. على سبيل المثال، إذا كنا قد استخرجنا ملفًا سابقًا من فرع main في مستودع، فسيحتوي مجلد refs على ملف باسم main، والذي سيحتوي بدوره على معرّف الالتزام الحالي للرأس.

إذا كان آخر التزام في main يحمل المعرّف aaaaaa، فسيحتوي على aaaaaa.

إذا تم تحديث ذلك الفرع نفسه بارتكاب جديد، يحمل bbbbbb كمعرّف، فإن إعادة تنزيل ملف من ذلك المرجع ستحدّث ملف refs/main ليحتوي على bbbbbb.

Blobs

تحتوي مجلد blobs على الملفات الفعلية التي قمنا بتنزيلها. اسم كل ملف هو تجزئته (hash).

لقطات

تحتوي مجلد snapshots على روابط رمزية إلى الكتل المذكورة أعلاه. ويتكون هو نفسه من عدة مجلدات: واحد لكل مراجعة معروفة!

في الشرح أعلاه، قمنا في البداية بجلب ملف من المراجعة aaaaaa، قبل جلب ملف من المراجعة bbbbbb. في هذه الحالة، سيكون لدينا الآن مجلدان داخل مجلد snapshots: aaaaaa وbbbbbb.

في كلٍّ من هذه المجلدات، توجد روابط رمزية حيّة تحمل أسماء الملفات التي قمنا بتنزيلها. على سبيل المثال، إذا كنا قد قمنا بتنزيل ملف README.md عند المراجعة aaaaaa، فسيكون المسار التالي:

<CACHE_DIR>/<REPO_NAME>/snapshots/aaaaaa/README.md

في الواقع، ملف README.md هو رابط رمزي يشير إلى الكائن الذي يحتوي على تجزئة الملف.

من خلال إنشاء الهيكل بهذه الطريقة، نفتح آلية مشاركة الملفات: إذا تم جلب نفس الملف في المراجعة bbbbbb، فسيكون له نفس التوقيع الرقمي ولن تكون هناك حاجة إلى إعادة تنزيل الملف.

الأشجار

تخزّن مجلد trees قائمة الملفات التي يحتويها المستودع عند نقطة التزامن المحددة. بما أن نقطة التزامن غير قابلة للتغيير، فإن قائمة ملفاتتها لا تتغير أبدًا. وهذا يعني أنه يمكن تخزين القائمة مؤقتًا إلى الأبد دون الحاجة إلى التحقق منها مرة أخرى مقابل Hub.

يُسمّى كل قائمة مخزّنة مؤقتًا باسم تجزئة التزامن (commit hash) وتُخزَّن كملف JSON، على سبيل المثال trees/aaaaaa.json. لكل ملف في المستودع عند ذلك التزامن، تسجّل القائمة ما يلزم لتنزيل الملف: مساره، حجمه، وتجزئته. هذه هي نفس المعلومات التي كان سيردّ بها Hub، لكنها عادةً ما تتطلب استدعاءً واحدًا للشبكة لكل ملف لجلبها.

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

تقرأ كلتا الدالتين snapshot_download() و hf_hub_download() هذا التخزين المؤقت لتجنب استدعاءات الشبكة. عند تنزيل ملف باستخدام تجزئة الالتزام (commit hash) كإصدار (وهو ما تفعله snapshot_download() داخليًا لكل ملف)، يتم قراءة بيانات التنزيل الوصفية من قائمة الملفات المخزنة مؤقتًا ويتم تجاوز استدعاء الشبكة الخاص بكل ملف. وهذا يعني أن استدعاء hf_hub_download() لملف واحد يستفيد أيضًا من قائمة الملفات التي حفظها استدعاء snapshot_download() سابقًا لنفس الالتزام.

بما أن قائمة الملفات المخزنة مؤقتًا تصف بالضبط ما يجب أن يحتويه الالتزام، يمكن لـ snapshot_download() أيضًا أن يحدد ما إذا كان لقطة محلية مكتملة. إذا تعذر الوصول إلى Hub (أنت غير متصل، أو فشلت الاتصال، أو مررت بـ local_files_only=True) وكانت بعض الملفات المتوقعة مفقودة من اللقطة المحلية، يرمي snapshot_download() استثناء IncompleteSnapshotError بدلاً من إرجاع مجلد جزئي. قبل ذلك، كانت اللقطة غير المكتملة تُرجع بصمت، مما قد يجعلك تعمل مع ملفات مفقودة دون علم بذلك. الملفات المستبعدة بواسطة allow_patterns أو ignore_patterns لا تُحتسب كملفات مفقودة. يكشف الاستثناء عن المسار إلى اللقطة غير المكتملة عبر خاصية snapshot_path الخاصة به، بحيث يمكنك تحديد موقع الملفات المخزنة مؤقتًا جزئيًا إذا لزم الأمر.

.no_exist (متقدم)

بالإضافة إلى مجلدات blobs وrefs وsnapshots، قد تجد أيضاً مجلد .no_exist في ذاكرتك المؤقتة. يحتفظ هذا المجلد بسجل للملفات التي حاولت تنزيلها مرة واحدة لكنها غير موجودة على Hub. هيكلته هي نفسها هيكل مجلد snapshots مع مجلد فرعي واحد لكل مراجعة معروفة:

<CACHE_DIR>/<REPO_NAME>/.no_exist/aaaaaa/config_that_does_not_exist.json

على عكس مجلد snapshots، تكون الملفات هنا ملفات فارغة بسيطة (بدون روابط رمزية). في هذا المثال، الملف "config_that_does_not_exist.json" غير موجود على Hub للمراجعة "aaaaaa". وبما أنه يخزن ملفات فارغة فقط، فإن هذا المجلد يُعدّ ضئيلاً من حيث استهلاك مساحة القرص.

لذا قد تتساءل الآن، لماذا تكون هذه المعلومات ذات صلة؟ في بعض الحالات، يحاول إطار العمل تحميل ملفات اختيارية لنموذج. إن حفظ عدم وجود الملفات الاختيارية يجعل تحميل النموذج أسرع لأنه يوفر استدعاء HTTP واحدًا لكل ملف اختياري محتمل. هذا هو الحال على سبيل المثال في transformers حيث يمكن لكل مُجزِّئ (tokenizer) دعم ملفات إضافية. عند أول مرة تقوم فيها بتحميل المُجزِّئ على جهازك، سيخزّن مؤقتًا أي الملفات الاختيارية موجودة (وأيها غير موجودة) لجعل وقت التحميل أسرع في المرات التالية من التهيئة.

To test if a file is cached locally (without making any HTTP request), you can use the try_to_load_from_cache() helper. It will either return the filepath (if exists and cached), the object _CACHED_NO_EXIST (if non-existence is cached) or None (if we don’t know).

from huggingface_hub import try_to_load_from_cache, _CACHED_NO_EXIST

filepath = try_to_load_from_cache()
if isinstance(filepath, str):
    # file exists and is cached
    ...
elif filepath is _CACHED_NO_EXIST:
    # non-existence of file is cached
    ...
else:
    # file is not cached
    ...

في الممارسة العملية

عملياً، يجب أن يبدو مخزنك المؤقت (Cache) كشجرة من الشكل التالي:

    [  96]  .
    └── [ 160]  models--julien-c--EsperBERTo-small
        ├── [ 160]  blobs
        │   ├── [321M]  403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        │   ├── [ 398]  7cb18dc9bafbfcf74629a4b760af1b160957a83e
        │   └── [1.4K]  d7edf6bd2a681fb0175f7735299831ee1b22b812
        ├── [  96]  refs
        │   └── [  40]  main
        ├── [ 128]  snapshots
        │   ├── [ 128]  2439f60ef33a0d46d85da5001d52aeda5b00ce9f
        │   │   ├── [  52]  README.md -> ../../blobs/d7edf6bd2a681fb0175f7735299831ee1b22b812
        │   │   └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        │   └── [ 128]  bbc77c8132af1cc5cf678da3f1ddf2de43606d48
        │       ├── [  52]  README.md -> ../../blobs/7cb18dc9bafbfcf74629a4b760af1b160957a83e
        │       └── [  76]  pytorch_model.bin -> ../../blobs/403450e234d65943a7dcf7e05a771ce3c92faa84dd07db4ac20f592037a1e4bd
        └── [  96]  trees
            ├── [ 521]  2439f60ef33a0d46d85da5001d52aeda5b00ce9f.json
            └── [ 521]  bbc77c8132af1cc5cf678da3f1ddf2de43606d48.json

CACHEDIR.TAG

ينشئ huggingface_hub تلقائيًا ملف CACHEDIR.TAG داخل مجلد التخزين المؤقت. يتبع هذا الوسم معيار وسم مجلدات التخزين المؤقت ويخبر أدوات النسخ الاحتياطي (مثل Borg وrestic وrsync) أن المجلد يحتوي على بيانات تخزين مؤقت قابلة لإعادة التنزيل ويمكن استبعادها بأمان من عمليات النسخ الاحتياطي.

القيود

لضمان نظام تخزين مؤقت فعّال، يستخدم huggingface-hub الروابط الرمزية. ومع ذلك، لا تدعم جميع الأجهزة الروابط الرمزية. هذه مشكلة معروفة خاصةً على نظام Windows. في هذه الحالة، لا يستخدم huggingface_hub مجلد blobs/ بل يخزّن الملفات مباشرةً في مجلد snapshots/ بدلاً من ذلك. يتيح هذا الحل البديل للمستخدمين تنزيل الملفات وتخزينها مؤقتاً من Hub بالطريقة نفسها تماماً. كما يتم دعم الأدوات لفحص الحذف (انظر أدناه). ومع ذلك، يكون نظام التخزين المؤقت أقل كفاءة، إذ قد يتم تنزيل ملف واحد عدة مرات إذا تم تنزيل عدة مراجع لنفس المستودع.

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

إذا كنت ترغب في استخدام وضع التخزين المؤقت بدون روابط رمزية بشكل استباقي (على سبيل المثال، على نظام ملفات مشترك لا يتعامل مع الروابط الرمزية بشكل جيد)، يمكنك تعيين متغير البيئة HF_HUB_DISABLE_SYMLINKS إلى 1. سيتم نسخ الملفات مباشرة إلى snapshots/ بدلاً من إنشاء روابط رمزية إلى blobs/.

عندما لا تكون الروابط الرمزية مدعومة، يتم عرض رسالة تحذير للمستخدم لإعلامه بأنه يستخدم نسخة متدهورة من نظام التخزين المؤقت. يمكن تعطيل هذا التحذير عن طريق تعيين متغير البيئة HF_HUB_DISABLE_SYMLINKS_WARNING إلى true.

المقاطع المشتركة بين المستودعات

بشكل افتراضي، يتم أيضًا إزالة التكرار من ملفات Xet عبر المستودعات. تُخزَّن ملف Xet الذي تم تنزيله عبر hf_xet مرة واحدة في <CACHE_DIR>/blobs/<prefix>/<xet_hash>، بينما يكون إدخال blobs/<etag> الخاص بالمستودع رابطًا رمزيًا نسبيًا إليه. عندما يحتاج مستودع آخر إلى نفس الملف، يحصل على رابط رمزي بدلاً من التنزيل: لا يتم نقل أي بايت ولا يُستخدم أي مساحة إضافية. لا يتغير تخطيط اللقطة. يحدد ملف علامة المخزن، لذا لا يتم المساس أبدًا بمجلد blobs لم يتم إنشاؤه بواسطة huggingface_hub.

يحتوي كل ملف مشترك على قائمة <xet_hash>.refs تُدرج كتل المستودع التي تستخدمه. تقرأ hf cache rm هذه القائمة للتحقق فقط من الملفات المشتركة المتأثرة بالحذف، وتزيل hf cache prune الملفات المشتركة التي لم يعد أي مستودع مخزّن مؤقتًا يستخدمها. القائمة مجرد تلميح: يتم التحقق من كل إدخال مقابل نظام الملفات، ويُحتفظ بأي ملف تكون بياناته الوصفية مفقودة أو غير قابلة للقراءة. تفضل عملية التنظيف ترك بيانات قابلة للاسترداد على كسر إدخال تخزين مؤقت صالح.

تبقى أحجام المستودعات الفردية منطقية، إذ يُحتسب الملف المشترك لكل مستودع يستخدمه. أما size_on_disk على مستوى الكاش بالكامل فهو فيزيائي: يُحتسب كل ملف مشترك مرة واحدة، بما في ذلك الملفات التي لم يعد أي مستودع يستخدمها.

تستمر العملاء الأقدم (huggingface_hub، huggingface.js، hf-hub، llama.cpp، وأي شيء يتبع الروابط الرمزية) في القراءة والتنزيل بشكل طبيعي، في مجلدات المستودعات نفسها. هناك قيودان:

  • يترك huggingface_hub<=1.31 الملفات المشتركة المستودع المحذوف في المخزن، حيث يحدد hf cache ls هذه الملفات ويحذفها hf cache prune. قد تحذف أدوات حذف الكاش الخاصة بالعملاء الآخرين بدلاً من ذلك ملفاً مشتركاً ما زال مستخدماً من قبل مستودعات أخرى؛ يتم إعادة تنزيل الملفات المتأثرة عند الاستخدام التالي. استخدم إصداراً محدثاً من huggingface_hub لأوامر hf cache rm وhf cache prune والحذف البرمجي.
  • قد تُبلّغ مُسحّات ذاكرة التخزين المؤقت لديهم عن مجلد blobs في المستوى الأعلى كعنصر غير معروف.

يتطلب المتجر تخطيط ذاكرة التخزين المؤقت القائم على الروابط الرمزية، ويُعطَّل عبر HF_HUB_DISABLE_XET=1. أي فشل في مشاركة ملف، مثل نظام ملفات غير مدعوم، أو خطأ في الصلاحيات، أو وجود مسبق لمجلد blobs غير مُعلَّم، يؤدي بصمت إلى الرجوع إلى التخزين المحلي العادي للمستودع. اضبط HF_HUB_DISABLE_SHARED_BLOBS=1 للاستبعاد بالكامل.

تثبيت نسخة (متقدم)

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

عندما يقوم أحد المكتبات بتنزيل عدة ملفات واحدة تلو الأخرى، يجب على كل استدعاء أن يحل revision="main" إلى تجزئة التزامن من جديد. وهذا يستهلك استدعاء HTTP واحداً لكل ملف، والأسوأ من ذلك أن الاستدعاءين المنفذين بفارق ثوانٍ قليلة قد ينتهيان إلى تزامنين مختلفين إذا تم تحديث المستودع بينهما.

تحلّ HfApi.resolve_revision() المراجعة مرة واحدة وتعيد ResolvedRevision:

>>> from huggingface_hub import resolve_revision
>>> revision = resolve_revision("openai-community/gpt2")
>>> revision
ResolvedRevision(initial=None, resolved='607a30d783dfa663caf39e06633721c8d4cfcd7e')

ResolvedRevision هو فئة فرعية من str، لذا يمكن تمريره إلى أي طريقة في huggingface_hub تقبل معامل revision. قيمته النصية هي ما طلبه المستخدم في البداية ("main" هنا، مما يجعل رسائل الخطأ قابلة للقراءة)، بينما يحتوي .resolved على تجزئة الالتزام:

>>> revision == "main"
True
>>> revision.resolved
'607a30d783dfa663caf39e06633721c8d4cfcd7e'

تكتشف أدوات التنزيل (hf_hub_download()، snapshot_download()، get_cached_repo_tree()) كائن ResolvedRevision وتستخدم تجزئة الالتزام مباشرة. يُضمن أن كل ملف يأتي من نفس الالتزام، وبمجرد تخزين الملفات مؤقتًا لا تكون هناك حاجة إلى أي استدعاء HTTP على الإطلاق:

>>> from huggingface_hub import hf_hub_download
>>> config = hf_hub_download("openai-community/gpt2", "config.json", revision=revision)
>>> weights = hf_hub_download("openai-community/gpt2", "model.safetensors", revision=revision)

يتم أيضًا كتابة تعيين revision -> commit hash في مجلد refs/ من ذاكرة التخزين المؤقت (انظر Refs). وهذا يعني أنه إذا تعذّر الوصول إلى Hub لاحقًا (وضع عدم الاتصال، خطأ في الاتصال، انتهاء المهلة، توقف Hub عن العمل)، فإن HfApi.resolve_revision() يلجأ بشكل شفاف إلى القيمة المخزنة مؤقتًا. وإذا لم يكن هناك أي شيء مخزن مؤقتًا، يتم رفع RevisionResolutionError.

لا يعني مُعرّف الالتزام (commit hash) شيئًا إلا بالنسبة إلى المستودع الذي تم حله ضده، وتستخدم أدوات التحميل هذا المُعرّف كما هو. لذا يجب تمرير ResolvedRevision فقط إلى المستودع الذي تم حله من أجله. إذا كان المكتبة تقوم أيضًا بتنزيل ملفات من مستودع آخر (نموذج أساسي، مُكيّف، مكوّن موجود في مستودع مستقل، …)، فهي بحاجة إلى نسخة (revision) محلولة لذلك المستودع. ما عليك سوى تمرير ResolvedRevision مرة أخرى إلى HfApi.resolve_revision(): فهو يتذكر المستودع الذي ينتمي إليه ويعيد حل النسخة المطلوبة في الأصل ("main" هنا) من جديد للمستودع الجديد.

>>> other_revision = resolve_revision("openai-community/gpt2-medium", revision=revision)  # resolves "main" again
>>> other_revision.resolved
'6dcaa7a952f72f9298047fd5137cd6e4f05f41da'
>>> config = hf_hub_download("openai-community/gpt2-medium", "config.json", revision=other_revision)

تخزين Xet مؤقت

لتوفير عمليات رفع أكثر كفاءة، يضيف hf_xet مجلد xet إلى ذاكرة التخزين المؤقت الحالية لـhuggingface_hub. يخزّن هذا المجلد الشظايا (وهي بنية بيانات تربط الملفات بالقطع) وبيانات التهيئة المستخدمة لإزالة التكرار من عمليات الرفع واستئنافها. لمزيد من المعلومات حول نظام تخزين Xet، راجع هذا القسم.

لم يعد hf_xet يستخدم ذاكرة تخزين مؤقت محلية للقطع لتنزيل الملفات. لا يؤدي ضبط HF_XET_CHUNK_CACHE_SIZE_BYTES إلى تفعيلها. لا تزال الملفات المنزلة مخزنة مؤقتًا في ذاكرة التخزين المؤقت القائمة على الملفات.

يمكن تكوين مجلد xet، الذي يقع افتراضيًا في ~/.cache/huggingface/xet، باستخدام HF_XET_CACHE. ويتضمن البنية التالية:

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  ├─ staging

مجلد environment_identifier هو نص مُرمَّز (قد يظهر على جهازك على شكل https___cas_serv-tGqkUaZf_CBPHQ6h). يُستخدم هذا أثناء التطوير مما يتيح وجود إصدارات محلية وإنتاجية من ذاكرة التخزين المؤقت جنبًا إلى جنب في الوقت نفسه. كما يُستخدم عند التنزيل من المستودعات التي تقع في مناطق تخزين مختلفة. قد ترى عدة إدخالات من هذا النوع في مجلد xet، حيث يتوافق كل منها مع بيئة مختلفة، لكن هيكلها الداخلي متطابق.

تخدم المجلدات الداخلية الأغراض التالية:

  • shard-cache يحتوي على شظايا مخزنة مؤقتًا تُستخدم في مسار الرفع.
  • staging هو مساحة عمل مصممة لدعم عمليات رفع قابلة للاستئناف.

وهي موثقة أدناه.

يُدير hf_xet ذاكرة التخزين المؤقت للتقسيمات وبيانات الترحيل كطبقة تحسين للعمليات المرفوعة. ولإدارة الملفات المُحمّلة، استخدم واجهات برمجة التطبيقات القائمة على الملفات في huggingface_hub.

shard-cache

يُستخدم هذا الكاش عند رفع المحتوى إلى Hub. المجلد مسطّح، ويتكوّن فقط من ملفات شُعب (shards)، حيث يستخدم كل منها معرّفًا (ID) كاسم للشعبة.

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb
│  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  ├─ ceeeb7ea4cf6c0a8d395a2cf9c08871211fbbd17b9b5dc1005811845307e6b8f.mdb
│  │  │  ├─ e8535155b1b11ebd894c908e91a1e14e3461dddd1392695ddc90ae54a548d8b2.mdb

تحتوي shard-cache على شظايا هي:

  • تم توليده محلياً وتم رفعه بنجاح إلى CAS
  • تم تنزيلها من CAS كجزء من خوارزمية إزالة التكرار العالمية

توفّر الشرائح (Shards) إسقاطًا بين الملفات والقطع. أثناء عمليات الرفع، تُقسَّم كل ملف إلى قطع ويُحفظ تجزئة (hash) كل قطعة. ثم يُستشار كل شريحة في ذاكرة التخزين المؤقت. إذا احتوت شريحة على تجزئة قطعة موجودة في الملف المحلي قيد الرفع، فيمكن التخلّي عن تلك قطعة لأنها مخزنة مسبقًا في نظام التخزين المركزي (CAS).

تنتهي صلاحية جميع الشرائح بعد 3-4 أسابيع من تاريخ تنزيلها. لا يتم تحميل الشرائح التي انتهت صلاحيتها أثناء الرفع، وتُحذف بعد أسبوع من انتهاء صلاحيتها.

staging

عندما ينتهي الرفع قبل أن يتم تثبيت المحتوى الجديد في المستودع، ستحتاج إلى استئناف نقل الملف. ومع ذلك، من الممكن أن تكون بعض المقاطع قد تم رفعها بنجاح قبل الانقطاع.

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

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ staging
│  │  │  ├─ shard-session
│  │  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  │  ├─ xorb-metadata
│  │  │  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb

عند معالجة الملفات ورفع المقاطع بنجاح، تُخزَّن بياناتها الوصفية في xorb-metadata على شكل شريحة. عند استئناف جلسة الرفع، تُعالَج كل الملفات مرة أخرى ويُستشار محتوى الشرائح الموجودة في هذا المجلد. يتم تجاوز أي محتوى تم رفعه بنجاح، ويُرفع أي محتوى جديد (مع حفظ بياناته الوصفية).

في غضون ذلك، يخزّن shard-session معلومات الملفات والقطع الخاصة بالملفات المعالجة. عند اكتمال عملية الرفع بنجاح، يتم نقل المحتوى من هذه القطع إلى shard-cache الأكثر دوامًا.

القيود والمحدّدات

يتمتع shard-cache بحد أقصى مرن يبلغ 16 جيجابايت، ويمكن ضبطه عبر متغير البيئة HF_XET_SHARD_CACHE_SIZE_LIMIT. لا يتوفر أي واجهة برمجة تطبيقات عالية المستوى لإدارة هذا الكاش.

تُستخدم ذاكرة التخزين المؤقت للتقسيمات وبيانات الترحيل لتحسين عمليات الرفع. للتفاعل مع الأصول نفسها، يُوصى باستخدام واجهات برمجة التطبيقات الخاصة بنظام ذاكرة التخزين المؤقت في huggingface_hub.

إذا كنت بحاجة إلى استعادة المساحة التي يستخدمها Xet أو إلى تصحيح أي مشاكل محتملة متعلقة بالذاكرة المؤقتة، فما عليك سوى إزالة ذاكرة xet المؤقتة بالكامل عن طريق تشغيل rm -rf ~/<cache_dir>/xet حيث <cache_dir> هو موقع ذاكرة Hugging Face المؤقتة لديك، وهو عادةً ~/.cache/huggingface

مثال على شجرة مجلد كاش xet:

<CACHE_DIR>
├─ xet
│  ├─ environment_identifier
│  │  ├─ shard-cache
│  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb
│  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  ├─ ceeeb7ea4cf6c0a8d395a2cf9c08871211fbbd17b9b5dc1005811845307e6b8f.mdb
│  │  │  ├─ e8535155b1b11ebd894c908e91a1e14e3461dddd1392695ddc90ae54a548d8b2.mdb
│  │  ├─ staging
│  │  │  ├─ shard-session
│  │  │  │  ├─ 906ee184dc1cd0615164a89ed64e8147b3fdccd1163d80d794c66814b3b09992.mdb
│  │  │  │  ├─ xorb-metadata
│  │  │  │  │  ├─ 1fe4ffd5cf0c3375f1ef9aec5016cf773ccc5ca294293d3f92d92771dacfc15d.mdb

للمزيد من المعلومات حول Xet Storage، راجع هذا القسم.

تخزين الأصول

بالإضافة إلى تخزين ملفات المستودع (Hub) مؤقتًا، تتطلب المكتبات التابعة (downstream) غالبًا تخزين ملفات أخرى مرتبطة بـ HF لكنها غير مُدارة مباشرةً بواسطة huggingface_hub (مثل: ملف تم تنزيله من GitHub، بيانات مُعالجة مسبقًا، سجلات، إلخ). من أجل تخزين هذه الملفات، المسمّى بـ assets، يمكن استخدام cached_assets_path(). يولّد هذا المساعد الصغير مسارات في ذاكرة التخزين المؤقت لـ HF بطريقة موحّدة بناءً على اسم المكتبة التي تطلب ذلك، وخيارًا بناءً على مساحة الاسم واسم مجلد فرعي. الهدف هو السماح لكل مكتبة تابعة بإدارة أصولها بطريقتها الخاصة (مثلًا: لا توجد قاعدة حول البنية) طالما أنها تبقى في مجلد الأصول الصحيح. يمكن لهذه المكتبات بعد ذلك الاستفادة من أدوات huggingface_hub لإدارة ذاكرة التخزين المؤقت، ولا سيما مسح أجزاء من الأصول وحذفها عبر أمر سطر الأوامر.

from huggingface_hub import cached_assets_path

assets_path = cached_assets_path(library_name="datasets", namespace="SQuAD", subfolder="download")
something_path = assets_path / "something.json" # Do anything you like in your assets folder !

يُعد cached_assets_path() الطريقة الموصى بها لتخزين الأصول، لكنه ليس إلزاميًا. إذا كانت مكتبتك تستخدم بالفعل ذاكرة تخزين مؤقت خاصة بها، فلا تتردد في استخدامها!

الأصول في الممارسة

عملياً، يجب أن يبدو كاش الأصول لديك كشجرة مماثلة لما يلي:

    assets/
    └── datasets/
    │   ├── SQuAD/
    │   │   ├── downloaded/
    │   │   ├── extracted/
    │   │   └── processed/
    │   ├── Helsinki-NLP--tatoeba_mt/
    │       ├── downloaded/
    │       ├── extracted/
    │       └── processed/
    └── transformers/
        ├── default/
        │   ├── something/
        ├── bert-base-cased/
        │   ├── default/
        │   └── training/
    hub/
    └── models--julien-c--EsperBERTo-small/
        ├── blobs/
        │   ├── (...)
        │   ├── (...)
        ├── refs/
        │   └── (...)
        └── [ 128]  snapshots/
            ├── 2439f60ef33a0d46d85da5001d52aeda5b00ce9f/
            │   ├── (...)
            └── bbc77c8132af1cc5cf678da3f1ddf2de43606d48/
                └── (...)

إدارة ذاكرة التخزين المؤقت القائمة على الملفات

فحص ذاكرتك المؤقتة

حاليًا، لا يتم حذف الملفات المخزّنة مؤقتًا من مجلدك المحلي أبدًا: عند تنزيل نسخة جديدة من فرع، تُحفظ الملفات السابقة في حال احتجت إليها مرة أخرى. لذلك، قد يكون من المفيد فحص مجلد التخزين المؤقت لمعرفة المستودعات والنسخ التي تستهلك أكبر قدر من مساحة القرص. يوفر huggingface_hub أدوات مساعدة يمكنك استخدامها من سطر الأوامر hf أو من بايثون.

فحص ذاكرة التخزين المؤقت من الطرفية

شغّل hf cache ls لاستكشاف ما هو مخزّن محليًا. افتراضيًا، تجمع الأوامر المعلومات حسب المستودع:

➜ hf cache ls
ID                                   SIZE   LAST_ACCESSED LAST_MODIFIED REFS
------------------------------------ ------- ------------- ------------- -------------------
dataset/glue                         116.3K 4 days ago     4 days ago     2.4.0 main 1.17.0
dataset/google/fleurs                 64.9M 1 week ago     1 week ago     main refs/pr/1
model/Jean-Baptiste/camembert-ner    441.0M 2 weeks ago    16 hours ago   main
model/bert-base-cased                  1.9G 1 week ago     2 years ago
model/t5-base                          10.1K 3 months ago   3 months ago   main
model/t5-small                        970.7M 3 days ago     3 days ago     main refs/pr/1

Found 6 repo(s) for a total of 12 revision(s) and 3.4G on disk.

أضف --revisions لعرض كل لقطة مخزّنة مؤقتًا، واربط عوامل التصفية للتركيز على ما يهم. تفهم عوامل التصفية الأحجام والمُدَد الصديقة للمستخدم، لذا تعمل تعبيرات مثل size>1GB أو accessed>30d مباشرةً:

➜ hf cache ls --revisions --filter "size>1GB" --filter "accessed>30d"
ID                                   REVISION            SIZE   LAST_MODIFIED REFS
------------------------------------ ------------------ ------- ------------- -------------------
model/bert-base-cased                6d1d7a1a2a6cf4c2    1.9G  2 years ago
model/t5-small                       1c610f6b3f5e7d8a    1.1G  3 months ago  main

Found 2 repo(s) for a total of 2 revision(s) and 3.0G on disk.

هل تحتاج إلى مخرجات صالحة للآلة؟ استخدم --format json للحصول على كائنات منظمة أو --format csv للجدول الإلكتروني. أو استخدم --quiet لطباعة المعرّفات فقط (واحد في كل سطر) حتى تتمكن من تمريرها إلى أدوات أخرى. استخدم --sort لترتيب الإدخالات حسب accessed أو modified أو name أو size (أضف :asc أو :desc للتحكم في الترتيب)، و--limit لتقييد النتائج بأفضل N إدخالات. اجمع هذه الخيارات مع --cache-dir عندما تحتاج إلى فحص ذاكرة تخزين مؤقت محفوظة خارج HF_HOME.

التصفية باستخدام أدوات shell الشائعة

يعني المخرجات الجدولية أنك تستطيع مواصلة استخدام الأدوات التي تعرفها بالفعل. على سبيل المثال، يحدد المقطع أدناه كل نسخة مخزنة مؤقتاً مرتبطة بـ t5-small:

➜ eval "hf cache ls --revisions" | grep "t5-small"
model/t5-small                       1c610f6b3f5e7d8a    1.1G  3 months ago  main
model/t5-small                       8f3ad1c90fed7a62    820.1M 2 weeks ago   refs/pr/1

فحص ذاكرة التخزين المؤقت من بايثون

للاستخدام الأكثر تقدماً، استخدم scan_cache_dir() وهو الأداة البرمجية بلغة بايثون التي يستدعيها أداة سطر الأوامر.

يمكنك استخدامه للحصول على تقرير مفصّل مبني حول 4 فئات بيانات:

إليك مثالًا بسيطًا للاستخدام. راجع المرجع للتفاصيل.

>>> from huggingface_hub import scan_cache_dir

>>> hf_cache_info = scan_cache_dir()
HFCacheInfo(
    size_on_disk=3398085269,
    repos=frozenset({
        CachedRepoInfo(
            repo_id='t5-small',
            repo_type='model',
            repo_path=PosixPath(...),
            size_on_disk=970726914,
            nb_files=11,
            last_accessed=1662971707.3567169,
            last_modified=1662971107.3567169,
            revisions=frozenset({
                CachedRevisionInfo(
                    commit_hash='d78aea13fa7ecd06c29e3e46195d6341255065d5',
                    size_on_disk=970726339,
                    snapshot_path=PosixPath(...),
                    # No `last_accessed` as blobs are shared among revisions
                    last_modified=1662971107.3567169,
                    files=frozenset({
                        CachedFileInfo(
                            file_name='config.json',
                            size_on_disk=1197
                            file_path=PosixPath(...),
                            blob_path=PosixPath(...),
                            blob_last_accessed=1662971707.3567169,
                            blob_last_modified=1662971107.3567169,
                        ),
                        CachedFileInfo(...),
                        ...
                    }),
                ),
                CachedRevisionInfo(...),
                ...
            }),
        ),
        CachedRepoInfo(...),
        ...
    }),
    warnings=[
        CorruptedCacheException("Snapshots dir doesn't exist in cached repo: ..."),
        CorruptedCacheException(...),
        ...
    ],
)

تحقق من ذاكرتك المؤقتة

يمكن لـhuggingface_hub التحقق من تطابق الملفات المخزنة مؤقتًا لديك مع قيم التجزئة (checksums) على Hub. استخدم أمر hf cache verify في سطر الأوامر للتحقق من اتساق الملفات لإصدار محدد من مستودع محدد:

>>> hf cache verify meta-llama/Llama-3.2-1B-Instruct
✅ Verified 13 file(s) for 'meta-llama/Llama-3.2-1B-Instruct' (model) in ~/.cache/huggingface/hub/models--meta-llama--Llama-3.2-1B-Instruct/snapshots/9213176726f574b556790deb65791e0c5aa438b6
  All checksums match.

تحقّق من نسخة مخزّنة محددة:

>>> hf cache verify meta-llama/Llama-3.1-8B-Instruct --revision 0e9e39f249a16976918f6564b8830bc894c89659

راجع مرجع سطر الأوامر hf cache verify لمزيد من التفاصيل حول الاستخدام وقائمة كاملة بالخيارات.

تنظيف ذاكرة التخزين المؤقت

إن مسح ذاكرة التخزين المؤقت أمر مثير للاهتمام، لكن ما تريد فعله عادةً بعد ذلك هو حذف بعض الأجزاء لتحرير مساحة على القرص. وهذا ممكن باستخدام أوامر سطر الأوامر hf cache rm وhf cache prune. كما يمكن استخدام الدوال المساعدة delete_revisions() وdelete_files() برمجياً من كائن HFCacheInfo الذي يُعاد عند مسح ذاكرة التخزين المؤقت.

استراتيجية الحذف

لحذف بعض البيانات المؤقتة، يجب عليك تمرير قائمة بالمراجعات المراد حذفها. سيعرّف الأداة استراتيجية لتحرير المساحة بناءً على هذه القائمة. وتعيد كائن DeleteCacheStrategy يصف الملفات والمجلدات التي سيتم حذفها. يتيح لك DeleteCacheStrategy معرفة مقدار المساحة المتوقعة للتحرير. بمجرد موافقتك على الحذف، يجب عليك تنفيذه لجعل الحذف ساري المفعول. ولتجنب أي تناقضات، لا يمكنك تعديل كائن الاستراتيجية يدويًا.

الاستراتيجية لحذف المراجعات هي كالتالي:

  • يتم حذف مجلد snapshot الذي يحتوي على روابط الرمزات (symlinks) للإصدارات.
  • تُحذف ملفات blobs التي تستهدفها فقط المراجعات المزمع حذفها.
  • إذا كان هناك ارتباط بين نسخة واحدة أو أكثر من refs، يتم حذف المراجع.
  • إذا تم حذف جميع المراجعات من مستودع، يتم حذف المستودع المخزّن مؤقتًا بالكامل.

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

تُعدّ تجزئات المراجعات فريدة عبر جميع المستودعات. لذلك، يقبل hf cache rm إما معرّف مستودع (مثل model/bert-base-uncased) أو تجزئة مراجعة مجردة؛ وعند تمرير تجزئة، لا حاجة إلى تحديد المستودع بشكل منفصل.

إذا لم يُعثر على نسخة (revision) في ذاكرة التخزين المؤقت، فسيتم تجاهلها بصمت. بالإضافة إلى ذلك، إذا تعذّر العثور على ملف أو مجلد أثناء محاولة حذفه، فسيُسجَّل تحذير لكن لن يتم طرح خطأ. يستمر الحذف بالنسبة للمسارات الأخرى الموجودة في كائن DeleteCacheStrategy.

تنظيف ذاكرة التخزين المؤقت من الطرفية

استخدم hf cache rm لحذف المستودعات أو المراجعات نهائياً من ذاكرتك المؤقتة. مرّر معرّف مستودع واحد أو أكثر (على سبيل المثال model/bert-base-uncased) أو تجزئات المراجعة:

➜ hf cache rm model/bert-base-cased
About to delete 1 repo(s) totalling 1.9G.
  - model/bert-base-cased (entire repo)
Proceed with deletion? [y/N]: y
Deleted 1 repo(s) and 1 revision(s); freed 1.9G.

يمكنك أيضًا استخدام hf cache rm بالاقتران مع hf cache ls --quiet لحذف العناصر المحددة بواسطة عامل تصفية دفعة واحدة:

>>> hf cache rm $(hf cache ls --filter "accessed>1y" -q) -y
About to delete 2 repo(s) totalling 5.31G.
  - model/meta-llama/Llama-3.2-1B-Instruct (entire repo)
  - model/hexgrad/Kokoro-82M (entire repo)
Deleted 2 repo(s) and 2 revision(s); freed 5.31G.

اخلط المستودعات والمراجعات في نفس الاستدعاء. أضف --dry-run لمعاينة الأثر، أو --yes لتخطي مطالبة التأكيد عند استخدام السكربتات:

➜ hf cache rm model/t5-small 8f3ad1c --dry-run
About to delete 1 repo(s) and 1 revision(s) totalling 1.1G.
  - model/t5-small:
      8f3ad1c [main] 1.1G
Dry run: no files were deleted.

لإزالة ملف واحد بدلاً من مستودع كامل، على سبيل المثال كميّة GGUF واحدة، مرّر عنوان URI للملف بصيغة hf://. يُزال الملف من كل نسخة مخبأة من المستودع، ولا يُحذف blob الخاص به إلا إذا لم يكن أي ملف مخبأ آخر لا يزال يشير إليه. تبقى النسخة قابلة للاستخدام، ويُعاد تنزيل الملف المحذوف في المرة التالية التي يُحتاج فيها. يجب أن تتطابق المسارات تمامًا: لا يتم دعم المجلدات أو أنماط glob.

➜ hf cache rm hf://models/unsloth/gemma-3-27b-it-GGUF/gemma-3-27b-it-Q4_K_M.gguf --dry-run
About to delete 1 file(s) totalling 16.5G.
  - model/unsloth/gemma-3-27b-it-GGUF@3f4b5c1d2e6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c/gemma-3-27b-it-Q4_K_M.gguf
Dry run: no files were deleted.

عند العمل خارج موقع التخزين المؤقت الافتراضي، اجمع الأمر مع --cache-dir PATH.

لتنظيف مخلفات ذاكرة التخزين المؤقت دفعة واحدة، شغّل hf cache prune. يحذف تلقائيًا المراجعات التي لم تعد تشير إليها أي فرع أو وسم، وملفات .incomplete المتبقية من عمليات تنزيل انقطعت، والكتل المشتركة التي لم تعد تشير إليها أي مستودع مخزّن مؤقتًا:

➜ hf cache prune
About to delete 3 unreferenced revision(s) and 2 incomplete download(s) (2.4G total).
  - model/t5-small:
      1c610f6b [refs/pr/1] 820.1M
      d4ec9b72 [(detached)] 640.5M
  - dataset/google/fleurs:
      2b91c8dd [(detached)] 937.6M
Proceed? [y/N]: y
Deleted 3 unreferenced revision(s) and 2 incomplete download(s); freed 2.4G.

ملفات .incomplete هي كتل جزئية تُترك خلفها عندما ينقطع التحميل. وهي غير مُتبعة بواسطة الفحص القائم على المراجعات، لذا فإن hf cache ls يكتفي بإبرازها مع تلميح (Found X incomplete download(s) ...) بينما الأمر hf cache prune هو الذي يقوم فعليًا بإزالتها. ولا يمس hf cache rm هذه الملفات أبدًا، باستثناء حالة حذف مستودع كامل.

تدعم كلا الأمرين --dry-run و--yes و--cache-dir مما يتيح لك معاينة العمليات، وأتمتتها، وتحديد مسارات ذاكرة تخزين مؤقت بديلة حسب الحاجة.

تنظيف ذاكرة التخزين المؤقت من بايثون

لمزيد من المرونة، يمكنك أيضًا استخدام طريقة delete_revisions() برمجيًا. إليك مثالًا بسيطًا. راجع المرجع للتفاصيل.

>>> from huggingface_hub import scan_cache_dir

>>> delete_strategy = scan_cache_dir().delete_revisions(
...     "81fd1d6e7847c99f5862c9fb81387956d99ec7aa"
...     "e2983b237dccf3ab4937c97fa717319a9ca1a96d",
...     "6c0e6080953db56375760c0471a8c5f2929baf11",
... )
>>> print("Will free " + delete_strategy.expected_freed_size_str)
Will free 8.6G

>>> delete_strategy.execute()
Update on GitHub