Thực hành tốt nhất về kiểm thử TensorFlow

Đây là các phương pháp được khuyến nghị để kiểm tra mã trong kho lưu trữ TensorFlow .

Trước khi bạn bắt đầu

Trước khi bạn đóng góp mã nguồn cho dự án TensorFlow, vui lòng xem lại tệp CONTRIBUTING.md trong kho GitHub của dự án. (Ví dụ: xem tệp CONTRIBUTING.md để biết kho lưu trữ TensorFlow cốt lõi .) Tất cả những người đóng góp mã đều phải ký Thỏa thuận cấp phép cộng tác viên (CLA).

Nguyên tắc chung

Chỉ phụ thuộc vào những gì bạn sử dụng trong quy tắc BUILD của mình

TensorFlow là một thư viện lớn và việc viết bài kiểm tra đơn vị cho các mô-đun con của nó phụ thuộc vào gói đầy đủ là một thông lệ. Tuy nhiên, điều này vô hiệu hóa phân tích dựa trên phụ thuộc bazel . Điều này có nghĩa là các hệ thống tích hợp liên tục không thể loại bỏ các thử nghiệm không liên quan một cách thông minh đối với các lần chạy trước/sau gửi. Nếu chỉ phụ thuộc vào các mô-đun con mà bạn đang thử nghiệm trong tệp BUILD , bạn sẽ tiết kiệm thời gian cho tất cả các nhà phát triển TensorFlow và rất nhiều sức mạnh tính toán có giá trị.

Tuy nhiên, việc sửa đổi phần phụ thuộc bản dựng của bạn để bỏ qua toàn bộ mục tiêu TF mang đến một số hạn chế đối với những gì bạn có thể nhập vào mã Python của mình. Bạn sẽ không thể sử dụng câu lệnh import tensorflow as tf trong các bài kiểm tra đơn vị của mình nữa. Nhưng đây là một sự đánh đổi đáng giá vì nó giúp tất cả các nhà phát triển tránh phải chạy hàng nghìn thử nghiệm không cần thiết.

Tất cả các mã nên có bài kiểm tra đơn vị

Đối với bất kỳ mã nào bạn viết, bạn cũng nên viết các bài kiểm tra đơn vị của nó. Nếu bạn viết một tệp mới foo.py , bạn nên đặt các bài kiểm tra đơn vị của nó vào foo_test.py và gửi nó trong cùng một thay đổi. Hãy nhắm tới phạm vi kiểm thử gia tăng >90% cho tất cả mã của bạn.

Tránh sử dụng quy tắc kiểm tra bazel gốc trong TF

TF có rất nhiều sự tinh tế khi chạy thử nghiệm. Chúng tôi đã cố gắng che giấu tất cả những điều phức tạp đó trong macro bazel của mình. Để tránh phải giải quyết những vấn đề đó, hãy sử dụng quy tắc sau thay vì quy tắc kiểm tra gốc. Lưu ý rằng tất cả những thứ này được xác định trong tensorflow/tensorflow.bzl Đối với các bài kiểm tra CC, hãy sử dụng tf_cc_test , tf_gpu_cc_test , tf_gpu_only_cc_test . Đối với các bài kiểm tra python, hãy sử dụng tf_py_test hoặc gpu_py_test . Nếu bạn cần một cái gì đó thực sự gần với quy tắc py_test gốc, thay vào đó hãy sử dụng quy tắc được xác định trong tensorflow.bzl. Bạn chỉ cần thêm dòng sau vào đầu tệp BUILD: load(“tensorflow/tensorflow.bzl”, “py_test”)

Hãy nhận biết nơi thực hiện thử nghiệm

Khi bạn viết bài kiểm thử, cơ sở hạ tầng kiểm thử của chúng tôi có thể đảm nhiệm việc chạy bài kiểm thử của bạn trên CPU, GPU và bộ tăng tốc nếu bạn viết chúng phù hợp. Chúng tôi có các thử nghiệm tự động chạy trên Linux, macos, windows, có hệ thống có hoặc không có GPU. Bạn chỉ cần chọn một trong các macro được liệt kê ở trên, sau đó sử dụng thẻ để giới hạn nơi chúng được thực thi.

  • thẻ manual sẽ loại trừ việc chạy thử nghiệm của bạn ở bất cứ đâu. Điều này bao gồm việc thực hiện kiểm thử thủ công sử dụng các mẫu như bazel test tensorflow/…

  • no_oss sẽ loại trừ việc chạy thử nghiệm của bạn trong cơ sở hạ tầng thử nghiệm TF OSS chính thức.

  • Thẻ no_mac hoặc no_windows có thể được sử dụng để loại trừ thử nghiệm của bạn khỏi bộ thử nghiệm hệ điều hành có liên quan.

  • Thẻ no_gpu có thể được sử dụng để loại trừ thử nghiệm của bạn chạy trong bộ thử nghiệm GPU.

Xác minh các thử nghiệm chạy trong bộ thử nghiệm dự kiến

TF có khá nhiều bộ thử nghiệm. Đôi khi, chúng có thể gây nhầm lẫn khi thiết lập. Có thể có nhiều vấn đề khác nhau khiến thử nghiệm của bạn bị bỏ qua trong quá trình xây dựng liên tục. Vì vậy, bạn nên xác minh rằng các bài kiểm tra của bạn đang thực hiện như mong đợi. Để làm điều này:

  • Đợi quá trình gửi trước của bạn trên Yêu cầu kéo (PR) chạy đến khi hoàn thành.
  • Cuộn xuống cuối PR của bạn để xem kiểm tra trạng thái.
  • Nhấp vào liên kết “Chi tiết” ở bên phải của bất kỳ séc Kokoro nào.
  • Kiểm tra danh sách “Mục tiêu” để tìm các mục tiêu mới được thêm vào của bạn.

Mỗi lớp/đơn vị phải có tệp kiểm tra đơn vị riêng

Các lớp kiểm tra riêng biệt giúp chúng tôi tách biệt các lỗi và tài nguyên tốt hơn. Chúng dẫn đến các tệp thử nghiệm ngắn hơn và dễ đọc hơn nhiều. Do đó, tất cả các tệp Python của bạn phải có ít nhất một tệp thử nghiệm tương ứng (Đối với mỗi foo.py , cần có foo_test.py ). Đối với các thử nghiệm phức tạp hơn, chẳng hạn như thử nghiệm tích hợp yêu cầu các thiết lập khác nhau, bạn có thể thêm nhiều tệp thử nghiệm hơn.

Tốc độ và thời gian chạy

Sharding nên được sử dụng càng ít càng tốt

Thay vì phân đoạn, vui lòng xem xét:

  • Làm cho bài kiểm tra của bạn nhỏ hơn
  • Nếu điều trên là không thể, hãy chia các bài kiểm tra ra

Phân đoạn giúp giảm độ trễ tổng thể của thử nghiệm, nhưng bạn có thể đạt được điều tương tự bằng cách chia nhỏ thử nghiệm thành các mục tiêu nhỏ hơn. Việc phân tách các thử nghiệm mang lại cho chúng tôi mức độ kiểm soát tốt hơn trên mỗi thử nghiệm, giảm thiểu các lần chạy gửi trước không cần thiết và giảm tổn thất về phạm vi bảo hiểm do một bản dựng làm vô hiệu hóa toàn bộ mục tiêu do một trường hợp thử nghiệm hoạt động sai. Hơn nữa, sharding phát sinh những chi phí ẩn không quá rõ ràng, chẳng hạn như chạy tất cả mã khởi tạo thử nghiệm cho tất cả các phân đoạn. Vấn đề này đã được các nhóm cơ sở hạ tầng báo cáo cho chúng tôi như một nguồn tạo thêm tải.

Các bài kiểm tra nhỏ hơn sẽ tốt hơn

Bài kiểm tra của bạn chạy càng nhanh thì càng có nhiều khả năng mọi người sẽ chạy bài kiểm tra của bạn. Thêm một giây cho thử nghiệm của bạn có thể tích lũy thành hàng giờ để các nhà phát triển và cơ sở hạ tầng của chúng tôi dành thêm thời gian để chạy thử nghiệm của bạn. Cố gắng làm cho các bài kiểm tra của bạn chạy dưới 30 giây (ở chế độ không chọn lựa!) và làm cho chúng nhỏ lại. Chỉ đánh dấu các bài kiểm tra của bạn ở mức trung bình như là phương sách cuối cùng. Cơ sở hạ tầng không chạy bất kỳ bài kiểm tra lớn nào dưới dạng gửi trước hoặc gửi sau! Vì vậy, chỉ viết một bài kiểm thử lớn nếu bạn định sắp xếp nơi nó sẽ chạy. Một số mẹo để làm cho bài kiểm tra chạy nhanh hơn:

  • Chạy ít lần lặp lại đào tạo hơn trong bài kiểm tra của bạn
  • Hãy cân nhắc việc sử dụng tính năng chèn phần phụ thuộc để thay thế các phần phụ thuộc nặng nề của hệ thống đang được thử nghiệm bằng các phần giả mạo đơn giản.
  • Cân nhắc sử dụng dữ liệu đầu vào nhỏ hơn trong các bài kiểm tra đơn vị
  • Nếu không có gì khác hoạt động, hãy thử chia nhỏ tệp thử nghiệm của bạn.

Thời gian thử nghiệm nên nhắm tới một nửa thời gian chờ của kích thước thử nghiệm để tránh hiện tượng bong tróc

