26 KiB
Inżynieria uczenia maszynowego
22 maja 2024
10. DVC
DVC - Data Version Control
- dvc.org
- "Version Control System for Machine Learning Projects" (System kontroli wersji dla projektów uczenia maszynowego)
- Open Source
- Umożliwia:
- wersjonowanie danych i modeli. "Git dla danych i modeli"
- budowanie potoków ("pipeline") definiujących jak budować/trenować/ewaluować modele. "Makefile dla uczenia maszynowego"
- śledzenie, porównywanie metryk i parametrów
- ściśle zintegowany z gitem
- działa niezależnie od używanego języka/bibliotek i systemu operacyjnego
- 5-minutowe wprowadzenie: https://www.youtube.com/watch?v=UbL7VUpv1Bs&t=197s
Śledzenie plików za pomocą DVC
- dużymi plikami, takimi jak plikami z danymi wejściowymi czy plikami modeli, trudno zarządza się za pomocą gita, ze względu na problemy z:
- wydajnością
- przestrzenią w repozytorium
- ograniczenia ze strony serwisu (np. limit 100 MB na plik w Github)
- Git posiada rozszerzenie lfs(Large File Storage), które stanowi pewne rozwiązanie tego problemu.
- Same pliki przechowywane są na specjalnym zdalnym serwerze, w repozytorium przechowywane są jedynie odnośniki do tych plików i pewne metadane
- Github ma zintegrowany LFS z limitem 1GB dla kont bezpłatnych
- DVC proponuje podobne podejście co LFS, ale:
Instalacja i inicjalizacja
- https://dvc.org/doc/install
pip(x) install dvc
albo:conda install dvc
!pip3 install dvc
Stwórzmy katalog, w którym będziemy przechowywać nasz projekt:
!rm -r -f IUM_10/sample-ml-project-2023
!mkdir -p IUM_10/sample-ml-project-2023
#Jupyter notebook magic https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-cd
%cd "IUM_10/sample-ml-project-2023"
Inicjalizujemy puste repozytorium Git (możemy też pominąć ten krok i działać w istniejącym już repozytorium)
!git init
Teraz inicjalizujemy repozytorium DVC:
!dvc init
Zobaczmy jakie pliki dodał (również do repozytorium git) DVC. Ich opis znajdziemy tutaj: https://dvc.org/doc/user-guide/project-structure/internal-files
!git status
.dvc/config
- główny plik konfiguracyjny dvc.dvc/config.local
- nadpisuje wartości zconfig
, do lokalnych zmian nie commitowanych do repo.dvc/.gitignore
- pliki dvc, które nie mają znaleźć się w repo.dvcignore
- dvc pomija pliki zdefiniowane w tym pliku (np. aby poprawić wydajność)
Możemy teraz zacommitować zmiany w git:
!git commit -m "Initial commit"
Przygotujmy przykładowe dane, pobierając je z Kaggle:
!kaggle datasets download -d uciml/iris
!unzip -o iris.zip
!rm database.sqlite iris.zip
!mkdir -p data
!mv Iris.csv data/
Teraz dodamy plik(i) z danymi do DVC:
!dvc add data/Iris.csv
- DVC utworzył plik
data/Iris.csv.dvc
i dadał oryginalny plik do.gitignore
- W repozytorium będzie obecny tylko plik
*.dvc
, zawierający odnośnik do prawdziwego pliku
!git status -u
Dodajmy pliki data/Iris.csv.dvc data/.gitignore
do repozytorium git, zgodnie z sugestią DVC:
!git add data/Iris.csv.dvc data/.gitignore
!git commit -m "Dodano dane IRIS (DVC)"
Plik *.dvc
zawiera m.in. hash pliku. Więcej o plikach *.dvc
: link
# %load data/Iris.csv.dvc
Oryginalny plik Iris.csv
został przeniesiony do katalogu ./dvc/cache/{wartość hash pliku) i podlinkowany z powrotem do oryginalnej lokalizacji. Sposób tworzenia linków może być różny w zależności od systemu plików.
!ls -l .dvc/cache/71
!head -n 3 .dvc/cache/71/7820ef0af287ff346c5cabfb4c612c
!git remote add origin git@git.wmi.amu.edu.pl:tzietkiewicz/sample-ml-project.git
!git push --set-upstream origin main
dvc remote
- żeby wysłać właściwe pliki śledzone przez DVC do zdalnej lokalizacji (z której będą mogłby być pobrane np. przez system CI albo innych użytkowników) musimy mieć skonfigurowaną taką lokazliację
- służy do tego polecenie
dvc remote add
- użyjemy lokalnego "remote". Tutaj będzie to po prostu utworzony wcześniej katalog
/dvcstore
. Taki katalog istnieje też na naszym Jenkinsie, oczywiście należy go podmontować w Dockerze - w realnych zastosowaniach podalibyśmy tutaj ścieżkę do jakiegoś zasobu dostępnego przez inernet jak np. serwer SFTP, ścieżka do AWS S3 itp.
Obsługiwane typy zdalnych lokalizacji (remotes): https://dvc.org/doc/command-reference/remote/add#supported-storage-types
- Amazon S3
- S3-compatible storage
- Microsoft Azure Blob Storage
- Google Drive
- Google Cloud Storage
- Aliyun OSS
- SSH
- HDFS
- WebHDFS
- HTTP
- WebDAV
- local remote
Dodawanie remote typu local
!dvc remote add -d my_local_remote /dvcstore
!git status
!git add .dvc/config
!git commit -m "Added DVC remote"
dvc push
Kiedy mamy już skonfigurowany "remote" możemy wypchnąć do niego pliki korzystając z polecenia dvc push
:
!dvc push
!tree /dvcstore
dvc pull
Żeby pobrać dane z DVC (np. w innej lokalizacji, przez innego użytkownika), musimy:
- sklonować repozytorium git (żeby m.in. pobrać pliki
*.dvc
- wykonać
dvc pull
Dodawanie nowych plików i modyfikacja istniejących wygląda podobnie jak przy zwykłych plikach śledzonych przez git, tylko zamiast git
używamy polecenia dvc
a dodatkowo pamiętamy o zarządzaniu plikami *.dvc
za pomocą gita:
!head -n -1 data/Iris.csv | sponge data/Iris.csv
!git status
!dvc status
!dvc add data/Iris.csv
!git add data/Iris.csv.dvc
!git commit -m "Removed last line from Iris dataset"
!wc -l .dvc/cache/*/*
dvc checkout
- Polecenia
dvc checkout
używamy razem zgit checkout
, żeby zmienić branch, na którym pracujemy. - DVC podmieni wersje plików śledzonych przez siebie na pochodzące z innego brancha (o ile pliki te się różnią i różnią się pliki
*.dvc
w odpowiednich branchach - zmiana brancha przez git powoduje (ewentualną) zmianę plików
*.dvc
advc checkout
kopiuje/linkuje pliki z katalogu.dvc/cache
o wartościach hash odpowiadających tym z plików*.dvc
Wymiana danych między projektami
- za pomocą poleceń
dvc import
idvc update
możemy dodać i później aktualizować pliki śledzone przez DVC w innym repozytorium
!dvc import https://github.com/iterative/dataset-registry \
get-started/data.xml -o data/data.xml
!dvc status
ls -l data
# %load data/data.xml.dvc
md5: 9d5921765bfba6c2c7e4c780c66edaa0
frozen: true
deps:
- path: get-started/data.xml
repo:
url: https://github.com/iterative/dataset-registry
rev_lock: 08c38bbea04e4f9e2130615dd679309ed0e11a72
outs:
- md5: 22a1a2931c8370d3aeedd7183606fd7f
size: 14445097
path: data.xml
DVC pipelines
- wprowadzenie: https://youtu.be/71IGzyH95UY
- Getting started: https://dvc.org/doc/start/data-pipelines
- dvc pipelines pozwala nam zbudować (za pomocą polecenie
dvc run
) lub zdefiniować (edytując plikdvc.yaml
) graf zależności między krokami wykonywanymi w naszym projekcie (takimi jak "przygotowanie danych", "trenowanie", "ewaluacja") - tak zdefiniowany pipeline można potem uruchomić za pomocą polecenia
dvc reproduce
Zadania [10+10 pkt]
- Zainicjalizuj repozytorium DVC wewnątrz Twojego repozytorium z projektem [1pkt]
- Dodaj plik(i) z danymi w Twoim projekcie do DVC [1pkt]
- Skonfiguruj remote (dane do konfiguracji podane poniżej) [3pkt]
- Stwórz/zdefiniuj i dodaj do repozytorium plik
dvc.yaml
opisujący kroki wykonywane w Twoim projekcie. Wydziel przynajmniej 2 kroki (np. przygotowanie danych/trenowanie) powiązane ze sobą za pomocą zależności (skorzystaj z materiałów "Getting started", link powyżej) [10pkt (opcjonalne)] - Stwórz projekt na Jenkinsie (
s1233456-dvc
), w którym sklonujesz repozytorium, ściągniesz pliki dvc (za pomocądvc pull
) i uruchomisz pipeline (za pomocądvc reproduce
) [5pkt]
SSH remote
Jednym z remote obsługiwanych przez DVC jest SFTP/SSH.
W celu jego wykorzystania na serwerze tzietkiewicz.vm.wmi.amu.edu.pl utworzony został użytkownik ium-sftp
i skonfigurowany serwer SFTP.
Został też dla niego wygenerowany klucz ssh, który został dodany jako "Jenkins credential" (patrz opis konfiguracji na Jenkins poniżej)
Lokalnie
Będziemy potrzebować zależności (szczegóły)
conda install dvc-ssh
albo
pip install dvc[ssh] paramiko
conda install -c conda-forge dvc-ssh
Collecting package metadata (current_repodata.json): done Solving environment: \
## Poniższe są potrzebne, żeby polecania dvc remote działały:
!sudo apt install libssl3 libffi7
Dodajemy remote:
!dvc remote add -f -d ium_ssh_remote ssh://ium-sftp@tzietkiewicz.vm.wmi.amu.edu.pl
!dvc remote list
Zapisujemy hasło:
!dvc remote modify --local ium_ssh_remote password IUM@2021
Pushujemy do skonfigurowanego remote:
!dvc push
Jenkins
W Jenkins można użyć mechanizmu "Credentials", żeby w bezpieczny sposób przekazać hasło albo klucz prywatny.
Takie dane dla użytkownika ium-sftp zostały stworzone na Jenkinsie:
- typu ssh key: https://tzietkiewicz.vm.wmi.amu.edu.pl:8081/credentials/store/system/domain/_/credential/48ac7004-216e-4260-abba-1fe5db753e18/
- typu "secret text" - zawierający hasło użytkownika ium-shftp: https://tzietkiewicz.vm.wmi.amu.edu.pl:8081/credentials/store/system/domain/_/credential/ium-sftp-password/
Opis używania "Credentials" w Jenkinsfile: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#for-other-credential-types
Klucza ssh można użyć tak:
withCredentials(
[sshUserPrivateKey(credentialsId: '48ac7004-216e-4260-abba-1fe5db753e18', keyFileVariable: 'IUM_SFTP_KEY', passphraseVariable: '', usernameVariable: '')]) {
sh 'dvc remote add -d ium_ssh_remote ssh://ium-sftp@tzietkiewicz.vm.wmi.amu.edu.pl/ium-sftp'
sh 'dvc remote modify --local ium_ssh_remote keyfile $IUM_SFTP_KEY'
sh 'dvc pull'}
Secret text tak:
withCredentials([string(credentialsId: 'ium-sftp-password', variable: 'IUM_SFTP_PASS')]) {
sh 'dvc remote add -d ium_ssh_remote ssh://ium-sftp@tzietkiewicz.vm.wmi.amu.edu.pl/ium-sftp'
sh 'dvc remote modify --local ium_ssh_remote password $IUM_SFTP_PASS'
sh 'dvc pull'
}
Przykład konfiguracji: