Best Practices für TensorFlow-Tests

Dies sind die empfohlenen Methoden zum Testen von Code im TensorFlow-Repository .

Bevor Sie anfangen

Bevor Sie Quellcode zu einem TensorFlow-Projekt beitragen, überprüfen Sie bitte die Datei CONTRIBUTING.md im GitHub-Repo des Projekts. ( Informationen zum TensorFlow-Kern-Repo finden Sie beispielsweise in der Datei CONTRIBUTING.md .) Alle Code-Mitwirkenden müssen eine Contributor-Lizenzvereinbarung ( Contributor License Agreement, CLA) unterzeichnen.

Allgemeine Grundsätze

Hängen Sie nur davon ab, was Sie in Ihren BUILD-Regeln verwenden

TensorFlow ist eine große Bibliothek, und je nach Gesamtpaket war das Schreiben eines Komponententests für seine Submodule eine gängige Praxis. Dies deaktiviert jedoch die auf bazel Abhängigkeiten basierende Analyse. Dies bedeutet, dass kontinuierliche Integrationssysteme nicht verwandte Tests für Voreinreichungs- / Nacheinreichungsläufe nicht intelligent eliminieren können. Wenn Sie nur von den Submodulen abhängen, die Sie in Ihrer BUILD Datei testen, sparen Sie Zeit für alle TensorFlow-Entwickler und viel wertvolle Rechenleistung.

Das Ändern Ihrer Build-Abhängigkeit, um die vollständigen TF-Ziele wegzulassen, bringt jedoch einige Einschränkungen für das mit sich, was Sie in Ihren Python-Code importieren können. Sie können den import tensorflow as tf Anweisung in Ihren import tensorflow as tf verwenden. Dies ist jedoch ein lohnender Kompromiss, da alle Entwickler nicht Tausende unnötiger Tests durchführen müssen.

Alle Codes sollten Unit-Tests haben

Für jeden Code, den Sie schreiben, sollten Sie auch die Komponententests schreiben. Wenn Sie eine neue Datei foo.py schreiben, sollten Sie deren foo_test.py in foo_test.py und innerhalb derselben Änderung foo_test.py . Streben Sie eine inkrementelle Testabdeckung von> 90% für Ihren gesamten Code an.

Vermeiden Sie die Verwendung nativer Bazel-Testregeln in TF

TF hat viele Feinheiten beim Ausführen von Tests. Wir haben daran gearbeitet, all diese Komplexitäten in unseren Bazel-Makros zu verbergen. Verwenden Sie anstelle der nativen Testregeln die folgenden Regeln, um zu vermeiden, dass Sie sich mit diesen befassen müssen. Beachten Sie, dass alle diese tensorflow/tensorflow.bzl in tensorflow/tensorflow.bzl definiert sind. tensorflow/tensorflow.bzl für CC-Tests tf_cc_test , tf_gpu_cc_test , tf_gpu_only_cc_test . Verwenden tf_py_test für Python-Tests tf_py_test oder gpu_py_test . Wenn Sie etwas benötigen, das der nativen py_test Regel sehr nahe py_test , verwenden Sie stattdessen die in tensorflow.bzl definierte. Sie müssen nur die folgende Zeile oben in die BUILD-Datei load(“tensorflow/tensorflow.bzl”, “py_test”) : load(“tensorflow/tensorflow.bzl”, “py_test”)

Beachten Sie, wo der Test ausgeführt wird

Wenn Sie einen Test schreiben, kann unsere Testinfra dafür sorgen, dass Ihre Tests auf CPU, GPU und Beschleunigern ausgeführt werden, wenn Sie sie entsprechend schreiben. Wir haben automatisierte Tests, die unter Linux, Macos und Windows ausgeführt werden und Systeme mit oder ohne GPUs haben. Sie müssen lediglich eines der oben aufgeführten Makros auswählen und dann mithilfe von Tags einschränken, wo sie ausgeführt werden.

  • manual Tag schließt aus, dass Ihr Test irgendwo ausgeführt wird. Dies schließt manuelle Testausführungen ein, die Muster wie bazel test tensorflow/…

  • no_oss schließt Ihren Test von der Ausführung in der offiziellen TF OSS-Testinfrastruktur aus.

  • no_mac no_windows Tags no_mac oder no_windows können Sie Ihren Test von relevanten Betriebssystem- no_windows ausschließen.

  • no_gpu Tag no_gpu können Sie Ihren Test von der Ausführung in GPU- no_gpu ausschließen.

