Önceki yazıda DVC ile veri versiyonlama işlemi gerçekleştirmiştir. Bu yazıda DVC ile model versiyonlama yapacağız.
İlk olarak bu linkten gerekli veri setini indirebilirsiniz. Gerekli olan kütüphaneleri kurmakla başlayalım;
pip install dvclive omegaconf colorama scikit-learn pandas joblib
1 – ) ‘pipeline-test’ isminde bir klasör açıyorum ve içerisine bazı klasör ve dosyalar oluşturuyorum. Projemizdeki dosyaların dizin yapısı şu şekildedir;
- data: Veri dosyalarını barındıran dizindir. ‘raw’ klasörüne işlenmemiş veri setini yükleyeceğiz, ‘processed’ klasörüne ise işlenmiş veri setini kaydedeceğiz.
- models: Oluşan modelleri kaydedeceğimiz dizindir.
- results: Model sonuçlarını kaydedeceğimiz dizindir.
- prepare.py: Modeli eğitim ve test setlerine bölme kodları.
- process.py: Veri setini ön işleme kodları.
- train.py: Model eğitme kodları.
- evaluate.py: Modeli sınama kodları.
- params.yaml: Veri setini işlemeden modeli sınamaya kadar kullanılacak olan tüm parametrelerin tanımlandığı yaml dosyasıdır.
- dvc.yaml: Model eğitim sürecini otomatikleştirerek modeli takip edebileceğimiz dvc üzerinde bir ‘experiment’ oluşturan yaml dosyasıdır.
alper@alper:/mnt/d/work2/data-versioning-dvc/cyberds/pipeline-test$ ls -R
.:
data dvc.yaml evaluate.py models params.yaml prepare.py process.py results train.py
./data:
processed raw
./data/processed:
./data/raw:
winequality-red.csv
./models:
./results:
2 – ) DVC yi kullanabilmek için projemize git eklenmiş olması gerekiyordu. ‘git init’ yazarak projemize git ekliyoruz ve ‘dvc init’ yazarak da projemize DVC’yi ekliyoruz.
alper@alper:/mnt/d/work2/data-versioning-dvc/cyberds/pipeline-test$ git init
alper@alper:/mnt/d/work2/data-versioning-dvc/cyberds/pipeline-test$ dvc init
3 – ) Projemiz için gerekli dosyaları da ayarladığımıza göre artık kodlamaya geçebiliriz. İlk olarak params.yaml dosyasını hazırlayalım. Bu YAML dosyasında verilere erişip kod içinde kullanabilmek için ‘OmegaConf’ kütüphanesini kullanıyoruz. YAML dosyası içerisindeki en baştaki değerler ‘stage’ yani durumlardır. Bunlar yürütülecek olan process.py, train.py gibi çeşitli dosyalarda kullanılacak olan parametrelerin bölünmüş halidir. Her bir durum içindeki parametre o durumda kullanılacak olan parametrelerdir. Model için takip edilecek adımlar şunlardır;
- Kaynak veri setinin ‘quality’ sütunu bizim hedef değişkenimiz. Veri seti %70’i eğitim, %30’u sınama için ayrılacak ve ayrı ayrı ‘csv’ dosyalarında kaydedilecek.
- Daha sonra kaydedilen csv dosyalarına ölçeklendirme yapılacak ve bu ölçeklendirilmiş dosyalar kaydedilecek.
- Model eğitmek için ‘RandomForestClassifier’ ve birtakım hiperparametreler kullanılacak. Daha sonra eğitilen model kaydedilecek.
- Eğitilmiş model dosyasını kullanarak ölçeklendirilmiş sınama verisi üzerinde test işlemi yapılacak ve ‘accuracy’ ve ‘f1’ skorları bir yaml dosyasına kaydedilecek.
data:
raw_data_path: ./data/raw/winequality-red.csv
target: quality
test_size: 0.3
random_state: 42
train_csv_path: ./data/raw/train.csv
test_csv_path: ./data/raw/test.csv
features:
train_features_path: ./data/processed/train.joblib
test_features_path: ./data/processed/test.joblib
train:
n_estimators: 100
min_samples_split: 2
max_features: sqrt
model_path: ./models/model.joblib
evaluate:
results_path: ./results/results.yaml
4 – ) prepare.py dosyasında veri setimizi %70’i eğitim ve %30’u sınama olacak şekilde bölüyoruz ve daha sonra bölünmüş veri setini csv dosyalarına kaydediyoruz.
import colorama
from colorama import Fore
colorama.init(autoreset=True)
import pandas as pd
from omegaconf import OmegaConf
from sklearn.model_selection import train_test_split
def prepare(config):
print(f"{Fore.YELLOW}[+] Preparing data.")
df = pd.read_csv(config.data.raw_data_path)
target_map = {3: "Low", 4: "Low", 5: "Medium", 6: "Medium", 7: "High", 8: "High"}
test_size = config.data.test_size
train_df, test_df = train_test_split(df, test_size=test_size, random_state=config.data.random_state)
train_df[config.data.target] = train_df[config.data.target].map(target_map)
test_df[config.data.target] = test_df[config.data.target].map(target_map)
train_df.to_csv(config.data.train_csv_path, index=False)
test_df.to_csv(config.data.test_csv_path, index=False)
if __name__ == "__main__":
config = OmegaConf.load("./params.yaml")
prepare(config)
5 – ) process.py dosyasında verimizi ölçeklendireceğiz. Veri setimiz tamamen numerik değerler olduğu için ‘StandardScaler’ kullanarak tüm değerlerimizi ölçeklendiriyoruz. Daha sonra ölçeklendirilmiş veriyi bir ‘joblib’ dosyası olarak kaydediyoruz. Bu dosyaları modeli eğitirken ve sınarken kullanacağız.
import colorama
from colorama import Fore
colorama.init(autoreset=True)
import joblib
import pandas as pd
from omegaconf import OmegaConf
from sklearn.preprocessing import StandardScaler
def process(config):
print(f"{Fore.BLUE}[+] Processing data.")
train_df = pd.read_csv(config.data.train_csv_path)
test_df = pd.read_csv(config.data.test_csv_path)
sc = StandardScaler()
train_scaled = sc.fit_transform(train_df.drop(config.data.target, axis=1))
test_scaled = sc.fit_transform(test_df.drop(config.data.target, axis=1))
joblib.dump(train_scaled, config.features.train_features_path)
joblib.dump(test_scaled, config.features.test_features_path)
if __name__ == "__main__":
config = OmegaConf.load('./params.yaml')
process(config)
6 – ) train.py modelimizi eğiteceğiz. Daha önceden ölçeklendirdiğimiz eğitim verilerini kullanarak ve YAML dosyasında belirttiğimiz hiperparametreleri kullanarak modelimizi eğitiyoruz. Burdaki ‘Live’ modelimi eğitirken kullandığımız hiperparametreleri loglamamızı sağlıyor. Daha sonra bu loglanan değerleri ‘Visual Studio Code’ üzerinde inceleyeceğiz. Eğitim bittikten sonra eğitilen modeli kaydediyoruz.
import colorama
from colorama import Fore
colorama.init(autoreset=True)
import joblib
import pandas as pd
from omegaconf import OmegaConf
from sklearn.ensemble import RandomForestClassifier
from dvclive import Live
def process(config):
print(f"{Fore.RED}[+] Training model.")
train_features = joblib.load(config.features.train_features_path)
train_labels = pd.read_csv(config.data.train_csv_path)[config.data.target].values
n_estimators = config.train.n_estimators
min_samples_split = config.train.min_samples_split
max_features = config.train.max_features
with Live() as live:
live.log_param("n_estimators", n_estimators)
live.log_param("min_samples_split", min_samples_split)
live.log_param("max_features", max_features)
model = RandomForestClassifier(n_estimators=n_estimators, min_samples_split=min_samples_split, max_features=max_features)
model.fit(train_features, train_labels)
joblib.dump(model, config.train.model_path)
if __name__ == "__main__":
config = OmegaConf.load('./params.yaml')
process(config)
7 – ) evaluate.py eğittiğimiz modeli sınıyoruz. ‘Live’ ile eğitim aşamasındaki hiperparametrelerimizi loglamıştık. Bu sefer ‘Live’ kullanarak metrikleri logluyoruz ve karmaşıklık matrisi (confusion matrix) oluşturup kaydediyoruz.
import colorama
from colorama import Fore
colorama.init(autoreset=True)
import joblib
import pandas as pd
from omegaconf import OmegaConf
from sklearn.metrics import accuracy_score, f1_score
from dvclive import Live
def process(config):
print(f"{Fore.GREEN}[+] Evaluating model.")
test_inputs = joblib.load(config.features.test_features_path)
test_labels = pd.read_csv(config.data.test_csv_path)[config.data.target].values
model = joblib.load(config.train.model_path)
with Live() as live:
predicted = model.predict(test_inputs)
accuracy = accuracy_score(test_labels, predicted)
f1 = f1_score(test_labels, predicted, average="weighted")
live.log_metric("test/accuracy", accuracy)
live.log_metric("test/f1", f1)
live.log_sklearn_plot("confusion_matrix", test_labels, predicted, name="test/confusion_matrix", title="Test Confusion Matrix")
results_json = {"accuracy": accuracy, "f1": f1}
OmegaConf.save(results_json, config.evaluate.results_path)
if __name__ == "__main__":
config = OmegaConf.load('./params.yaml')
process(config)
8 – ) Tüm aşamalar için gereken kodları tamamladık. Şimdi DVC ile bunları otomatik olarak çalıştıracak bir YAML dosyası hazırlayalım. ‘Stages’ ile her bir adımda çalıştırılacak olan işlemleri bölümlere ayırıyoruz. ‘cmd’ etiketi her bir adımda çalıştırılacak python dosyasını temsil ediyor. ‘deps’ o python dosyasını çalıştırmak için gereken bileşenleri ve dosyaları temsil ediyor. ‘params’ ise ‘params.yaml’ dosyasında kullanacağı bölüm adını temsil ediyor. ‘outs’ kod çalıştırıldıktan sonra üretilecek çıktıları temsil ediyor.
stages:
prepare:
cmd: python3 ./prepare.py
deps:
- ./prepare.py
- ./data/raw/winequality-red.csv
params:
- data
outs:
- ./data/raw/train.csv
- ./data/raw/test.csv
process:
cmd: python3 ./process.py
deps:
- ./process.py
- ./data/raw/train.csv
- ./data/raw/test.csv
params:
- features
outs:
- ./data/processed/train.joblib
- ./data/processed/test.joblib
train:
cmd: python3 ./train.py
deps:
- ./train.py
- ./data/raw/train.csv
- ./data/processed/train.joblib
params:
- train
outs:
- ./models/model.joblib
evaluate:
cmd: python3 ./evaluate.py
deps:
- ./evaluate.py
- ./data/raw/test.csv
- ./data/processed/test.joblib
- ./models/model.joblib
params:
- evaluate
9 – ) ‘dvc dag’ komutu ile aşamaları görselleştirelim. Bu görselde yukarıdan aşağıya doğru sırasıyla çalıştırılacak kodları gösteriliyor.
alper@alper:/mnt/d/work2/data-versioning-dvc/cyberds/pipeline$ dvc dag
+---------+
| prepare |
**+---------+****
**** * ***
*** * ***
** * ****
+---------+ * **
| process | * *
+---------+*** * *
* **** * *
* *** * *
* ** * *
** +-------+ **
*** | train | ****
**** +-------+ ***
*** * ***
*** * ****
** * **
+----------+
| evaluate |
+----------+
10 – ) ‘dvc run exp’ komutu ile ilk modelimi oluşturalım.
alper@alper:/mnt/d/work2/data-versioning-dvc/cyberds/pipeline-test$ dvc exp run
Running stage 'prepare':
> python3 ./prepare.py
[+] Preparing data.
Generating lock file 'dvc.lock'
Updating lock file 'dvc.lock'
Running stage 'process':
> python3 ./process.py
[+] Processing data.
Updating lock file 'dvc.lock'
Running stage 'train':
> python3 ./train.py
[+] Training model.
Updating lock file 'dvc.lock'
Running stage 'evaluate':
> python3 ./evaluate.py
[+] Evaluating model.
11 – ) İlk modelimizin n_estimators değeri 100 idi. YAML dosyasında bunu 300 yapıp tekrar ‘dvc run exp’ komutunu çalıştırarak bir model daha eğitiyorum. Kodun sadece model eğitme kısmında değişiklik yaptığım için ilk iki adım prepare ve process kısmı çalışmadı.
Stage 'prepare' didn't change, skipping
Stage 'process' didn't change, skipping
Running stage 'train':
> python3 ./train.py
[+] Training model.
Updating lock file 'dvc.lock'
Running stage 'evaluate':
> python3 ./evaluate.py
[+] Evaluating model.
Updating lock file 'dvc.lock'
12 – ) Şimdi eğittiğimiz modellerin sonuçlarını ‘Visual Studio Code’ üzerinden inceleyelim. Bunun için marketten ‘DVC’ eklentisini kurmanız gerek. Eklentiyi kurduktan sonra soldaki menüden DVC logosuna tıklayıp ‘show experiments’ butonuna basıyoruz. Bu kısımda modelimizdeki parametreler ve metrikler gözüküyor.
13 – ) ‘Show plots’ butonunda ise modeli eğitirken oluşturduğumuz karmaşıklık matrisleri görünüyor.