RSVP for your your local TensorFlow Everywhere event today!
Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Najlepsze praktyki testowania TensorFlow

Oto zalecane praktyki testowania kodu w repozytorium TensorFlow .

Zanim zaczniesz

Przed przesłaniem kodu źródłowego do projektu TensorFlow przejrzyj plik CONTRIBUTING.md w repozytorium GitHub projektu. (Na przykład zapoznaj się z plikiem CONTRIBUTING.md dla podstawowego repozytorium TensorFlow ). Wszyscy współtwórcy kodu są zobowiązani do podpisania umowy licencyjnej współautora (CLA).

Ogólne zasady

Zależy tylko od tego, czego używasz w swoich regułach BUILD

TensorFlow to duża biblioteka, a pisanie testu jednostkowego dla jego podmodułów polegało na zależności od pełnego pakietu. Jednak bazel to wyłączenie analizy opartej na zależnościach bazel . Oznacza to, że systemy ciągłej integracji nie mogą w inteligentny sposób eliminować niepowiązanych testów dla przebiegów przed przesłaniem / po przesłaniu. Jeśli polegasz tylko na modułach podrzędnych, które testujesz w pliku BUILD , zaoszczędzisz czas wszystkich programistów TensorFlow i dużo cennej mocy obliczeniowej.

Jednak modyfikowanie zależności kompilacji w celu pominięcia pełnych celów TF powoduje pewne ograniczenia dotyczące tego, co można zaimportować w kodzie Pythona. Nie będzie już można używać instrukcji import tensorflow as tf instrukcji import tensorflow as tf w testach jednostkowych. Jest to jednak opłacalny kompromis, ponieważ oszczędza wszystkim programistom wykonywania tysięcy niepotrzebnych testów.

Cały kod powinien mieć testy jednostkowe

Dla każdego napisanego kodu należy również napisać jego testy jednostkowe. Jeśli napiszesz nowy plik foo.py , powinieneś umieścić jego testy jednostkowe w foo_test.py i przesłać go w ramach tej samej zmiany. Celuj w> 90% przyrostowego pokrycia testami dla całego kodu.

Unikaj używania natywnych reguł testu bazel w TF

TF ma wiele subtelności podczas przeprowadzania testów. Pracowaliśmy, aby ukryć wszystkie te zawiłości w naszych makrach bazela. Aby uniknąć konieczności zajmowania się nimi, użyj następujących zamiast natywnych reguł testowych. Zauważ, że wszystkie z nich są zdefiniowane w tensorflow/tensorflow.bzl W przypadku testów CC użyj tf_cc_test , tf_gpu_cc_test , tf_gpu_only_cc_test . W przypadku testów Pythona użyj tf_py_test lub gpu_py_test . Jeśli potrzebujesz czegoś bardzo zbliżonego do natywnej reguły py_test , użyj zamiast tego reguły zdefiniowanej w tensorflow.bzl. Wystarczy dodać następujący wiersz na początku pliku BUILD: load(“tensorflow/tensorflow.bzl”, “py_test”)

Miej świadomość, gdzie wykonywany jest test

Kiedy piszesz test, nasza infra testowa może zająć się przeprowadzaniem testów na CPU, GPU i akceleratorach, jeśli napiszesz je odpowiednio. Mamy zautomatyzowane testy, które działają na Linuksie, macOS, Windows, które mają systemy z lub bez GPU. Wystarczy wybrać jedno z wymienionych powyżej makr, a następnie użyć tagów, aby ograniczyć miejsce ich wykonywania.

  • tag manual wykluczy Twój test z dowolnego miejsca. Obejmuje to ręczne wykonywanie testów, które używają wzorców, takich jak bazel test tensorflow/…

  • no_oss wykluczy Twój test z uruchamiania w oficjalnej infrastrukturze testowej TF OSS.

  • no_mac lub no_windows mogą służyć do wykluczania testu z odpowiednich zestawów testów systemu operacyjnego.

  • no_gpu tagu no_gpu można wykluczyć test z uruchamiania w pakietach testów GPU.

