18 KiB
18 KiB
Inżynieria uczenia maszynowego
11. Github actions i CML [laboratoria]
Tomasz Ziętkiewicz (2021)
- https://docs.github.com/en/actions
- System ciągłej integracji "wbudowany" w GitHub
- Darmowy dla publicznych repozytoriów (z większymi niż w płatnych planach ograniczeniami dotyczącymi zasobów)
Terminologia Github Actions
- _Workflow - workflow odpowiada "Pipeline" z Jenkinsa.
- _Job - workflow składa się z jednego lub kilku "jobs". Każdy z nich może być wykonywany równolegle na innej maszynie (patrz "runner")
- _Step - odpowiednik "Stage" z Jenkinsa - służu do grupowania "Actions"
- _Action - odpowiednik "Step" z Jenkinsa - pojedyncze polecenie do wykonania, np. dodanie komentarze do Pull requesta, wykonanie polecenia systemowego itp.
- _Runner - odpowiednik Jenkinsowego "Agent" - serwer, na którym mogą być wykonywane zadania ("jobs")
- _Github-hosted runner - serwer utrzymywany przez Github (2-core CPU, 7 GB RAM, 14 GB SSD). Windows, Linux albo macOS
- _Self-hosted runner - nasz własny serwer, z zinstalowaną aplikacją Github actions runner
- _Event - zdażenie, które odapala ("triggers") uruchomienie Workflow. Np. wypchnięcie zmiany do repozytorium ("push"), utworzenie Pull requesta. Pełna lista
Definicja workflow
- Workflow definiuje się w plikach YAM(o rozszerzeniu
*.yml
albo*.yaml
) umieszczonych w specjalnym folderze.github/workflows/
wewnątrz repozytorium - Pełna składnia jest opisana tutaj
- Podstawowe pola:
name
[opcjonalna] - nazwa, pod którą workflow/step będzie widoczny w UI. Domyślnie ścieżka do pliku yamlon
- definiuje kiedy workflow ma być odpalonyjobs
- grupuje razem "zadania" do wykonania. Każde może być wykonane na innym "runnerze". Domyślnie wykonywane są równolegle (ale możemy definiować zależności między jobami, co powoduje wykonanie ich sekwencyjnieruns-on
- parametr joba, definujący na jakiej maszynie wirtualnej ma być uruchomiony (np.ubuntu-latest
)uses
- umożliwia użycie gotowych akcji zdefiniowanych przez nas, albo przez innych użytkowników, np.-uses: actions/checkout@v2
spowoduje checkout plików z repozytoriumrun
- pozwala uruchomić dowolne (dostępne/zainstalowane) polecenie, np.python3 train.py
env
- pozwala zdefiniować zmienne środowiskowe dostępne dla akcji lub skorzystać ze zmiennych ustawionych przez Github
%cd IUM_11
!mkdir github-actions-hello;\
cd github-actions-hello;\
git init
/home/tomek/AITech/repo/aitech-ium-private/IUM_11 Initialized empty Git repository in /home/tomek/AITech/repo/aitech-ium-private/IUM_11/github-actions-hello/.git/
%cd github-actions-hello
!mkdir -p .github/workflows
/home/tomek/AITech/repo/aitech-ium-private/IUM_11/github-actions-hello
%%writefile .github/workflows/workflow.yml
name: github-actions-hello
on: [push]
jobs:
hello-job:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2.2.2
with:
python-version: '3.7'
- run: python3 --version
Writing .github/workflows/workflow.yml
Zależności
Maszyny wirtualne ("runners"), na których uruchamiane są "joby" mają zainstalowany zbiór narzędzi. Przykładowa lista dla Ubuntu 20.04
Brakujące zależności można zainstalować, korzystając z:
- akcji
- poleceń systemowych takich jak
apt install
czypip install
uruchomionych poprzezrun
. Patrz przykład
Akcje
Za pomocą polecenia uses
możemy używać przygotowanych wcześniej akcji. Mogą one pochodzić:
- z tego samego repozytorium co workflow (więcej)
- z dowolnego publicznego repozytorium Github (np. repozytorioum iterative/setup-clm, patrz przykład poniżej
- z Github Marketplace
- Tworzone przez iterative.ai (tak jak DVC)
- https://cml.dev/
- Dokumentacja: https://dvc.org/doc/cml
- Korzysta z Github Actions lub Gitlab CI (a także Bitbucket Pipelines)
- CML dodaje do Github Actions kilka "akcji":
iterative/setup-cml
- dodaje poniższe akcjecml-send-comment
- dodaje raport CML jako komentarz do Pull Requesta na Githubiecml-send-github-check
- dodaje raport CML do zakładki "Checks" Pull Requesta na Githubiecml-publish
- umożliwia dodanie obrazka do raportu
Przykładowy Workflow CML:
!git clone git@github.com:TomekZet/example_cml.git
/home/tomek/AITech/repo/aitech-ium-private/IUM_11 Cloning into 'example_cml'... remote: Enumerating objects: 25, done.[K remote: Total 25 (delta 0), reused 0 (delta 0), pack-reused 25[K Receiving objects: 100% (25/25), 222.95 KiB | 920.00 KiB/s, done. Resolving deltas: 100% (6/6), done.
%cd example_cml
!mkdir -p .github/workflows/
/home/tomek/AITech/repo/aitech-ium-private/IUM_11/example_cml
%%writefile .github/workflows/cml.yaml
name: model-training
on: [push]
jobs:
run:
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: iterative/setup-cml@v1
- name: Train model
env:
REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pip install -r requirements.txt
python train.py
cat metrics.txt >> report.md
cml-publish confusion_matrix.png --md >> report.md
cml-send-comment report.md
Overwriting .github/workflows/cml.yaml
# %load train.py
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt
import json
import os
import numpy as np
# Read in data
X_train = np.genfromtxt("data/train_features.csv")
y_train = np.genfromtxt("data/train_labels.csv")
X_test = np.genfromtxt("data/test_features.csv")
y_test = np.genfromtxt("data/test_labels.csv")
# Fit a model
depth = 2
clf = RandomForestClassifier(max_depth=depth)
clf.fit(X_train,y_train)
acc = clf.score(X_test, y_test)
print(acc)
with open("metrics.txt", 'w') as outfile:
outfile.write("Accuracy: " + str(acc) + "\n")
# Plot it
disp = plot_confusion_matrix(clf, X_test, y_test, normalize='true',cmap=plt.cm.Blues)
plt.savefig('confusion_matrix.png')
Wprowadźmy zmianę do pliku (linijka 17: depth= = 6
)
%%writefile train.py
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt
import json
import os
import numpy as np
# Read in data
X_train = np.genfromtxt("data/train_features.csv")
y_train = np.genfromtxt("data/train_labels.csv")
X_test = np.genfromtxt("data/test_features.csv")
y_test = np.genfromtxt("data/test_labels.csv")
# Fit a model
depth = 6
clf = RandomForestClassifier(max_depth=depth)
clf.fit(X_train,y_train)
acc = clf.score(X_test, y_test)
print(acc)
with open("metrics.txt", 'w') as outfile:
outfile.write("Accuracy: " + str(acc) + "\n")
# Plot it
disp = plot_confusion_matrix(clf, X_test, y_test, normalize='true',cmap=plt.cm.Blues)
plt.savefig('confusion_matrix.png')
Overwriting train.py
Stwórzmy nowy branch "deep_depth":
!git checkout -b deep_depth
!git add train.py .github/workflows/cml.yaml
!git commit -m "Changed depth and added cml workflow"
!git push origin deep_depth
Switched to a new branch 'deep_depth' [deep_depth 0df0f2c] Changed depth and added cml workflow 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/cml.yaml Enumerating objects: 8, done. Counting objects: 100% (8/8), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 738 bytes | 738.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 2 local objects.[K remote: remote: Create a pull request for 'deep_depth' on GitHub by visiting:[K remote: https://github.com/TomekZet/example_cml/pull/new/deep_depth[K remote: To github.com:TomekZet/example_cml.git * [new branch] deep_depth -> deep_depth
Zadania
- Utwórz konto na Github (jeśli jeszcze nie masz)
- Stwórz publiczne repozytorium. Link do niego wklej do kolumny "Link Github" w arkuszu "Zapisy na zbiory" [1 pkt]
- Stwórz prosty Github workflow wykorzystujący akcje CML, który:
- zrobi checkout Twojego repozytorium [2 pkt]
- ściągnie pliki trenujące. Najlepiej byłoby to zrobić za pomocą DVC, ale tym razem uprośćmy zadanie ze względu na koplikacje, które mogą się pojawić przy konfiguracji uwierzytelniania. Pliki można po prostu dodać do repozytorium albo ściągnąć przez wget jeśli są publicznie dostępne [2 pkt]
- dokona trenowania i ewaluacji [8 pkt]
- wyniki opublikuje za pomocą
cml-send-github-check
i/lubcml-send-comment
[2 pkt]