1. Odkryj, co jądro jeszcze pamięta
Plik notebooka i stan jądra nie zawsze opowiadają tę samą historię. Zmienna może pochodzić z usuniętej komórki, lista mogła być modyfikowana kilka razy, a obiekt wczytany przed ostatnią zmianą kodu może pozostać w pamięci. Wyświetlane wyniki nie dowodzą więc, że bieżące komórki nadal dają te wyniki w widocznej kolejności.
Zachowaj kopię roboczą, zrestartuj jądro, a następnie uruchom komórki od początku do końca. Zanotuj pierwszą komórkę, która zawodzi lub zmienia wynik. Poszukaj brakującej zależności, zamiast ręcznie wstrzykiwać zmienną ze starej sesji. Jądro Jupyter to odrębny proces; zamknięcie karty nie jest równoznaczne z odtworzeniem czystego środowiska.
Zinwentaryzuj także efekty zewnętrzne: pobieranie, instalację pakietu, zmianę katalogu, odczyt już wygenerowanego pliku i użycie zmiennej środowiskowej. Komórka, której wynik wydaje się natychmiastowy, może po prostu korzystać ze starego pliku. Twój przyszły skrypt musi umieć odróżnić świadome wejście od pozostałości po próbie.
2. Napisz kontrakt, zanim przeniesiesz kod
Wybierz jedno zadanie do wyodrębnienia. Na przykład: odczytaj plik z wynikami, zachowaj identyfikatory, których wynik osiąga próg, i zapisz rezultat. Przykład z tego przewodnika jest dydaktyczny, nieuruchamiany i bez GPU. Służy pokazaniu zależności wykonania, a nie ogłaszaniu pomiaru lub narzędzia dostarczanego z Kernodeck.
Zdefiniuj wejście, parametr i wyjście z wystarczającą precyzją, aby zweryfikować przekształcenie. Tutaj próg jest domknięty: wynik równy 0,5 jest zachowany. Identyfikatory muszą pozostać powiązane ze swoimi wynikami, a kolejność wejściowa jest zachowana. Istniejące wyjście nie może zostać nieumyślnie zastąpione przez nową próbę.
Ten krok zapobiega niejednoznacznej migracji: jeśli notebook odrzucał wyniki równe progowi, a skrypt je zachowuje, zmieniłeś obliczenie. Zdecyduj wyraźnie, czy to poprawka, czy regresja. Zachowaj przypadek dokładnie na granicy, nie tylko dwie odległe wartości.
Przewiń tabelę, aby zobaczyć wszystkie kolumny.| Element | Wartość z przykładu | Kryterium |
|---|---|---|
| Wejście | a: 0,4; b: 0,8; c: 0,5 | Trzy odrębne identyfikatory, wyniki już zwalidowane między 0 a 1. |
| Parametr | Próg 0,5 | Porównanie większe lub równe. |
| Oczekiwane wyjście | b, potem c | Dwa identyfikatory, bez duplikacji i bez zmiany kolejności. |
3. Wyodrębnij funkcję, która nie zależy już od komórki
Oddziel przekształcenie od operacji odczytu i zapisu. Funkcja obliczeniowa otrzymuje swoje dane i swój próg, a następnie zwraca wybrane identyfikatory. Nie odwołuje się do zmiennej globalnej o nazwie seuil, nie otwiera pośrednio pliku i nie modyfikuje listy wejściowej. Dzięki temu notebook i skrypt mogą wywoływać dokładnie to samo obliczenie.
W tym fragmencie zakłada się, że dane zostały już zwalidowane zgodnie z poprzednim kontraktem. Funkcja nie stanowi więc pełnego walidatora pliku. To ograniczenie jest zamierzone: sprawdź formaty na wejściu programu, a następnie utrzymuj przekształcenie łatwe do zrozumienia. Dodanie parametru nie powinno wymagać odnajdywania komórki, która zmieniła jakąś wartość.
Notebook może pozostać Twoim narzędziem eksploracji. Niech importuje tę funkcję, zamiast utrzymywać drugą kopię. Po zmodyfikowaniu modułu zacznij od nowego jądra, aby porównać obie ścieżki; stara, już zaimportowana funkcja nie może fałszować weryfikacji.
def retenir_identifiants(records, seuil):
return [
record["id"]
for record in records
if record["score"] >= seuil
]
if __name__ == "__main__":
records = [
{"id": "a", "score": 0.4},
{"id": "b", "score": 0.8},
{"id": "c", "score": 0.5},
]
attendu = ["b", "c"]
obtenu = retenir_identifiants(records, 0.5)
if obtenu != attendu:
raise SystemExit("Sélection inattendue")4. Uczyń parametry widocznym wejściem
Punkt wejścia skryptu przetwarza argumenty, waliduje wybory i wywołuje funkcje. Standardowy moduł argparse opisuje opcje i generuje pomoc; nie zna Twoich reguł biznesowych. Liczba zmiennoprzecinkowa akceptowana składniowo może wciąż wykraczać poza dozwolony zakres. Próg w tym przykładzie wymaga więc dodatkowego sprawdzenia.
Określ sposób rozwiązywania ścieżek: względem katalogu, z którego uruchamiane jest polecenie, albo względem jawnie wybranego katalogu projektu. Nie stosuj ukrytej zmiany katalogu w trakcie obliczeń. Poniższy blok pokazuje wyłącznie analizę argumentów; wczytywanie danych i zapis pozostają do podłączenia w programie czytnika.
Trzymaj sekrety poza tymi argumentami. Parametry, którymi można się dzielić, opisują eksperyment; dostęp do repozytorium lub magazynu danych przebiega innym kanałem. Polecenie przydatne dla kolegi musi dać się skopiować bez kopiowania także tokenu.
import argparse
from pathlib import Path
def lire_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True, type=Path)
parser.add_argument("--output", required=True, type=Path)
parser.add_argument("--seuil", required=True, type=float)
args = parser.parse_args()
if not 0 <= args.seuil <= 1:
parser.error("Le seuil doit être compris entre 0 et 1.")
return args5. Nadaj skryptowi zakończenie i weryfikowalne wyniki
Umieść orkiestrację w funkcji main i wywołaj ją pod warunkiem if __name__ == "__main__". Dzięki temu moduł można zaimportować z notebooka bez natychmiastowego uruchamiania przetwarzania. Importy definiują narzędzia; punkt wejścia decyduje, kiedy czytać, liczyć i zapisywać.
Przydziel osobny katalog dla każdego uruchomienia. Zapisz rzeczywiście użyte parametry niebędące danymi wrażliwymi oraz tożsamość wejścia, a następnie zapisz wyniki. W naszym wyborze sprawdź liczbę identyfikatorów, ich przynależność do wejścia i regułę progu. Poprawnie sformatowany plik JSON może zawierać błędne identyfikatory; sam jego fakt istnienia nie wystarcza.
Zapewnij jawne niepowodzenie, gdy brakuje pliku wejściowego lub gdy miejsce docelowe nie nadaje się do użycia. Nie zastępuj tych problemów pustą listą: można by ją uznać za prawidłowy wybór. Program musi odróżniać brak wyników spełniających próg od braku wyników spowodowanego nieudanym odczytem.
6. Porównanie w dwóch świeżych uruchomieniach
Najpierw użyj trzech linii dydaktycznych. Przy progu 0,5 oczekuj b i c; przy 0,9 oczekuj pustej listy; przy 0,4 oczekuj trzech identyfikatorów. Te odpowiedzi wynikają z kontraktu i nie są tu przedstawiane jako wyniki faktycznie uruchomione. Pozwalają wychwycić odwrócony operator porównania lub błędną kolejność.
Następnie uruchom swój zrestartowany notebook i swój skrypt w świeżym procesie, na tym samym wejściu. Porównuj istotne wartości, a nie zrzuty ekranu ani godziny zapisane w plikach. Dodaj drugi reprezentatywny zestaw i nieprawidłowe wejście. Udokumentuj oczekiwane różnice, takie jak bardziej oszczędna prezentacja wyników.
Konwersja przez nbconvert może przyspieszyć wstępne przeniesienie komórek, ale jej polecenia magiczne mogą nadal zależeć od Jupytera. Usuń lub zastąp instrukcje specyficzne dla notebooka, zbędne wyświetlenia i doraźne instalacje. Eksport to punkt wyjścia; o zakończeniu migracji decyduje porównanie ze świeżego stanu.
7. Przejście na GPU bez ponownego wprowadzania ukrytego stanu
Gdy zrozumiesz już przebieg na CPU, podłącz wczytywanie modelu i backend do tej samej jawnej struktury. Zachowaj wersje, precyzję, wejście i miejsce docelowe. Przejście na GPU nie naprawi ani niespójnej kolejności komórek, ani pliku wytworzonego przez wcześniejszy przebieg. Osobno sprawdź, czy PyTorch rzeczywiście potrafi liczyć na wybranym urządzeniu.
Jeśli dwa uruchomienia dają różne wartości, rozróżnij zapomniany stan, źródło losowości i numeryczne ograniczenia obliczeń. Ziarno nie jest uniwersalną gwarancją identyczności między wersjami i sprzętami. W przypadku przerwanego treningu użyj procedury przeznaczonej dla checkpointów: ten przewodnik przekształca punkt wejścia, nie odtwarzając stanów optymalizatora ani generatorów.
Użytecznym wynikiem jest program, który możesz opisać jedną komendą, wraz z jego wymaganiami wstępnymi i kontrolą wyniku. Notebook pozostaje wolny do eksploracji i śledzenia; nie jest już jedynym nośnikiem pamięci o tym, jak należy uruchomić obliczenie.