Sprawdź, czy testy są uruchamiane w oczekiwanych zestawach testów

TF ma sporo zestawów testowych. Czasami ich konfiguracja może być myląca. Mogą występować różne problemy, które powodują pomijanie testów w ciągłych kompilacjach. Dlatego należy sprawdzić, czy testy działają zgodnie z oczekiwaniami. Aby to zrobić:

  • Poczekaj, aż wstępne przesłania żądania ściągnięcia (PR) przebiegną do końca.
  • Przewiń w dół swojego PR, aby zobaczyć kontrole stanu.
  • Kliknij link „Szczegóły” po prawej stronie dowolnego czeku Kokoro.
  • Sprawdź listę „Cele”, aby znaleźć nowo dodane cele.

Każda klasa / jednostka powinna mieć własny plik testów jednostkowych

Oddzielne klasy testowe pomagają nam lepiej izolować awarie i zasoby. Prowadzą do znacznie krótszych i łatwiejszych do odczytania plików testowych. Dlatego wszystkie twoje pliki Pythona powinny mieć co najmniej jeden odpowiedni plik testowy (dla każdego foo.py powinien mieć foo_test.py ). W przypadku bardziej skomplikowanych testów, takich jak testy integracyjne, które wymagają różnych konfiguracji, można dodać więcej plików testowych.

Prędkość i czasy pracy

Odłamki powinny być używane jak najmniej

Zamiast dzielenia na fragmenty rozważ:

  • Zmniejszanie rozmiarów testów
  • Jeśli powyższe nie jest możliwe, podziel testy

Fragmentowanie pomaga zmniejszyć ogólne opóźnienie testu, ale to samo można osiągnąć, dzieląc testy na mniejsze cele. Dzielenie testów daje nam lepszy poziom kontroli nad każdym testem, minimalizując niepotrzebne wstępne uruchomienia i zmniejszając utratę pokrycia z powodu wyłączenia całego obiektu docelowego z powodu nieprawidłowo działającego przypadku testowego. Co więcej, tworzenie fragmentów wiąże się z ukrytymi kosztami, które nie są tak oczywiste, takie jak uruchomienie całego kodu inicjującego test dla wszystkich fragmentów. Ten problem został zgłoszony do nas przez zespoły infra jako źródło, które powoduje dodatkowe obciążenie.

Mniejsze testy są lepsze

Im szybciej przeprowadzisz testy, tym większe prawdopodobieństwo, że ludzie je wykonają. Jedna dodatkowa sekunda na test może skumulować się do godzin dodatkowego czasu spędzonego na przeprowadzaniu testu przez programistów i naszą infrastrukturę. Postaraj się, aby testy działały krócej niż 30 sekund (w trybie non-opt!) I spraw, aby były małe. Oznaczaj testy jako średnie tylko w ostateczności. Infra nie przeprowadza żadnych dużych testów jako przesłanych wstępnych lub po przesłaniu! Dlatego napisz duży test tylko wtedy, gdy zamierzasz ustalić, gdzie będzie on wykonywany. Kilka wskazówek, jak przyspieszyć działanie testów:

  • Wykonuj mniej powtórzeń treningu w teście
  • Rozważ użycie wstrzykiwania zależności w celu zastąpienia ciężkich zależności testowanego systemu prostymi podróbkami.
  • Rozważ użycie mniejszych danych wejściowych w testach jednostkowych
  • Jeśli nic innego nie działa, spróbuj podzielić plik testowy.

Czasy testu powinny mieć na celu połowę limitu czasu testu, aby uniknąć płatków

W bazel celów testowych bazel , małe testy mają 1-minutowe przerwy. Średnie limity czasu testu to 5 minut. Duże testy po prostu nie są wykonywane przez test TensorFlow infra. Jednak wiele testów nie jest deterministycznych pod względem czasu, jaki zajmują. Z różnych powodów twoje testy mogą od czasu do czasu zająć więcej czasu. A jeśli oznaczysz test, który trwa średnio 50 sekund jako mały, test zakończy się niepowodzeniem, jeśli zostanie zaplanowany na komputerze ze starym procesorem. Dlatego w przypadku małych testów należy dążyć do 30-sekundowego średniego czasu działania. Celuj przez 2 minuty i 30 sekund średniego czasu działania dla średnich testów.

