الفصل 1: Git لمشاريع تعلم الآلة
مقدمة
Git هو أساس التحكم في الإصدارات في تطوير البرمجيات، لكن مشاريع تعلم الآلة تقدم تحديات فريدة تتطلب ممارسات وتكوينات متخصصة.
تحديات Git الخاصة بتعلم الآلة
الطبيعة الفريدة لكود تعلم الآلة
على عكس البرمجيات التقليدية، تتضمن مشاريع تعلم الآلة:
| التحدي | الوصف |
|---|---|
| ملفات كبيرة | مجموعات البيانات، أوزان النماذج (جيجابايت إلى تيرابايت) |
| القطع الثنائية | النماذج المدربة، المعالجات المسبقة |
| انتشار التجارب | مئات الفروع التجريبية |
| عدم الحتمية | قد ينتج عن نفس الكود نتائج مختلفة |
| فوضى الدفاتر | دفاتر Jupyter مع مخرجات مضمنة |
هيكل المستودع لمشاريع تعلم الآلة
الهيكل الموصى به
ml-project/
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── training.yml
│ └── deployment.yml
├── data/
│ ├── raw/ # البيانات الأصلية (متابعة بواسطة DVC)
│ ├── processed/ # البيانات المحولة (متابعة بواسطة DVC)
│ └── features/ # صادرات متجر الميزات
├── models/
│ ├── artifacts/ # النماذج المدربة (متابعة بواسطة DVC)
│ └── configs/ # تكوينات النماذج
├── notebooks/
│ ├── exploration/ # دفاتر تحليل البيانات الاستكشافية
│ └── experiments/ # دفاتر التجارب
├── src/
│ ├── __init__.py
│ ├── data/
│ │ ├── __init__.py
│ │ ├── ingestion.py
│ │ └── preprocessing.py
│ ├── features/
│ │ ├── __init__.py
│ │ └── engineering.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── train.py
│ │ └── predict.py
│ └── utils/
│ ├── __init__.py
│ └── helpers.py
├── tests/
│ ├── unit/
│ ├── integration/
│ └── data/
├── configs/
│ ├── training_config.yaml
│ └── serving_config.yaml
├── .dvc/
├── .gitignore
├── .pre-commit-config.yaml
├── dvc.yaml
├── dvc.lock
├── pyproject.toml
├── requirements.txt
└── README.md
.gitignore شامل لتعلم الآلة
# .gitignore لمشاريع تعلم الآلة
# ===== Python =====
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# ===== البيئات الافتراضية =====
venv/
ENV/
env/
.venv/
.conda/
# ===== دفاتر Jupyter =====
.ipynb_checkpoints/
*/.ipynb_checkpoints/
# ===== ملفات البيانات =====
# ملفات البيانات الكبيرة (متابعة بواسطة DVC بدلاً من ذلك)
*.csv
*.parquet
*.feather
*.h5
*.hdf5
*.pkl
*.pickle
!data/.gitkeep
data/raw/*
data/processed/*
data/features/*
# ===== قطع النماذج =====
# النماذج المدربة (متابعة بواسطة DVC بدلاً من ذلك)
*.pt
*.pth
*.onnx
*.pb
*.h5
*.keras
*.joblib
*.model
models/artifacts/*
!models/artifacts/.gitkeep
# ===== قطع MLOps =====
mlruns/
outputs/
wandb/
.neptune/
tensorboard_logs/
# ===== IDE =====
.idea/
.vscode/
*.swp
*.swo
.DS_Store
# ===== متغيرات البيئة =====
.env
.env.local
*.env
# ===== الأسرار =====
secrets/
credentials/
*.pem
*.key
# ===== السجلات =====
logs/
*.log
# ===== ذاكرة التخزين المؤقت =====
.cache/
.pytest_cache/
.mypy_cache/
.ruff_cache/
# ===== التغطية =====
htmlcov/
.coverage
.coverage.*
coverage.xml
Git LFS للملفات الكبيرة
متى تستخدم Git LFS
Git LFS (تخزين الملفات الكبيرة) مفيد للملفات التي:
- ضرورية للمستودع
- يتم تحديثها بشكل غير متكرر
- أصغر من 2 جيجابايت
- لا يمكن متابعتها بواسطة DVC
إعداد Git LFS
# تثبيت Git LFS
git lfs install
# متابعة أنواع ملفات محددة
git lfs track "*.bin"
git lfs track "*.weights"
git lfs track "*.ckpt"
# متابعة أدلة محددة
git lfs track "models/pretrained/*"
# التحقق من المتابعة
cat .gitattributes
مثال .gitattributes
# متابعة Git LFS
*.bin filter=lfs diff=lfs merge=lfs -text
*.weights filter=lfs diff=lfs merge=lfs -text
*.ckpt filter=lfs diff=lfs merge=lfs -text
models/pretrained/* filter=lfs diff=lfs merge=lfs -text
# ضمان نهايات الأسطر المتسقة
*.py text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.json text eol=lf
*.md text eol=lf
# دفاتر كمستندات ثنائية (لمنع تعارضات الدمج)
*.ipynb binary
استراتيجيات الفروع لتعلم الآلة
GitFlow المعدل لتعلم الآلة
اصطلاحات تسمية الفروع
# فروع الميزات (البنية التحتية، الأنابيب)
feature/data-pipeline
feature/monitoring-setup
feature/api-endpoint
# فروع التجارب (تطوير النموذج)
experiment/baseline-rf
experiment/deep-learning-v1
experiment/transformer-tuning
# فروع الإصلاحات الساخنة
hotfix/data-drift-fix
hotfix/prediction-bug
# فروع الإصدارات
release/v1.0.0
release/v1.1.0
قواعد الفروع الخاصة بتعلم الآلة
# .github/branch-protection.yml
branches:
main:
protection:
required_reviews: 2
required_status_checks:
- unit-tests
- integration-tests
- model-validation
enforce_admins: true
develop:
protection:
required_reviews: 1
required_status_checks:
- unit-tests
- linting
experiment/*:
protection:
required_reviews: 0 # يمكن دمج التجارب بحرية
allow_force_push: true # السماح بإعادة ترتيب التجارب
اصطلاحات رسائل الالتزام
رسائل الالتزام المنظمة
# التنسيق: <type>(<scope>): <description>
# الأنواع لمشاريع تعلم الآلة:
# - data: تغييرات متعلقة بالبيانات
# - feat: ميزة جديدة
# - fix: إصلاح خطأ
# - model: تغييرات في بنية النموذج
# - train: تغييرات متعلقة بالتدريب
# - eval: تغييرات في التقييم/المقاييس
# - docs: توثيق
# - refactor: إعادة هيكلة الكود
# - test: اختبارات
# - ci: تغييرات CI/CD
# - config: تغييرات التكوين
# أمثلة:
git commit -m "data: add new customer segmentation dataset v2.1"
git commit -m "model: implement attention mechanism in encoder"
git commit -m "train: add learning rate scheduling"
git commit -m "eval: add precision-recall analysis"
git commit -m "config: update training hyperparameters"
قالب رسالة الالتزام
# .gitmessage
# <type>(<scope>): <subject>
# |<---- Using a Maximum Of 50 Characters ---->|
# Explain why this change is being made
# |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->|
# Provide links or keys to any relevant tickets, articles or other resources
# Example: Experiment: exp-2024-01-15-baseline
# MLflow Run: abc123
# --- COMMIT END ---
# Type can be:
# data (data-related changes)
# feat (new feature)
# fix (bug fix)
# model (model architecture)
# train (training changes)
# eval (evaluation/metrics)
# docs (documentation)
# refactor (refactoring code)
# test (adding tests)
# ci (CI/CD changes)
# config (configuration changes)
تعيينها كافتراضي:
git config --global commit.template ~/.gitmessage
الخطافات المسبقة لتعلم الآلة
تكوين الخطافات المسبقة
# .pre-commit-config.yaml
repos:
# Python العام
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-added-large-files
args: ['--maxkb=1000'] # منع الملفات الكبيرة
- id: detect-private-key
- id: check-merge-conflict
# تنسيق Python
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
# التحقق من الأنواع
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [types-all]
# الأمان
- repo: https://github.com/PyCQA/bandit
rev: 1.7.6
hooks:
- id: bandit
args: ['-c', 'pyproject.toml']
# دفاتر Jupyter
- repo: https://github.com/kynan/nbstripout
rev: 0.6.1
hooks:
- id: nbstripout # إزالة مخرجات الدفاتر قبل الالتزام
# DVC
- repo: https://github.com/iterative/dvc
rev: 3.38.1
hooks:
- id: dvc-pre-commit
- id: dvc-pre-push
تثبيت الخطافات المسبقة
# تثبيت الخطافات المسبقة
pip install pre-commit
# تثبيت الخطافات
pre-commit install
# تشغيل على جميع الملفات
pre-commit run --all-files
التعامل مع دفاتر Jupyter
مشكلة الدفاتر
دفاتر Jupyter تمثل مشكلة للتحكم في الإصدارات:
- تحتوي على خلايا مخرجات (صور، إطارات بيانات)
- تتضمن أعداد تنفيذ
- اختلافات كبيرة بسبب تغييرات البيانات الوصفية
الحل 1: إزالة المخرجات
# باستخدام nbstripout
pip install nbstripout
# تثبيت كفلتر git
nbstripout --install
# إزالة يدويًا
nbstripout notebook.ipynb
الحل 2: Jupytext للدفاتر
# تثبيت jupytext
pip install jupytext
# تحويل الدفتر إلى سكربت Python
jupytext --to py:percent notebooks/experiment.ipynb
# مزامنة الدفتر والسكربت
jupytext --sync notebooks/experiment.ipynb
# pyproject.toml - تكوين Jupytext
[tool.jupytext]
formats = "notebooks///ipynb,scripts///py:percent"
الحل 3: ReviewNB لمراجعات PR
استخدم ReviewNB لمراجعات PR على GitHub للدفاتر:
- اختلافات بصرية للدفاتر
- التعليق على خلايا محددة
- تتبع التغييرات بفعالية
تكامل CI/CD
GitHub Actions لتعلم الآلة
# .github/workflows/ml-ci.yml
name: ML CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # التاريخ الكامل لـ DVC
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Run linting
run: ruff check .
- name: Run type checking
run: mypy src/
- name: Run unit tests
run: pytest tests/unit/ -v --cov=src/
- name: Upload coverage
uses: codecov/codecov-action@v3
data-validation:
runs-on: ubuntu-latest
needs: lint-and-test
steps:
- uses: actions/checkout@v4
- name: Setup DVC
uses: iterative/setup-dvc@v1
- name: Pull data
run: dvc pull data/processed/
- name: Validate data
run: python src/data/validate.py
النقاط الرئيسية
ملخص
- هيكل مستودعك بفصل واضح بين الكود والبيانات والنماذج
- استخدم .gitignore شامل لاستبعاد الملفات الكبيرة والبيانات الحساسة
- فكر في Git LFS للملفات الكبيرة الأساسية التي لا يمكن استخدام DVC لها
- اعتمد فروعًا خاصة بتعلم الآلة مع فروع التجارب
- فرض اصطلاحات الالتزام لتتبع التاريخ بشكل أفضل
- استخدم الخطافات المسبقة للحفاظ على جودة الكود
- تعامل مع الدفاتر بعناية باستخدام nbstripout أو jupytext
تمرين عملي
- أنشئ مستودع تعلم الآلة جديد بالهيكل الموصى به
- قم بتكوين .gitignore و .gitattributes
- قم بإعداد الخطافات المسبقة
- أنشئ وادمج فرع تجربة