التحكم في إصدار البيانات والنماذج باستخدام DVC
قابلية إعادة إنتاج التجارب
4 دقيقة للقراءة
القوة الحقيقية لـ DVC تكمن في خطوط الأنابيب—تعريف سير عمل ML بالكامل ككود. شغّل dvc repro وأعد إنشاء أي تجربة بدقة.
مشكلة إعادة الإنتاج
بدون خطوط الأنابيب:
# "كيف درّبت هذا النموذج؟"
python preprocess.py --input raw.csv --output clean.csv # أي معاملات؟
python train.py --data clean.csv --model rf # أي معلمات فائقة؟
python evaluate.py --model model.pkl # أي مقاييس؟
# الترتيب؟ التبعيات؟ الإصدارات؟
مع خطوط أنابيب DVC:
dvc repro # يُعيد إنشاء كل شيء، تلقائياً
أساسيات خطوط أنابيب DVC
ملف dvc.yaml
خطوط الأنابيب تُعرف في dvc.yaml:
# dvc.yaml
stages:
preprocess:
cmd: python src/preprocess.py
deps:
- src/preprocess.py
- data/raw.csv
outs:
- data/processed.csv
train:
cmd: python src/train.py
deps:
- src/train.py
- data/processed.csv
params:
- train.epochs
- train.learning_rate
outs:
- models/model.pkl
evaluate:
cmd: python src/evaluate.py
deps:
- src/evaluate.py
- models/model.pkl
- data/test.csv
metrics:
- metrics.json:
cache: false
المكونات الرئيسية
| المكون | الغرض | مثال |
|---|---|---|
cmd |
الأمر للتشغيل | python train.py |
deps |
تبعيات المدخلات | ملفات المصدر، البيانات |
outs |
مخرجات المخرجات | النماذج، البيانات المُعالجة |
params |
المعلمات الفائقة | معدل التعلم، الحقب |
metrics |
مقاييس التقييم | الدقة، درجة F1 |
ملف المعلمات
خزّن المعلمات الفائقة في params.yaml:
# params.yaml
preprocess:
test_split: 0.2
random_seed: 42
train:
epochs: 100
learning_rate: 0.001
batch_size: 32
model_type: random_forest
evaluate:
threshold: 0.5
الإشارة في كودك:
# src/train.py
import yaml
with open('params.yaml') as f:
params = yaml.safe_load(f)
epochs = params['train']['epochs']
lr = params['train']['learning_rate']
تشغيل خطوط الأنابيب
التنفيذ الأساسي
# شغّل خط الأنابيب بالكامل
dvc repro
# شغّل مرحلة محددة
dvc repro train
# أجبر إعادة التشغيل (تجاهل الكاش)
dvc repro --force
التخزين المؤقت الذكي
DVC يُعيد تشغيل المراحل فقط عندما يتغير شيء:
$ dvc repro
Stage 'preprocess' didn't change, skipping
Stage 'train' didn't change, skipping
Stage 'evaluate' didn't change, skipping
Data and calculation are already up to date.
# الآن عدّل learning_rate في params.yaml
$ dvc repro
Stage 'preprocess' didn't change, skipping
Running stage 'train'... # يُعاد التشغيل لأن المعلمة تغيرت
Running stage 'evaluate'... # يُعاد التشغيل لأن التبعية تغيرت
تتبع المقاييس
ملف المقاييس
# src/evaluate.py
import json
metrics = {
"accuracy": 0.87,
"precision": 0.85,
"recall": 0.89,
"f1_score": 0.87
}
with open('metrics.json', 'w') as f:
json.dump(metrics, f, indent=2)
عرض المقاييس
# اعرض المقاييس الحالية
dvc metrics show
# الناتج:
# Path accuracy precision recall f1_score
# metrics.json 0.87 0.85 0.89 0.87
مقارنة التجارب
# قارن المقاييس عبر commits Git
dvc metrics diff HEAD~1
# الناتج:
# Path Metric HEAD HEAD~1 Change
# metrics.json accuracy 0.87 0.82 +0.05
# metrics.json f1_score 0.87 0.81 +0.06
الرسوم والتصورات
تعريف الرسوم
# dvc.yaml
stages:
train:
cmd: python src/train.py
plots:
- training_history.csv:
x: epoch
y: loss
ملف سجل التدريب
# src/train.py
import csv
history = []
for epoch in range(epochs):
loss = train_epoch(model, data)
history.append({'epoch': epoch, 'loss': loss})
with open('training_history.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['epoch', 'loss'])
writer.writeheader()
writer.writerows(history)
عرض الرسوم
# أنشئ رسوم HTML
dvc plots show
# قارن الرسوم عبر التجارب
dvc plots diff HEAD~1
مثال خط أنابيب كامل
هيكل المشروع
my-project/
├── data/
│ ├── raw.csv
│ └── processed.csv
├── src/
│ ├── preprocess.py
│ ├── train.py
│ └── evaluate.py
├── models/
│ └── model.pkl
├── dvc.yaml
├── params.yaml
├── metrics.json
└── dvc.lock
dvc.yaml كامل
stages:
preprocess:
cmd: python src/preprocess.py
deps:
- src/preprocess.py
- data/raw.csv
params:
- preprocess.test_split
- preprocess.random_seed
outs:
- data/processed.csv
- data/test.csv
train:
cmd: python src/train.py
deps:
- src/train.py
- data/processed.csv
params:
- train.epochs
- train.learning_rate
- train.model_type
outs:
- models/model.pkl
plots:
- training_history.csv:
x: epoch
y: loss
evaluate:
cmd: python src/evaluate.py
deps:
- src/evaluate.py
- models/model.pkl
- data/test.csv
metrics:
- metrics.json:
cache: false
ملف القفل
dvc.lock يُسجل الحالة الدقيقة لكل تشغيل:
# dvc.lock (يُنشأ تلقائياً)
schema: '2.0'
stages:
preprocess:
cmd: python src/preprocess.py
deps:
- path: data/raw.csv
hash: md5
md5: a1b2c3d4e5...
- path: src/preprocess.py
hash: md5
md5: f6g7h8i9j0...
outs:
- path: data/processed.csv
hash: md5
md5: k1l2m3n4o5...
سير عمل التجارب
# 1. أنشئ فرع تجربة
git checkout -b experiment/new-features
# 2. عدّل المعلمات
vim params.yaml
# 3. شغّل خط الأنابيب
dvc repro
# 4. قارن النتائج
dvc metrics diff main
# 5. إذا أفضل، ثبّت وادمج
git add dvc.yaml dvc.lock params.yaml metrics.json
git commit -m "Experiment: added feature engineering, acc +5%"
git checkout main
git merge experiment/new-features
أفضل الممارسات
| الممارسة | لماذا |
|---|---|
| أبقِ المراحل دقيقة | تخزين مؤقت وتصحيح أسهل |
| استخدم params.yaml | افصل الكود عن التكوين |
| ثبّت dvc.lock | يضمن إعادة الإنتاج الدقيقة |
| وثّق التجارب | رسائل commit Git مهمة |
| استخدم الفروع | تجربة واحدة لكل فرع |
الرؤية الرئيسية: مع
dvc.yamlوdvc.lockفي Git، يمكن لأي شخص تشغيلdvc reproوالحصول على نفس النتائج بالضبط—بعد أشهر أو سنوات.
الوحدة التالية: سنستكشف تنسيق سير عمل ML مع Kubeflow وAirflow وPrefect. :::