Überprüfen Sie, ob Tests in erwarteten Testsuiten ausgeführt werden

TF hat einige Testsuiten. Manchmal kann die Einrichtung verwirrend sein. Möglicherweise gibt es verschiedene Probleme, die dazu führen, dass Ihre Tests in fortlaufenden Builds nicht berücksichtigt werden. Daher sollten Sie überprüfen, ob Ihre Tests wie erwartet ausgeführt werden. Um dies zu tun:

  • Warten Sie, bis Ihre Vorabübermittlungen auf Ihrer Pull-Anforderung (PR) vollständig ausgeführt wurden.
  • Scrollen Sie zum Ende Ihrer PR, um die Statusprüfungen anzuzeigen.
  • Klicken Sie auf den Link "Details" auf der rechten Seite eines Kokoro-Checks.
  • Überprüfen Sie die Liste "Ziele", um Ihre neu hinzugefügten Ziele zu finden.

Jede Klasse / Einheit sollte eine eigene Einheitentestdatei haben

Separate Testklassen helfen uns, Fehler und Ressourcen besser zu isolieren. Sie führen zu viel kürzeren und leichter lesbaren Testdateien. Daher sollten alle Ihre Python-Dateien mindestens eine entsprechende Testdatei haben (für jede foo.py sollte sie foo_test.py ). Für aufwändigere Tests, wie z. B. Integrationstests, für die unterschiedliche Einstellungen erforderlich sind, können weitere Testdateien hinzugefügt werden.

Geschwindigkeit und Laufzeiten

Sharding sollte so wenig wie möglich verwendet werden

Anstatt zu scherben, bedenken Sie bitte:

  • Verkleinern Sie Ihre Tests
  • Wenn dies nicht möglich ist, teilen Sie die Tests auf

Durch Sharding wird die Gesamtlatenz eines Tests verringert. Dies kann jedoch erreicht werden, indem Tests auf kleinere Ziele aufgeteilt werden. Durch das Aufteilen von Tests erhalten wir eine genauere Kontrolle über jeden Test, wodurch unnötige Vorabübermittlungsläufe minimiert und der Abdeckungsverlust durch einen Buildcop verringert werden, der ein gesamtes Ziel aufgrund eines sich schlecht verhaltenden Testfalls deaktiviert. Darüber hinaus entstehen beim Sharding versteckte Kosten, die nicht so offensichtlich sind, z. B. das Ausführen des gesamten Testinitialisierungscodes für alle Shards. Dieses Problem wurde von Infra-Teams als Quelle für zusätzliche Belastung an uns weitergeleitet.

Kleinere Tests sind besser

Je schneller Ihre Tests ausgeführt werden, desto wahrscheinlicher ist es, dass Personen Ihre Tests ausführen. Eine zusätzliche Sekunde für Ihren Test kann sich auf Stunden zusätzlicher Zeit summieren, die Entwickler und unsere Infrastruktur für die Ausführung Ihres Tests aufgewendet haben. Versuchen Sie, Ihre Tests unter 30 Sekunden laufen zu lassen (im Nicht-Opt-Modus!), Und machen Sie sie klein. Markieren Sie Ihre Tests nur als letzten Ausweg als mittel. Die Infra führt keine großen Tests als Presubmits oder Postsubmits durch! Schreiben Sie daher nur dann einen großen Test, wenn Sie festlegen möchten, wo er ausgeführt werden soll. Einige Tipps, um Tests schneller laufen zu lassen:

  • Führen Sie in Ihrem Test weniger Trainingsiterationen durch
  • Erwägen Sie die Verwendung der Abhängigkeitsinjektion, um starke Abhängigkeiten des zu testenden Systems durch einfache Fälschungen zu ersetzen.
  • Erwägen Sie die Verwendung kleinerer Eingabedaten in Komponententests
  • Wenn nichts anderes funktioniert, versuchen Sie, Ihre Testdatei aufzuteilen.

Die Testzeiten sollten auf die Hälfte des Zeitlimits für die Testgröße abzielen, um Flocken zu vermeiden