Với mục tiêu kiểm tra bazel , các bài kiểm tra nhỏ có thời gian chờ là 1 phút. Thời gian chờ kiểm tra trung bình là 5 phút. Các thử nghiệm lớn không được thực hiện bởi cơ sở hạ tầng thử nghiệm TensorFlow. Tuy nhiên, nhiều bài kiểm tra không xác định được lượng thời gian thực hiện. Vì nhiều lý do khác nhau, bài kiểm tra của bạn thỉnh thoảng có thể mất nhiều thời gian hơn. Và nếu bạn đánh dấu một bài kiểm tra chạy trung bình trong 50 giây là nhỏ, thì bài kiểm tra của bạn sẽ bị hỏng nếu nó lên lịch trên máy có CPU cũ. Vì vậy, hãy nhắm tới thời gian chạy trung bình là 30 giây cho các bài kiểm tra nhỏ. Đặt mục tiêu thời gian chạy trung bình là 2 phút 30 giây cho các bài kiểm tra trung bình.

Giảm số lượng mẫu và tăng dung sai cho việc đào tạo

Các bài kiểm tra chạy chậm ngăn cản những người đóng góp. Chạy đào tạo trong các bài kiểm tra có thể rất chậm. Ưu tiên dung sai cao hơn để có thể sử dụng ít mẫu hơn trong các thử nghiệm của bạn nhằm giữ cho thử nghiệm của bạn đủ nhanh (tối đa 2,5 phút).

Loại bỏ tính không xác định và vảy

Viết các bài kiểm tra xác định

Các bài kiểm tra đơn vị phải luôn mang tính quyết định. Tất cả các bài kiểm tra chạy trên TAP và guitar phải chạy theo cùng một cách mỗi lần, nếu không có thay đổi mã nào ảnh hưởng đến chúng. Để đảm bảo điều này, dưới đây là một số điểm cần xem xét.

Luôn gieo mầm bất kỳ nguồn ngẫu nhiên nào

Bất kỳ trình tạo số ngẫu nhiên nào hoặc bất kỳ nguồn ngẫu nhiên nào khác đều có thể gây ra hiện tượng không ổn định. Vì vậy, mỗi thứ này phải được gieo hạt. Ngoài việc làm cho các bài kiểm tra ít sai sót hơn, điều này còn giúp tất cả các bài kiểm tra có thể lặp lại được. Các cách khác nhau để đặt một số hạt giống mà bạn có thể cần đặt trong các bài kiểm tra TF là:

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

Tránh sử dụng sleep trong các bài kiểm tra đa luồng

Sử dụng chức năng sleep trong các bài kiểm tra có thể là nguyên nhân chính gây ra tình trạng không ổn định. Đặc biệt khi sử dụng nhiều luồng, việc sử dụng chế độ ngủ để chờ luồng khác sẽ không bao giờ mang tính quyết định. Điều này là do hệ thống không thể đảm bảo bất kỳ thứ tự thực hiện nào của các luồng hoặc quy trình khác nhau. Do đó, hãy ưu tiên các cấu trúc đồng bộ hóa xác định như mutexes.

Kiểm tra xem bài kiểm tra có bị rung không

Mảnh vỡ khiến các nhà xây dựng và nhà phát triển mất nhiều giờ. Chúng rất khó phát hiện và khó gỡ lỗi. Mặc dù có các hệ thống tự động phát hiện sự không ổn định nhưng chúng cần phải tích lũy hàng trăm lần chạy thử trước khi có thể từ chối chính xác các thử nghiệm. Ngay cả khi họ phát hiện, họ vẫn từ chối đưa các bài kiểm tra của bạn vào danh sách và phạm vi kiểm tra sẽ bị mất. Vì vậy, người viết bài kiểm tra nên kiểm tra xem bài kiểm tra của họ có bị lỗi khi viết bài kiểm tra hay không. Điều này có thể được thực hiện dễ dàng bằng cách chạy thử nghiệm của bạn với cờ: --runs_per_test=1000

Sử dụng TensorFlowTestCase

TensorFlowTestCase thực hiện các biện pháp phòng ngừa cần thiết như gieo mầm tất cả các trình tạo số ngẫu nhiên được sử dụng để giảm độ bong tróc nhiều nhất có thể. Khi chúng tôi phát hiện và khắc phục nhiều nguồn gây lỗi hơn, tất cả những nguồn này sẽ được thêm vào TensorFlowTestCase. Vì vậy, bạn nên sử dụng TensorFlowTestCase khi viết bài kiểm tra cho tensorflow. TensorFlowTestCase được định nghĩa ở đây: tensorflow/python/framework/test_util.py

Viết các bài kiểm tra kín

Các thử nghiệm kín không cần bất kỳ nguồn lực bên ngoài nào. Họ có đầy đủ mọi thứ họ cần và họ chỉ bắt đầu bất kỳ dịch vụ giả mạo nào mà họ có thể cần. Bất kỳ dịch vụ nào ngoài các bài kiểm tra của bạn đều là nguồn cung cấp tính không xác định. Ngay cả khi các dịch vụ khác có sẵn 99%, mạng vẫn có thể bị hỏng, phản hồi rpc có thể bị chậm và bạn có thể nhận được thông báo lỗi không thể giải thích được. Các dịch vụ bên ngoài có thể bao gồm nhưng không giới hạn ở GCS, S3 hoặc bất kỳ trang web nào.