Hub Python Library documentation
رفع الملفات إلى Hub
رفع الملفات إلى Hub
تُعد مشاركة ملفاتك وأعمالك جانبًا مهمًا من جوانب الـ Hub. يوفر huggingface_hub عدة خيارات لرفع ملفاتك إلى الـ Hub. يمكنك استخدام هذه الدوال بشكل مستقل أو دمجها في مكتبتك، مما يجعل تفاعل مستخدميك مع الـ Hub أكثر راحة.
عندما ترغب في رفع ملفات إلى Hub، يجب عليك تسجيل الدخول إلى حسابك على Hugging Face. لمزيد من التفاصيل حول المصادقة، راجع هذا القسم.
رفع ملف
بمجرد إنشاء مستودع باستخدام create_repo()، يمكنك رفع ملف إلى مستودعك باستخدام upload_file().
حدد مسار الملف الذي تريد رفعه، والموقع الذي تريد رفع الملف إليه داخل المستودع، واسم المستودع الذي تريد إضافة الملف إليه. اعتمادًا على نوع المستودع، يمكنك اختيارًا تحديد نوع المستودع كـdataset أو model أو space.
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.upload_file(
... path_or_fileobj="/path/to/local/folder/README.md",
... path_in_repo="README.md",
... repo_id="username/test-dataset",
... repo_type="dataset",
... )رفع مجلد
استخدم دالة upload_folder() لرفع مجلد محلي إلى مستودع قائم. حدد مسار المجلد المحلي المراد رفعه، والموقع الذي تريد رفع المجلد إليه داخل المستودع، واسم المستودع الذي تريد إضافة المجلد إليه. اعتمادًا على نوع المستودع، يمكنك اختياريًا تحديد نوع المستودع كـ dataset أو model أو space.
>>> from huggingface_hub import HfApi
>>> api = HfApi()
# Upload all the content from the local folder to your remote Space.
# By default, files are uploaded at the root of the repo
>>> api.upload_folder(
... folder_path="/path/to/local/space",
... repo_id="username/my-cool-space",
... repo_type="space",
... )بشكل افتراضي، يُؤخذ ملف .gitignore في الاعتبار لمعرفة الملفات التي يجب إدراجها في المستودع أو عدم إدراجها. افتراضيًا، نتحقق من وجود ملف .gitignore في عملية الإدراج، وإذا لم يكن موجودًا، نتحقق من وجوده على Hub. يرجى العلم أنه لن يُستخدم إلا ملف .gitignore الموجود في جذر المجلد. لا نتحقق من ملفات .gitignore في المجلدات الفرعية.
إذا كنت لا تريد استخدام ملف .gitignore مُضمَّن مسبقًا، يمكنك استخدام الحججين allow_patterns وignore_patterns لتصفية الملفات المراد رفعها. تقبل هذه المعاملات نمطًا واحدًا أو قائمة بأنماط. الأنماط هي برتقالات قياسية (أنماط globbing) كما هو موثق هنا. إذا تم تقديم كل من allow_patterns وignore_patterns، فإن كلا القيدين يُطبَّقان.
بجانب ملف .gitignore وأنماط السماح/التجاهل، سيتم تجاهل أي مجلد .git/ موجود في أي مجلد فرعي.
>>> api.upload_folder(
... folder_path="/path/to/local/folder",
... path_in_repo="my-dataset/train", # Upload to a specific folder
... repo_id="username/test-dataset",
... repo_type="dataset",
... ignore_patterns="**/logs/*.txt", # Ignore all text logs
... )يمكنك أيضًا استخدام الحجة delete_patterns لتحديد الملفات التي تريد حذفها من المستودع في نفس الالتزام.
قد يكون ذلك مفيدًا إذا كنت ترغب في تنظيف مجلد بعيد قبل دفع الملفات إليه ولا تعرف أي الملفات موجودة بالفعل.
يرفع المثال أدناه المجلد المحلي ./logs إلى المجلد البعيد /experiment/logs/. يتم رفع ملفات txt فقط،
لكن قبل ذلك، يتم حذف جميع السجلات السابقة على المستودع. كل هذا في التزام الواحد.
>>> api.upload_folder(
... folder_path="/path/to/local/folder/logs",
... repo_id="username/trained-model",
... path_in_repo="experiment/logs/",
... allow_patterns="*.txt", # Upload all local text files
... delete_patterns="*.txt", # Delete all remote text files before
... )كيفية رفع الملفات
عند تثبيت hf_xet (وهو ما يحدث افتراضيًا)، يقوم upload_folder() برفع الملفات عبر خط أنابيب متدفق: حيث تُفحص الملفات مقابل Hub، ثم تُرفع إلى وحدة تخزين Xet (التي تقوم بتقسيم الملفات وإزالة التكرار وإعادة محاولة النقل داخليًا)، وتُلتزم في دفعات تكيفية، وكل ذلك بالتوازي. عمليًا، يعني هذا:
- مجلدات بأي حجم: تُرفع المجلدات الصغيرة في التزام الواحد، بينما تُقسَّم المجلدات التي تحتوي على عدد كبير من الملفات تلقائيًا إلى عدة التزامات للبقاء ضمن حدود الخادم. عند حدوث ذلك، تُضاف لاحقة
(part 2)،(part 3)، … إلى رسالة الالتزامات اللاحقة. - قابلة للاستئناف: إذا انقطع الرفع لأي سبب، ما عليك سوى إعادة تشغيل نفس الاستدعاء. يتم اكتشاف الملفات التي تم التثبيت بالفعل وتخطيها، ويتم إزالة التكرار من المقاطع التي تم رفعها بالفعل — فإعادة رفعها لا تنقل (تقريبًا) أي بيانات. لا يتدخل أي حالة محلية: يمكنك حتى الاستئناف من جهاز مختلف. استثناء واحد: عند استخدام
create_pr=True، يؤدي إعادة التشغيل إلى فتح طلب سحب جديد. ننصح بإعادة التشغيل باستخدامrevision="refs/pr/N"بدلاً من ذلك عند استئناف الرفع. - لا يوجد قراءة مزدوجة: يتم تجزئة الملفات وتوليد قيم التجزئة (hash) أثناء تقسيمها للرفع في عملية قراءة واحدة. لا توجد مرحلة "تجزئة" منفصلة قبل بدء الرفع.
يعمل عرض التقدم المباشر على تتبع المراحل الثلاث:
Found 5,000 files to upload
Preparing ████████████████████ 5,000 / 5,000 ✓
Uploading ██████████████░░░░░░ 423 / 603 files 3.8GB · 19.7MB/s
Committing ██████████████████░░ 4,580 / 5,000 6 commitsإذا لم يكن hf_xet مثبّتًا، فإن upload_folder() يعود إلى السلوك القديم: يقوم بتجزئة كل شيء أولاً، ثم يرفع الملفات عبر HTTP، ثم ينشئ التزام الواحد. ننصح دائمًا بإبقاء hf_xet مثبّتًا لضمان متانة أفضل
الرفع من سطر الأوامر
يمكنك استخدام أمر hf upload من الطرفية لرفع الملفات مباشرةً إلى Hub. يستخدم داخليًا نفس أدوات المساعدة upload_file() وupload_folder() الموصوفة أعلاه.
يمكنك إما رفع ملف واحد أو مجلد كامل:
# Usage: hf upload [repo_id] [local_path] [path_in_repo]
>>> hf upload Wauplin/my-cool-model ./models/model.safetensors model.safetensors
https://huggingface.co/Wauplin/my-cool-model/blob/main/model.safetensors
>>> hf upload Wauplin/my-cool-model ./models .
https://huggingface.co/Wauplin/my-cool-model/tree/mainlocal_path وpath_in_repo اختيارية ويمكن استنتاجها ضمنيًا. إذا لم يتم تعيين local_path، فسيتحقق الأداة مما إذا كان هناك مجلد أو ملف محلي يحمل نفس اسم repo_id. في هذه الحالة، سيتم رفع محتواه. وإلا، فسيتم رفع استثناء يطلب من المستخدم تعيين local_path بشكل صريح. وفي جميع الأحوال، إذا لم يتم تعيين path_in_repo، فسيتم رفع الملفات في جذر المستودع.
يمكن أيضًا التعبير عن الوجهة كوحدة عنوان hf:// واحدة تتبع القواعد النحوية hf://[<TYPE>/]<ID>[@<REVISION>][/<PATH>] (انظر مرجع وحدات عنوان HF للحصول على الصياغة الكاملة). ثم يتم قراءة نوع المستودع والمراجعة وpath_in_repo من وحدة العنوان، والتي لا يمكن دمجها مع خيارات --repo-type و--revision:
# Upload a single file to a dataset on a specific branch
>>> hf upload hf://datasets/Wauplin/my-cool-dataset@my-branch/data/train.csv ./train.csv
https://huggingface.co/datasets/Wauplin/my-cool-dataset/blob/my-branch/data/train.csvلحصول على أقصى معدل رفع للبيانات في الملفات الكبيرة، اضبط متغير البيئة
HF_XET_HIGH_PERFORMANCE=1. يتيح هذا وضع الأداء العالي فيhf_xet، والذي يستنفد النطاق الترددي المتاح وأنوية المعالج. ملاحظة: لم يعد يُستخدم علمHF_HUB_ENABLE_HF_TRANSFER=1القديم بعد إزالةhf_transferلصالحhf_xet— اضبطHF_XET_HIGH_PERFORMANCE=1بدلاً من ذلك.
لمزيد من التفاصيل حول أمر الرفع عبر سطر الأوامر، يُرجى الرجوع إلى دليل سطر الأوامر.
رفع مجلد كبير
يُعدّ upload_folder() وأمر hf upload الحلَّين الأساسيين لرفع الملفات إلى Hub، بما في ذلك المجلدات الكبيرة جداً. تُبَثّ الملفات إلى Hub عبر عدة التزامات، ويُستأنف العملية تلقائياً إذا انقطعت. ما عليك سوى إعادة تشغيل نفس الاستدعاء، وستُتخطى الملفات التي تم رفعها مسبقاً.
>>> api.upload_folder(
... repo_id="HuggingFaceM4/Docmatix",
... repo_type="dataset",
... folder_path="/path/to/local/docmatix",
... )أو من الطرفية:
hf upload HuggingFaceM4/Docmatix --repo-type=dataset /path/to/local/docmatix
نصائح وحيل للرفع الكبير
توجد بعض القيود التي يجب الانتباه إليها عند التعامل مع كميات كبيرة من البيانات في مستودعك. فبسبب الوقت الذي يستغرقه بث البيانات، قد يكون منزعجًا جدًا أن تفشل عملية الرفع/الدفع في نهاية العملية، أو أن تواجه تجربة متدهورة، سواء على hf.co أو عند العمل محليًا.
اطّلع على دليلنا قيود المستودعات والتوصيات لمعرفة أفضل الممارسات حول كيفية تنظيم مستودعاتك على Hub. لننتقل الآن إلى بعض النصائح العملية لجعل عملية الرفع سلسة قدر الإمكان.
- ابدأ بحجم صغير: ننصحك بالبدء بكمية صغيرة من البيانات لاختبار سكربت الرفع الخاص بك. من الأسهل إجراء تعديلات على السكربت عندما يستغرق الفشل القليل من الوقت فقط.
- توقّع حدوث أعطال: تدفّق كميات كبيرة من البيانات أمرٌ صعب. لا تعرف ما الذي قد يحدث، لكن من الأفضل دائمًا أن تفترض أن شيئًا ما سيفشل مرة واحدة على الأقل - سواء كان السبب جهازك، أو اتصالك، أو خوادمنا. على سبيل المثال، إذا كنت تخطط لرفع عدد كبير من الملفات، فمن الأفضل أن تتتبع محليًا الملفات التي رفعتها بالفعل قبل رفع الدفعة التالية. يُضمن لك أن ملف LFS مُلتزمًا بالفعل لن يُرفع مرتين، لكن التحقق منه على جانب العميل قد يوفر بعض الوقت. وهذا ما يفعله upload_folder() من أجلك.
- استخدم
hf_xet: يستفيد هذا من نظام التخزين الجديد الخاص بـ Hub، وهو مكتوب بلغة Rust، وأصبح متاحًا الآن للجميع للاستخدام. في الواقع،hf_xetمفعّل افتراضيًا عند استخدامhuggingface_hub! للحصول على أقصى أداء، اضبطHF_XET_HIGH_PERFORMANCE=1كمتغير بيئة. انتبه إلى أنه عند تفعيل وضع الأداء العالي، سيحاول الأداة استخدام كل النطاق الترددي ونوى المعالج المركزية المتاحة.
الميزات المتقدمة
في معظم الحالات، لن تحتاج إلى أكثر من upload_file() و upload_folder() لرفع ملفاتك إلى Hub.
ومع ذلك، يوفر huggingface_hub ميزات متقدمة أكثر لتسهيل الأمور. دعونا نلقي نظرة عليها!
تحميلات أسرع
استفد من عمليات رفع أسرع عبر hf_xet، وهي واجهة بايثون لمكتبة xet-core التي تتيح إزالة التكرار على أساس المقاطع (chunks) لرفع وتنزيل أسرع. يتكامل hf_xet بسلاسة مع huggingface_hub، لكنه يستخدم مكتبة xet-core بلغة Rust وتخزين Xet بدلاً من LFS.
hf_xet يستخدم نظام تخزين Xet، الذي يقسم الملفات إلى مقاطع غير قابلة للتغيير، ويخزّن مجموعات من هذه المقاطع (المعروفة باسم blocks أو xorbs) عن بُعد، ويستعيدها لإعادة تجميع الملف عند الطلب. عند الرفع، وبعد التأكد من أن المستخدم مصرّح له بالكتابة في هذا المستودع، يقوم hf_xet بمسح الملفات، وقسمتها إلى مقاطعها، وجمع تلك المقاطع في xorbs (مع إزالة التكرار عبر المقاطع المعروفة)، ثم يقوم برفع هذه الـ xorbs إلى خدمة Xet القابلة للعنوان بالمحتوى (CAS)، والتي ستتحقق من سلامة الـ xorbs، وتسجّل بيانات الـ xorb الوصفية مع تجزئة LFS SHA256 (لدعم الاستعلام/التنزيل)، وتكتب الـ xorbs في التخزين عن بُعد.
لتفعيله، ما عليك سوى تثبيت أحدث إصدار من huggingface_hub:
pip install -U "huggingface_hub"بدايةً من huggingface_hub 0.32.0، سيؤدي هذا أيضًا إلى تثبيت hf_xet.
ستواصل جميع واجهات huggingface_hub الأخرى العمل دون أي تعديل. لمعرفة المزيد حول فوائد تخزين Xet وhf_xet، راجع هذا القسم.
اعتبارات رفع الملفات إلى نظام الملفات الموزّع / العنقود
عند الرفع من عناقيد الحوسبة، غالبًا ما تكون الملفات المراد رفعها مقيمةً على نظام ملفات موزّع أو شبكي (NFS، EBS، Lustre، Fsx، إلخ). سيقوم تخزين Xet بتقسيم تلك الملفات إلى أجزاء وكتابتها محليًا في كتل (تُسمى أيضًا xorbs)، وبعد اكتمال الكتل سيُرفعها. لتحسين الأداء عند الرفع من نظام ملفات موزّع، تأكد من تعيين HF_XET_CACHE إلى مجلد يقع على قرص محلي (مثل قرص NVMe أو SSD محلي). الموقع الافتراضي لذاكرة التخزين المؤقت لـ Xet هو تحت HF_HOME في (~/.cache/huggingface/xet)، وغالبًا ما يقع هذا المسار داخل مجلد المستخدم الرئيسي الذي يكون بدوره على نظام الملفات الموزّع.
الرفع غير الحاسم
في بعض الحالات، ترغب في دفع البيانات دون تعطيل الخيط الرئيسي. وهذا مفيد بشكل خاص لرفع السجلات والمخرجات مع الاستمرار في التدريب. للقيام بذلك، يمكنك استخدام الحجة run_as_future في كل من upload_file() وupload_folder(). سيعيد هذا كائن concurrent.futures.Future يمكنك استخدامه للتحقق من حالة الرفع.
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> future = api.upload_folder( # Upload in the background (non-blocking action)
... repo_id="username/my-model",
... folder_path="checkpoints-001",
... run_as_future=True,
... )
>>> future
Future(...)
>>> future.done()
False
>>> future.result() # Wait for the upload to complete (blocking action)
...تُضاف المهام في الخلفية إلى قائمة الانتظار عند استخدام
run_as_future=True. وهذا يعني أنك مضمون أن المهام ستُنفَّذ بالترتيب الصحيح.
على الرغم من أن المهام في الخلفية مفيدة في الغالب لرفع البيانات/إنشاء التزامات، إلا أنه يمكنك وضع أي طريقة تريدها في قائمة الانتظار باستخدام run_as_future(). على سبيل المثال، يمكنك استخدامه لإنشاء مستودع ثم رفع البيانات إليه في الخلفية. إن الحجة المدمجة run_as_future في طرق الرفع ليست سوى اسم مستعار حولها.
>>> from huggingface_hub import HfApi
>>> api = HfApi()
>>> api.run_as_future(api.create_repo, "username/my-model", exists_ok=True)
Future(...)
>>> api.upload_file(
... repo_id="username/my-model",
... path_in_repo="file.txt",
... path_or_fileobj=b"file content",
... run_as_future=True,
... )
Future(...)نسخ الملفات بين المستودعات
استخدم copy_files() لنسخ الملفات أو المجلدات بين المستودعات على Hub دون الحاجة إلى تنزيل البيانات الكبيرة أو إعادة رفعها. وهذا مفيد عندما تريد تكرار الأوزان عبر متغيرات النموذج، أو نسخ ملفات مجموعة البيانات بين المستودعات، أو إعادة تنظيم الملفات عبر مستودعاتك. في الخلفية، يقوم بإنشاء التزامن (commit) باستخدام عمليات CommitOperationCopy.
>>> from huggingface_hub import HfApi
>>> api = HfApi()
# Copy a single file between repos
>>> api.copy_files(
... "hf://username/source-model/weights.safetensors",
... "hf://username/target-model/weights.safetensors",
... )
# Copy an entire folder
>>> api.copy_files(
... "hf://datasets/username/source-dataset/data/",
... "hf://datasets/username/target-dataset/data/",
... )يمكنك أيضًا النسخ داخل المستودع نفسه:
# Duplicate a file in the same repo
>>> api.copy_files(
... "hf://username/my-model/config.json",
... "hf://username/my-model/backup/config.json",
... )عند نسخ مجلد، فإن وجود
/في نهاية المسار المصدر يعني استخدام دلالات على غرار rsync، حيث يتم نسخ محتويات المجلد دون تضمين المجلد نفسه. أما في حال عدم وجود/في النهاية، فيتم تضمين المجلد نفسه في الوجهة.
يدعم copy_files() أيضًا نسخ الملفات إلى Buckets. راجع دليل Buckets لمزيد من التفاصيل.
الرفع المجدول
يُسهّل Hugging Face Hub حفظ البيانات وإدارة إصداراتها. ومع ذلك، توجد بعض القيود عند تحديث نفس الملف آلاف المرات. على سبيل المثال، قد ترغب في حفظ سجلات عملية تدريب أو ملاحظات المستخدمين على مساحة (Space) مُنفَّذة. في هذه الحالات، يكون رفع البيانات كمجموعة بيانات (dataset) على الـ Hub منطقياً، لكن قد يكون من الصعب القيام بذلك بشكل صحيح. والسبب الرئيسي هو أنك لا تريد إصدار كل تحديث لبياناتك لأن ذلك سيجعل مستودع git غير قابل للاستخدام. تقدم فئة CommitScheduler حلاً لهذه المشكلة.
الفكرة هي تشغيل مهمة في الخلفية تقوم بشكل دوري بدفع مجلد محلي إلى Hub. لنفترض أن لديك مساحة Gradio تستقبل نصًا كمدخل وتولّد ترجمتين له. ثم يمكن للمستخدم اختيار الترجمة المفضلة لديه. ولكل تشغيل، تريد حفظ المدخل والمخرج وتفضيل المستخدم لتحليل النتائج. هذا استخدام مثالي لـ CommitScheduler؛ فأنت تريد حفظ البيانات في Hub (ربما ملايين من ملاحظات المستخدمين)، لكنك لا تحتاج إلى حفظ مدخلات كل مستخدم في الوقت الفعلي. بدلاً من ذلك، يمكنك حفظ البيانات محليًا في ملف JSON ورفعها كل 10 دقائق. على سبيل المثال:
>>> import json
>>> import uuid
>>> from pathlib import Path
>>> import gradio as gr
>>> from huggingface_hub import CommitScheduler
# Define the file where to save the data. Use UUID to make sure not to overwrite existing data from a previous run.
>>> feedback_file = Path("user_feedback/") / f"data_{uuid.uuid4()}.json"
>>> feedback_folder = feedback_file.parent
# Schedule regular uploads. Remote repo and local folder are created if they don't already exist.
>>> scheduler = CommitScheduler(
... repo_id="report-translation-feedback",
... repo_type="dataset",
... folder_path=feedback_folder,
... path_in_repo="data",
... every=10,
... )
# Define the function that will be called when the user submits its feedback (to be called in Gradio)
>>> def save_feedback(input_text:str, output_1: str, output_2:str, user_choice: int) -> None:
... """
... Append input/outputs and user feedback to a JSON Lines file using a thread lock to avoid concurrent writes from different users.
... """
... with scheduler.lock:
... with feedback_file.open("a") as f:
... f.write(json.dumps({"input": input_text, "output_1": output_1, "output_2": output_2, "user_choice": user_choice}))
... f.write("\n")
# Start Gradio
>>> with gr.Blocks() as demo:
>>> ... # define Gradio demo + use `save_feedback`
>>> demo.launch()وهذا كل ما في الأمر! ستكون مدخلات ومخرجات المستخدم والتغذية الراجعة متاحة كمجموعة بيانات على الـ Hub. من خلال استخدام اسم ملف JSON فريد، يُضمن لك أنك لن تُغَيِّر بيانات من تشغيل سابق أو بيانات من مساحات/نسخ أخرى تُرسل بياناتها بالتوازي إلى نفس المستودع.
لمزيد من التفاصيل حول CommitScheduler، إليك ما تحتاج إلى معرفته:
- إضافة فقط: يُفترض أنك ستضيف المحتوى إلى المجلد فقط. يجب عليك إما إضافة البيانات إلى الملفات الموجودة أو إنشاء ملفات جديدة. قد يؤدي حذف ملف أو الكتابة فوقه إلى إتلاف مستودعك.
- سجل git:
سيُجري المُجدوِل (scheduler) عملية commit على المجلد كل
everyدقيقة. لتجنّب تلويث مستودع git بشكل مفرط، يُوصى بتعيين قيمة دنيا قدرها 5 دقائق. علاوة على ذلك، صُمم المُجدوِل لتجنّب عمليات commit الفارغة. إذا لم يُكتشف أي محتوى جديد في المجلد، تُهمل عملية commit المجدولة. - الأخطاء: يعمل المجدول كخيط في الخلفية. يبدأ عند إنشاء الكائن ويستمر في العمل حتى يتم استدعاء
stop()أو حتى ينتهي العملية. إذا حدث خطأ أثناء الرفع (على سبيل المثال: مشكلة في الاتصال)، يتم تسجيل الخطأ ويعيد المجدول المحاولة في الالتزام المجدول التالي. - scripts: في سكربت ذي عمر محدود (مثل التدريب)، استخدم المجدول كمدير سياق. عند مغادرة كتلة
withيتم تشغيل رفع أخير، وانتظار اكتماله، وإيقاف المجدول. - سلامة الخيوط: في معظم الحالات، من الآمن افتراض أنه يمكنك الكتابة إلى ملف دون الحاجة إلى القلق بشأن ملف القفل. لن ينهار المجدول أو يتلف إذا قمت بكتابة محتوى في المجلد أثناء رفعه. عمليًا، من الممكن حدوث مشاكل في التزامن للتطبيقات ذات الحمل الثقيل. في هذه الحالة، ننصح باستخدام قفل
scheduler.lockلضمان سلامة الخيوط. يُحظر القفل فقط عندما يفحص المجدول المجلد بحثًا عن التغييرات، وليس عند رفع البيانات. يمكنك افتراض بأمان أنه لن يؤثر على تجربة المستخدم في مساحتك.
عرض الديمو الخاص بالحفظ في المساحة
يُعدّ حفظ البيانات من مساحة إلى مجموعة بيانات على المنصة الاستخدام الرئيسي لـ CommitScheduler. اعتمادًا على حالة الاستخدام، قد ترغب في هيكلة بياناتك بشكل مختلف. يجب أن تكون البنية قوية تجاه المستخدمين المتزامنين وإعادة التشغيل، مما يعني غالبًا توليد معرّفات فريدة (UUIDs). بالإضافة إلى المتانة، يجب رفع البيانات بتنسيق قابل للقراءة بواسطة مكتبة 🤗 Datasets لإعادة استخدامها لاحقًا. أنشأنا Space يوضح كيفية حفظ عدة تنسيقات بيانات مختلفة (قد تحتاج إلى تكييفها لتلبية احتياجاتك الخاصة).
الرفع المخصص
يفترض CommitScheduler أن بياناتك تُضاف فقط (append-only) ويجب رفعها “كما هي”. ومع ذلك، قد ترغب في تخصيص طريقة رفع البيانات. يمكنك القيام بذلك بإنشاء فئة ترث من CommitScheduler وإعادة كتابة طريقة push_to_hub (يمكنك إعادة كتابتها بالطريقة التي تناسبك). يُضمن لك أنها ستُستدعى كل every دقائق في خيط خلفية. لا عليك القلق بشأن التزامن والأخطاء، لكن يجب أن تكون حذراً بشأن جوانب أخرى، مثل دفع التزامات فارغة أو تكرار البيانات.
في المثال المبسّط أدناه، نعيد كتابة push_to_hub لضغط جميع ملفات PNG في أرشيف واحد لتجنّب إجهاد المستودع على Hub:
class ZipScheduler(CommitScheduler):
def push_to_hub(self):
# 1. List PNG files
png_files = list(self.folder_path.glob("*.png"))
if len(png_files) == 0:
return None # return early if nothing to commit
# 2. Zip png files in a single archive
with tempfile.TemporaryDirectory() as tmpdir:
archive_path = Path(tmpdir) / "train.zip"
with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as zip:
for png_file in png_files:
zip.write(filename=png_file, arcname=png_file.name)
# 3. Upload archive
self.api.upload_file(..., path_or_fileobj=archive_path)
# 4. Delete local png files to avoid re-uploading them later
for png_file in png_files:
png_file.unlink()عندما تقوم بإعادة كتابة push_to_hub، يصبح بإمكانك الوصول إلى خصائص CommitScheduler، ولا سيما:
- عميل HfApi:
api - معاملات المجلد:
folder_pathوpath_in_repo - معاملات المستودع:
repo_id،repo_type،revision - قفل الخيط:
lock
لمزيد من الأمثلة على مجدولات مخصصة، اطّلع على مساحة العرض التوضيحي الخاصة بنا التي تتضمن تنفيذات مختلفة بناءً على حالات الاستخدام لديك.
create_commit
تُعد دالتا upload_file() و upload_folder() واجهات برمجة تطبيقات عالية المستوى تكون مريحة للاستخدام بشكل عام. ننصح بمحاولة استخدام هذه الدوال أولاً إذا لم تكن بحاجة إلى العمل على مستوى أدنى. ومع ذلك، إذا كنت ترغب في العمل على مستوى الالتزام (commit)، فيمكنك استخدام دالة create_commit() مباشرة.
هناك ثلاثة أنواع من العمليات التي يدعمها create_commit():
يرفع CommitOperationAdd ملفًا إلى Hub. إذا كان الملف موجودًا مسبقًا، يتم استبدال محتوياته. تقبل هذه العملية حجتين:
path_in_repo: مسار المستودع الذي سيتم رفع الملف إليه.path_or_fileobj: إما مسار إلى ملف على نظام الملفات لديك أو كائن يشبه الملف. هذا هو محتوى الملف الذي سيتم رفعه إلى Hub.
يحذف CommitOperationDelete ملفًا أو مجلدًا من المستودع. تقبل هذه العملية
path_in_repoكحجة.ينسخ CommitOperationCopy ملفًا داخل مستودع أو بين مستودعات. تقبل هذه العملية الحُجج التالية:
src_path_in_repo: مسار المستودع للملف الذي سيتم نسخه.path_in_repo: مسار المستودع الذي يجب نسخ الملف إليه.src_revision: اختياري - إصدار الملف الذي تريد نسخه إذا كنت ترغب في نسخ ملف من فرع/إصدار مختلف.src_repo_id: اختياري - المستودع المصدر الذي سيتم النسخ منه (مثلًا"username/source-model"). الافتراضي هو المستودع الوجهة.src_repo_type: اختياري - نوع المستودع المصدر ("model"،"dataset"أو"space"). مطلوب عند تعيينsrc_repo_id.
على سبيل المثال، إذا كنت ترغب في رفع ملفين وحذف ملف في مستودع Hub:
- استخدم
CommitOperationالمناسب لإضافة ملف أو حذفه، ولحذف مجلد:
>>> from huggingface_hub import HfApi, CommitOperationAdd, CommitOperationDelete
>>> api = HfApi()
>>> operations = [
... CommitOperationAdd(path_in_repo="LICENSE.md", path_or_fileobj="~/repo/LICENSE.md"),
... CommitOperationAdd(path_in_repo="weights.h5", path_or_fileobj="~/repo/weights-final.h5"),
... CommitOperationDelete(path_in_repo="old-weights.h5"),
... CommitOperationDelete(path_in_repo="logs/"),
... CommitOperationCopy(src_path_in_repo="image.png", path_in_repo="duplicate_image.png"),
... ]- مرّر عملياتك إلى create_commit():
>>> api.create_commit(
... repo_id="lysandre/test-model",
... operations=operations,
... commit_message="Upload my model weights and license",
... )بالإضافة إلى upload_file() وupload_folder()، تستخدم الدوال التالية create_commit() في الخلفية:
- يحذف delete_file() ملفًا واحدًا من مستودع على Hub.
- يحذف delete_folder() مجلدًا كاملًا من مستودع على Hub.
- تحديث metadata_update() بيانات المستودع الوصفية.
لمزيد من المعلومات التفصيلية، راجع مرجع HfApi.
رفع ملفات LFS قبل الالتزام
في بعض الحالات، قد ترغب في رفع ملفات ضخمة إلى S3 قبل إجراء استدعاء الالتزام. على سبيل المثال، إذا كنت تلتزم بمجموعة بيانات مقسمة إلى عدة أجزاء يتم توليدها في الذاكرة، فستحتاج إلى رفع هذه الأجزاء واحدًا تلو الآخر لتجنب مشكلة نفاد الذاكرة. أحد الحلول هو رفع كل جزء كالتزام منفصل في المستودع. وعلى الرغم من أن هذا الحل صالح تمامًا، إلا أن له عيبًا يتمثل في إمكانية إرباك سجل git من خلال توليد عشرات الالتزامات. للتغلب على هذه المشكلة، يمكنك رفع ملفاتك واحدًا تلو الآخر إلى S3 ثم إنشاء التزام واحد في النهاية. وهذا ممكن باستخدام preupload_lfs_files() بالاقتران مع create_commit().
هذه طريقة مخصصة للمستخدمين المتقدمين. استخدام upload_file() أو upload_folder() أو create_commit() مباشرةً بدلاً من التعامل مع منطق المستوى المنخفض لرفع الملفات مسبقاً هو النهج الأنسب في الغالبية العظمى من الحالات. التحذير الرئيسي الخاص بـ preupload_lfs_files() هو أنه حتى يتم إنشاء الالتزام فعلياً، لا يمكن الوصول إلى الملفات المرفوعة في المستودع على Hub. إذا كان لديك سؤال، فلا تتردد في التواصل معنا عبر Discord أو من خلال مشكلة على GitHub.
فيما يلي مثال بسيط يوضح كيفية رفع الملفات مسبقًا:
>>> from huggingface_hub import CommitOperationAdd, preupload_lfs_files, create_commit, create_repo
>>> repo_id = create_repo("test_preupload").repo_id
>>> operations = [] # List of all `CommitOperationAdd` objects that will be generated
>>> for i in range(5):
... content = ... # generate binary content
... addition = CommitOperationAdd(path_in_repo=f"shard_{i}_of_5.bin", path_or_fileobj=content)
... preupload_lfs_files(repo_id, additions=[addition])
... operations.append(addition)
>>> # Create commit
>>> create_commit(repo_id, operations=operations, commit_message="Commit all shards")أولاً، ننشئ كائنات CommitOperationAdd واحدة تلو الأخرى. في مثال واقعي، ستحتوي هذه الكائنات على الشرائح المولّدة. يتم رفع كل ملف قبل توليد الملف التالي. خلال خطوة preupload_lfs_files()، يتم تعديل كائن CommitOperationAdd. يجب عليك استخدامه فقط لتسليمه مباشرةً إلى create_commit(). التحديث الرئيسي للكائن هو أن المحتوى الثنائي يُحذف منه، مما يعني أنه سيُجمع كنفايات إذا لم تخزّن مرجعًا آخر إليه. وهذا متوقع لأننا لا نريد الاحتفاظ في الذاكرة بالمحتوى الذي تم رفعه بالفعل. أخيرًا، ننشئ الالتزام (commit) عن طريق تمرير جميع العمليات إلى create_commit(). يمكنك تمرير عمليات إضافية (إضافة، حذف أو نسخ) لم تتم معالجتها بعد، وسيتم التعامل معها بشكل صحيح.