Bei bazel Testzielen haben kleine Tests eine Zeitüberschreitung von 1 Minute. Mittlere Testzeitlimits betragen 5 Minuten. Große Tests werden vom TensorFlow-Test einfach nicht ausgeführt. Viele Tests sind jedoch nicht deterministisch in der Zeit, die sie benötigen. Aus verschiedenen Gründen können Ihre Tests von Zeit zu Zeit länger dauern. Wenn Sie einen Test, der durchschnittlich 50 Sekunden lang ausgeführt wird, als klein markieren, wird Ihr Test abblättern, wenn er auf einem Computer mit einer alten CPU geplant wird. Streben Sie daher für kleine Tests eine durchschnittliche Laufzeit von 30 Sekunden an. Streben Sie für mittlere Tests eine durchschnittliche Laufzeit von 2 Minuten und 30 Sekunden an.

Reduzieren Sie die Anzahl der Proben und erhöhen Sie die Toleranzen für das Training

Langsam laufende Tests schrecken die Mitwirkenden ab. Das Training in Tests kann sehr langsam sein. Bevorzugen Sie höhere Toleranzen, um weniger Proben in Ihren Tests verwenden zu können, um Ihre Tests ausreichend schnell zu halten (max. 2,5 Minuten).

Beseitigen Sie Nichtdeterminismus und Flocken

Schreiben Sie deterministische Tests

Unit-Tests sollten immer deterministisch sein. Alle Tests, die auf TAP und Gitarre ausgeführt werden, sollten jedes Mal auf die gleiche Weise ausgeführt werden, wenn keine Codeänderung Auswirkungen auf sie hat. Um dies sicherzustellen, sind im Folgenden einige Punkte zu beachten.

Saat immer eine Quelle der Stochastizität

Jeder Zufallszahlengenerator oder andere Stochastizitätsquellen können zu Schuppenbildung führen. Daher muss jeder von diesen ausgesät werden. Dies macht die Tests nicht nur weniger schuppig, sondern auch reproduzierbar. Es gibt verschiedene Möglichkeiten, um einige Samen zu setzen, die Sie möglicherweise in TF-Tests setzen müssen:

# 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)

Vermeiden Sie die Verwendung von sleep in Multithread-Tests

Die Verwendung der sleep in Tests kann eine Hauptursache für Schuppenbildung sein. Insbesondere bei Verwendung mehrerer Threads ist die Verwendung des Ruhezustands zum Warten auf einen anderen Thread niemals entscheidend. Dies liegt daran, dass das System keine Reihenfolge für die Ausführung verschiedener Threads oder Prozesse garantieren kann. Bevorzugen Sie daher deterministische Synchronisationskonstrukte wie Mutexe.

Überprüfen Sie, ob der Test schuppig ist

Flakes führen dazu, dass Buildcops und Entwickler viele Stunden verlieren. Sie sind schwer zu erkennen und schwer zu debuggen. Obwohl es automatisierte Systeme zum Erkennen von Schuppen gibt, müssen sie Hunderte von Testläufen akkumulieren, bevor sie Tests genau denylieren können. Selbst wenn sie erkennen, verweigern sie Ihre Tests und die Testabdeckung geht verloren. Daher sollten Testautoren beim Schreiben von Tests prüfen, ob ihre Tests schuppig sind. Dies kann einfach durchgeführt werden, indem Sie Ihren Test mit dem folgenden Flag --runs_per_test=1000 : --runs_per_test=1000

Verwenden Sie TensorFlowTestCase

TensorFlowTestCase trifft die erforderlichen Vorsichtsmaßnahmen, z. B. das Seeding aller Zufallszahlengeneratoren, die verwendet werden, um die Schuppenbildung so weit wie möglich zu reduzieren. Wenn wir mehr Flockigkeitsquellen entdecken und beheben, werden diese alle zu TensorFlowTestCase hinzugefügt. Daher sollten Sie TensorFlowTestCase verwenden, wenn Sie Tests für Tensorflow schreiben. TensorFlowTestCase wird hier definiert: tensorflow/python/framework/test_util.py

Schreiben Sie hermetische Tests

Hermetische Tests benötigen keine externen Ressourcen. Sie sind vollgepackt mit allem, was sie brauchen, und sie starten einfach alle gefälschten Dienste, die sie benötigen könnten. Alle anderen Dienste als Ihre Tests sind Quellen für Nichtdeterminismus. Selbst wenn andere Dienste zu 99% verfügbar sind, kann das Netzwerk ausfallen, die RPC-Antwort kann sich verzögern und es kann zu einer unerklärlichen Fehlermeldung kommen. Externe Dienste können GCS, S3 oder eine andere Website sein, sind jedoch nicht darauf beschränkt.