Zmniejsz liczbę próbek i zwiększ tolerancje podczas treningu

Powolne testy odstraszają współpracowników. Trening biegowy w testach może być bardzo powolny. Preferuj wyższe tolerancje, aby móc używać mniej próbek w testach i utrzymywać je wystarczająco szybko (maksymalnie 2,5 minuty).

Wyeliminuj niedeterminizm i łuski

Pisz testy deterministyczne

Testy jednostkowe powinny zawsze być deterministyczne. Wszystkie testy działające na TAP i gitarze powinny za każdym razem działać w ten sam sposób, jeśli nie ma na nie wpływu żadna zmiana kodu. Aby to zapewnić, poniżej przedstawiono kilka punktów do rozważenia.

Zawsze zasiewaj każde źródło stochastyczności

Dowolny generator liczb losowych lub jakiekolwiek inne źródła stochastyczności mogą powodować łuszczenie. Dlatego każdy z nich musi zostać obsiany. Oprócz tego, że testy są mniej łuszczące, zapewnia to powtarzalność wszystkich testów. Różne sposoby ustawienia nasion, które mogą być potrzebne w testach TF, to:

# Python RNG
import random
random.seed(42)

# Numpy RNG
import numpy as np
np.random.seed(42)

# TF RNG
from tensorflow.python.framework import random_seed
random_seed.set_seed(42)

Unikaj używania sleep w testach wielowątkowych

Korzystanie z funkcji sleep w testach może być główną przyczyną łuszczenia się. Zwłaszcza w przypadku korzystania z wielu wątków użycie trybu uśpienia do oczekiwania na inny wątek nigdy nie będzie deterministyczne. Jest to spowodowane tym, że system nie jest w stanie zagwarantować żadnej kolejności wykonywania różnych wątków lub procesów. Dlatego preferuj deterministyczne konstrukcje synchronizacji, takie jak muteksy.

Sprawdź, czy test jest niestabilny

Płatki powodują, że narzędzia budowlane i programiści tracą wiele godzin. Są trudne do wykrycia i trudne do debugowania. Mimo że istnieją zautomatyzowane systemy wykrywające łuszczenie, muszą one zgromadzić setki serii testów, zanim będą mogły dokładnie przeprowadzić testy denylistyczne. Nawet jeśli wykryją, denylują twoje testy i tracą zasięg testów. Dlatego autorzy testów powinni podczas pisania testów sprawdzić, czy ich testy są niestabilne. Można to łatwo zrobić, uruchamiając test z flagą: --runs_per_test=1000

Użyj TensorFlowTestCase

TensorFlowTestCase podejmuje niezbędne środki ostrożności, takie jak zaszczepianie wszystkich generatorów liczb losowych używanych w celu maksymalnego zmniejszenia łuszczenia się. Gdy odkryjemy i naprawimy więcej źródeł niestabilności, wszystkie one zostaną dodane do TensorFlowTestCase. Dlatego podczas pisania testów dla tensorflow należy używać TensorFlowTestCase. TensorFlowTestCase jest zdefiniowany tutaj: tensorflow/python/framework/test_util.py

Pisz testy hermetyczne

Testy hermetyczne nie wymagają żadnych zewnętrznych zasobów. Są spakowani we wszystko, czego potrzebują, i po prostu rozpoczynają fałszywe usługi, których mogą potrzebować. Wszelkie usługi inne niż Twoje testy są źródłem niedeterminizmu. Nawet przy 99% dostępności innych usług, sieć może się załamać, odpowiedź RPC może być opóźniona i możesz otrzymać niewytłumaczalny komunikat o błędzie. Usługami zewnętrznymi mogą być między innymi GCS, S3 lub dowolna witryna internetowa.