1. Oddziel program, jego parametry i śledzenie rozliczeń
Kod opisuje zachowanie programu. Konfiguracja określa obciążenie: model, dane, batch, precyzję i miejsce docelowe. Sekrety zapewniają dostęp do niezbędnych zasobów. Trzymaj te elementy osobno, aby zmienić próbę bez przepisywania kodu czy kopiowania tokena do współdzielonego pliku.
Odnośnik zamówienia Kernodeck pozwala odnaleźć kontekst wynajmu na Twoim koncie. Identyfikator próby odróżnia uruchomienia Twojego programu w tym okresie. Łącz je w notatkach, jeśli to pomaga, ale nie wymagaj od swojego skryptu wywnioskowania stanu obliczeń ze statusu płatności.
Weźmy projekt klasyfikacji dokumentów, który ma być uruchamiany wielokrotnie na tej samej próbce. Kontrakt programu opisuje plik wejściowy, dopuszczalne parametry, katalog wyjściowy i sposób zgłaszania błędów. Przewodnik po danych określa walidację zawartości; tutaj organizujemy interfejs łączący te etapy.
2. Napisz jawny i wersjonowany kontrakt wejściowy
Udokumentuj pola wymagane i akceptowane wartości. Unikaj cichych wartości domyślnych dla decyzji, która zmienia wynik, jak model czy urządzenie. Numer schematu odróżnia formę konfiguracji od wersji kodu; nie zastępuje tej ostatniej.
W tym przykładzie dydaktycznym plik JSON zawiera schemat, ścieżkę wejściową, batch i żądane urządzenie. Ścieżki względne są odczytywane od katalogu konfiguracji. Ta zasada przyjęta dla przykładu pozwala uniknąć zależności od katalogu, z którego kolega uruchamia komendę.
Odczyt poprawnego JSON weryfikuje tylko jego składnię. Twój program musi następnie sprawdzić typy, pola i ograniczenia projektu. W razie błędu powinien zatrzymać się przed załadowaniem kosztownego zasobu, z komunikatem nazywającym parametr do poprawienia.
{
"schema_version": 1,
"input": "../data/pilote.jsonl",
"batch_size": 4,
"device": "cuda"
}3. Przygotuj punkt wejścia, który odrzuca proste błędy
argparse pozwala deklarować opcje i generować pomoc dla Twojej komendy. Poniższy przykład stanowi wyłącznie kontrolę wstępną: odczytuje konfigurację, sprawdza jej pola i wykrywa już używany katalog wyjściowy. Nie ładuje modelu ani danych do pamięci i nie testuje dostępności GPU.
Zapisz ten kod dydaktyczny w prepare_run.py, jeśli chcesz go dostosować. Jest proponowany bez potwierdzonego wykonania. Następnie dodaj swoje kontrole biznesowe w aplikacji, zamiast traktować końcowy komunikat jako wynik obliczeń. Urządzenie cuda pozostaje żądaniem; PyTorch używa też tej nazwy z ROCm.
Odmowa dla istniejącego katalogu wyjściowego jest tu konwencją ochrony przed mieszaniem prób. Prawdziwa komenda wznowienia musi otrzymać opcję i odrębne kontrole. Nie zamieniaj nowego uruchomienia w niejawne wznowienie tylko dlatego, że pliki są obecne.
import argparse
import json
from pathlib import Path
parser = argparse.ArgumentParser(description="Walidacja uruchomienia projektu")
parser.add_argument("--config", type=Path, required=True)
parser.add_argument("--run-dir", type=Path, required=True)
args = parser.parse_args()
try:
config_path = args.config.resolve()
config = json.loads(config_path.read_text(encoding="utf-8"))
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
parser.error(f"Nie można odczytać konfiguracji: {exc}")
expected = {"schema_version", "input", "batch_size", "device"}
if not isinstance(config, dict) or set(config) != expected:
parser.error("Oczekiwane pola: schema_version, input, batch_size, device")
if type(config["schema_version"]) is not int or config["schema_version"] != 1:
parser.error("schema_version musi mieć wartość 1")
if type(config["batch_size"]) is not int or config["batch_size"] < 1:
parser.error("batch_size musi być dodatnią liczbą całkowitą")
if config["device"] not in ("cpu", "cuda"):
parser.error("device musi mieć wartość cpu lub cuda")
if not isinstance(config["input"], str) or not config["input"]:
parser.error("input musi być niepustą ścieżką")
input_path = (config_path.parent / config["input"]).resolve()
run_dir = args.run_dir.resolve()
if not input_path.is_file():
parser.error("Brak pliku wejściowego")
if run_dir.exists():
parser.error("Wybierz nowy folder wyjściowy")
print(json.dumps({
"status": "configuration_validated",
"input": str(input_path),
"run_dir": str(run_dir),
"device_requested": config["device"],
"batch_size": config["batch_size"]
}, ensure_ascii=False))python prepare_run.py --config config/pilote.json --run-dir runs/pilote-0014. Nadaj tożsamość uruchomieniom i ich wynikom
Przypisz każde uruchomienie do krótkiego identyfikatora, unikalnego w ramach kampanii. Zapisz rewizję kodu, schemat i faktycznie użyte parametry, a następnie odwołanie do danych i modelu. Przechowuj te wartości razem z wynikami, aby rezultat nie zależał od pliku konfiguracyjnego zmodyfikowanego później.
Aby porównać dwa rozmiary batcha, utwórz dwa testy i dwa katalogi. Zachowaj tę samą próbkę i wskaż zamierzoną różnicę. Same nazwy pilote-001 i pilote-002 nie wyjaśniają, co się zmieniło: manifest łączy nazwę z parametrami.
Zarezerwuj format podsumowania czytelny dla Twoich narzędzi. Może on rozróżniać elementy odebrane, zakończone sukcesem, odrzucone i pozostałe do przetworzenia. Wybierz jedną regułę pełnego sukcesu i nie oznaczaj testu jako zakończonego już przy zapisaniu pierwszego wyniku. Kod powrotu programu musi pozostać spójny z tym wnioskiem.
Przewiń tabelę, aby zobaczyć wszystkie kolumny.| Plik lub stan | Rola | Oczekiwana kontrola |
|---|---|---|
| manifest.json | Tożsamość kodu, danych i parametrów | Faktycznie użyte wartości, bez sekretów. |
| results.jsonl | Jeden wynik na zaakceptowany element | Znane identyfikatory i zgodny format. |
| errors.jsonl | Elementy odrzucone i użyteczny powód | Bez cichego znikania i bez zbędnych danych wrażliwych. |
| summary.json | Wniosek z testu i liczniki | Spójna suma, pliki odczytane ponownie przed statusem końcowym. |
5. Udostępniaj zdarzenia użyteczne dla Twoich narzędzi
Uwidocznij kilka przejść: konfiguracja zaakceptowana, dane dostępne, model załadowany, pierwszy wynik zapisany i koniec przetwarzania. Ślad powinien pozwalać odpowiedzieć na pytanie „na jakim etapie jest to uruchomienie?” bez kopiowania dokumentów czy promptów. Powiąż etap i identyfikator testu z komunikatem.
Moduł logging w Pythonie pozwala organizować komunikaty według poziomu i miejsca docelowego. Następnie wybierz własną konwencję zdarzeń i udokumentuj ją. Aplikacja, która zapisuje błąd, a potem kończy się sukcesem, czyni automatyzację zwodniczą; z drugiej strony nie każde ostrzeżenie oznacza, że wynik jest bezużyteczny.
Nie myl emitowanego zdarzenia z trwałym wynikiem: komunikat „rozpoczęto zapis” nie dowodzi, że plik został ponownie odczytany. W przypadku długiego uruchomienia dedykowany przewodnik wyjaśnia związek między procesem a sesją. Twoje interfejs powinien przede wszystkim zachować wniosek dostępny po zakończeniu interaktywnego połączenia.
6. Zdefiniuj porażkę, wznowienie i końcową weryfikację
Klasyfikuj przydatne błędy: nieprawidłowa konfiguracja, brakujący zasób, błąd obliczeń i wynik niezgodny z oczekiwaniami. Dla każdego podaj następne działanie. Nie instaluj automatycznego ponawiania, zanim nie zdecydujesz, które efekty można powtórzyć: nadpisanie już zaakceptowanego wyniku i wznowienie od checkpointu wymagają różnych reguł.
Twoja końcowa procedura wyjaśnia, jak uruchomić, obserwować, zatrzymać, wznowić i wyeksportować. W przypadku przetwarzania dokumentów prowadź listę zakończonych identyfikatorów i tych do ponownego przetworzenia. W przypadku treningu użyj protokołu, który weryfikuje zapisane stany w nowym procesie. Niepusty katalog nie jest dowodem poprawnego wznowienia.
Na koniec sprawdź projekt z nowego wywołania, ze znaną konfiguracją i odrębnym miejscem docelowym. Zweryfikuj oczekiwane odmowy, a następnie niewielką pełną ścieżkę. Kontrola wstępna opisana na tej stronie nie obejmuje dostępu współbieżnego, publicznego udostępnienia usługi ani uprawnień do przechowywania: te zagadnienia wymagają własnego projektu.