Ví dụ về tối ưu hóa bị ràng buộc TensorFlow sử dụng tập dữ liệu CelebA

Xem trên TensorFlow.org Chạy trong Google Colab Xem trên GitHub Tải xuống sổ ghi chép

Sổ tay này trình bày một cách dễ dàng để tạo và tối ưu hóa các vấn đề bị ràng buộc bằng cách sử dụng thư viện TFCO. Phương pháp này có thể hữu ích trong việc cải thiện mô hình khi chúng ta thấy rằng họ đang không thực hiện tốt như nhau trên lát khác nhau của dữ liệu của chúng tôi, mà chúng tôi có thể xác định bằng chỉ số Công bằng . Nguyên tắc thứ hai trong số các nguyên tắc AI của Google tuyên bố rằng công nghệ của chúng tôi nên tránh tạo ra hoặc củng cố thành kiến ​​không công bằng và chúng tôi tin rằng kỹ thuật này có thể giúp cải thiện tính công bằng của mô hình trong một số tình huống. Đặc biệt, sổ tay này sẽ:

  • Đào tạo một đơn giản, mô hình mạng thần kinh không bị giới hạn để phát hiện nụ cười của một người trong hình ảnh sử dụng tf.keras và CelebFaces quy mô lớn thuộc tính ( CelebA ) tập dữ liệu.
  • Đánh giá hiệu quả hoạt động của mô hình dựa trên thước đo công bằng thường được sử dụng giữa các nhóm tuổi, sử dụng các Chỉ số công bằng.
  • Thiết lập một bài toán tối ưu hóa có giới hạn đơn giản để đạt được hiệu suất công bằng hơn giữa các nhóm tuổi.
  • Đào tạo lại các mô hình hiện nay bị hạn chế và đánh giá hiệu suất một lần nữa, đảm bảo sự công bằng lựa chọn số liệu của chúng tôi đã được cải thiện.

Cập nhật lần cuối: 3/11 tháng 2 năm 2020

Cài đặt

Máy tính xách tay này được tạo ra trong Colaboratory , kết nối với Python 3 Google Compute Engine backend. Nếu bạn muốn lưu trữ sổ ghi chép này trong một môi trường khác, thì bạn sẽ không gặp phải bất kỳ sự cố lớn nào miễn là bạn bao gồm tất cả các gói bắt buộc trong các ô bên dưới.

Lưu ý rằng lần đầu tiên bạn chạy cài đặt pip, bạn có thể được yêu cầu khởi động lại thời gian chạy vì các gói lỗi thời được cài đặt sẵn. Khi bạn làm như vậy, các gói chính xác sẽ được sử dụng.

Pip cài đặt

Lưu ý rằng tùy thuộc vào thời điểm bạn chạy ô bên dưới, bạn có thể nhận được cảnh báo về việc phiên bản mặc định của TensorFlow trong Colab sẽ sớm chuyển sang TensorFlow 2.X. Bạn có thể bỏ qua cảnh báo đó một cách an toàn vì máy tính xách tay này được thiết kế để tương thích với TensorFlow 1.X và 2.X.

Nhập mô-đun

Ngoài ra, chúng tôi thêm một số mục nhập cụ thể cho các Chỉ số Công bằng mà chúng tôi sẽ sử dụng để đánh giá và hình dung hiệu suất của mô hình.

Mặc dù TFCO tương thích với thực thi háo hức và đồ thị, máy tính xách tay này giả định rằng thực thi háo hức được bật theo mặc định như trong TensorFlow 2.x. Để đảm bảo rằng không có gì bị hỏng, thực thi háo hức sẽ được bật trong ô bên dưới.

Bật các phiên bản in và thực thi háo hức

Eager execution enabled by default.
TensorFlow 2.8.0-rc0
TFMA 0.36.0
TFDS 4.4.0
FI 0.36.0

Tập dữ liệu CelebA

CelebA là thuộc tính một khuôn mặt quy mô lớn dữ liệu với hơn 200.000 hình ảnh người nổi tiếng, mỗi với 40 chú thích thuộc tính (chẳng hạn như loại tóc, phụ kiện thời trang, đặc điểm khuôn mặt, vv) và các địa điểm mang tính bước ngoặt 5 (mắt, miệng và vị trí mũi). Để biết thêm chi tiết hãy xem tờ giấy . Với sự cho phép của chủ sở hữu, chúng tôi đã lưu trữ dữ liệu này trên Google Cloud Storage và chủ yếu truy cập nó qua TensorFlow Datasets ( tfds ) .

Trong sổ tay này:

  • Mô hình của chúng tôi sẽ cố gắng để phân loại cho dù chủ đề của hình ảnh được mỉm cười, như được đại diện bởi "Mỉm cười" thuộc tính *.
  • Hình ảnh sẽ được thay đổi kích thước từ 218x178 thành 28x28 để giảm thời gian thực hiện và bộ nhớ khi đào tạo.
  • Hiệu suất của mô hình của chúng tôi sẽ được đánh giá giữa các nhóm tuổi, sử dụng thuộc tính "Trẻ" nhị phân. Chúng tôi sẽ gọi đây là "nhóm tuổi" trong sổ tay này.

* Trong khi có rất ít thông tin về các phương pháp dán nhãn cho dữ liệu này, chúng tôi sẽ giả định rằng "Mỉm cười" thuộc tính được xác định bằng một biểu hiện vật, hoặc thích thú vui trên khuôn mặt của đối tượng. Đối với mục đích của nghiên cứu điển hình này, chúng tôi sẽ coi những nhãn này là sự thật cơ bản.

gcs_base_dir = "gs://celeb_a_dataset/"
celeb_a_builder = tfds.builder("celeb_a", data_dir=gcs_base_dir, version='2.0.0')

celeb_a_builder.download_and_prepare()

num_test_shards_dict = {'0.3.0': 4, '2.0.0': 2} # Used because we download the test dataset separately
version = str(celeb_a_builder.info.version)
print('Celeb_A dataset version: %s' % version)
Celeb_A dataset version: 2.0.0

Kiểm tra các chức năng của trình trợ giúp tập dữ liệu

Cảnh báo

Trước khi tiếp tục, có một số lưu ý cần ghi nhớ khi sử dụng CelebA:

  • Mặc dù về nguyên tắc, sổ ghi chép này có thể sử dụng bất kỳ tập dữ liệu nào về hình ảnh khuôn mặt, CelebA được chọn vì nó chứa các hình ảnh thuộc phạm vi công cộng của các nhân vật của công chúng.
  • Tất cả các chú thích thuộc tính trong CelebA đều được vận hành dưới dạng danh mục nhị phân. Ví dụ: thuộc tính "Trẻ" (được xác định bởi các nhà ghi nhãn tập dữ liệu) được biểu thị là có hoặc không có trong hình ảnh.
  • Các phân loại của CelebA không phản ánh sự đa dạng thực sự của con người về các thuộc tính.
  • Theo mục đích của sổ tay này, đối tượng chứa thuộc tính "Trẻ" được gọi là "nhóm tuổi", trong đó sự hiện diện của thuộc tính "Trẻ" trong hình ảnh được gắn nhãn là thành viên của nhóm tuổi "Trẻ" và không có thuộc tính "Trẻ" được gắn nhãn là thành viên của nhóm tuổi "Không trẻ". Đây là những giả định thực hiện như thông tin này không được đề cập trong bài báo gốc .
  • Do đó, hiệu suất trong các mô hình được đào tạo trong sổ tay này gắn liền với cách các thuộc tính đã được vận hành và được các tác giả của CelebA chú thích.
  • Mô hình này không nên được sử dụng cho mục đích thương mại như rằng sẽ vi phạm thỏa thuận nghiên cứu phi thương mại CelebA của .

Thiết lập chức năng đầu vào

Các ô tiếp theo sẽ giúp sắp xếp hợp lý đường ống đầu vào cũng như trực quan hóa hiệu suất.

Đầu tiên, chúng tôi xác định một số biến liên quan đến dữ liệu và xác định một chức năng tiền xử lý cần thiết.

Xác định các biến

Xác định các chức năng tiền xử lý

Sau đó, chúng tôi xây dựng các hàm dữ liệu mà chúng tôi cần trong phần còn lại của chuyên mục.

# Train data returning either 2 or 3 elements (the third element being the group)
def celeb_a_train_data_wo_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_and_label)
def celeb_a_train_data_w_group(batch_size):
  celeb_a_train_data = celeb_a_builder.as_dataset(split='train').shuffle(1024).repeat().batch(batch_size).map(preprocess_input_dict)
  return celeb_a_train_data.map(get_image_label_and_group)

# Test data for the overall evaluation
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
# Copy test data locally to be able to read it into tfma
copy_test_files_to_local()

Xây dựng một mô hình DNN đơn giản

Bởi vì máy tính xách tay này tập trung vào TFCO, chúng tôi sẽ lắp ráp đơn giản, không bị giới hạn tf.keras.Sequential mô hình.

Chúng tôi có thể cải thiện đáng kể hiệu suất mô hình bằng cách thêm một số độ phức tạp (ví dụ: các lớp được kết nối dày đặc hơn, khám phá các chức năng kích hoạt khác nhau, tăng kích thước hình ảnh), nhưng điều đó có thể làm xao nhãng mục tiêu chứng minh việc áp dụng thư viện TFCO dễ dàng như thế nào. khi làm việc với Keras. Vì lý do đó, mô hình sẽ được giữ đơn giản - nhưng cảm thấy được khuyến khích khám phá không gian này.

def create_model():
  # For this notebook, accuracy will be used to evaluate performance.
  METRICS = [
    tf.keras.metrics.BinaryAccuracy(name='accuracy')
  ]

  # The model consists of:
  # 1. An input layer that represents the 28x28x3 image flatten.
  # 2. A fully connected layer with 64 units activated by a ReLU function.
  # 3. A single-unit readout layer to output real-scores instead of probabilities.
  model = keras.Sequential([
      keras.layers.Flatten(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), name='image'),
      keras.layers.Dense(64, activation='relu'),
      keras.layers.Dense(1, activation=None)
  ])

  # TFCO by default uses hinge loss — and that will also be used in the model.
  model.compile(
      optimizer=tf.keras.optimizers.Adam(0.001),
      loss='hinge',
      metrics=METRICS)
  return model

Chúng tôi cũng xác định một chức năng đặt hạt giống để đảm bảo kết quả có thể tái tạo. Lưu ý rằng chuyên mục này có nghĩa là một công cụ giáo dục và không có tính ổn định của một quy trình sản xuất được tinh chỉnh. Chạy mà không đặt hạt giống có thể dẫn đến các kết quả khác nhau.

def set_seeds():
  np.random.seed(121212)
  tf.compat.v1.set_random_seed(212121)

Chức năng của Người trợ giúp Chỉ báo Công bằng

Trước khi đào tạo mô hình của mình, chúng tôi xác định một số chức năng trợ giúp sẽ cho phép chúng tôi đánh giá hiệu suất của mô hình thông qua Chỉ số Công bằng.

Đầu tiên, chúng tôi tạo một hàm trợ giúp để lưu mô hình của chúng tôi sau khi chúng tôi đào tạo nó.

def save_model(model, subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_models')
  model_location = os.path.join(base_dir, subdir)
  model.save(model_location, save_format='tf')
  return model_location

Tiếp theo, chúng tôi xác định các hàm được sử dụng để xử lý trước dữ liệu nhằm chuyển dữ liệu đến TFMA một cách chính xác.

Các chức năng tiền xử lý dữ liệu cho

Cuối cùng, chúng tôi xác định một hàm đánh giá kết quả trong TFMA.

def get_eval_results(model_location, eval_subdir):
  base_dir = tempfile.mkdtemp(prefix='saved_eval_results')
  tfma_eval_result_path = os.path.join(base_dir, eval_subdir)

  eval_config_pbtxt = """
        model_specs {
          label_key: "%s"
        }
        metrics_specs {
          metrics {
            class_name: "FairnessIndicators"
            config: '{ "thresholds": [0.22, 0.5, 0.75] }'
          }
          metrics {
            class_name: "ExampleCount"
          }
        }
        slicing_specs {}
        slicing_specs { feature_keys: "%s" }
        options {
          compute_confidence_intervals { value: False }
          disabled_outputs{values: "analysis"}
        }
      """ % (LABEL_KEY, GROUP_KEY)

  eval_config = text_format.Parse(eval_config_pbtxt, tfma.EvalConfig())

  eval_shared_model = tfma.default_eval_shared_model(
        eval_saved_model_path=model_location, tags=[tf.saved_model.SERVING])

  schema_pbtxt = """
        tensor_representation_group {
          key: ""
          value {
            tensor_representation {
              key: "%s"
              value {
                dense_tensor {
                  column_name: "%s"
                  shape {
                    dim { size: 28 }
                    dim { size: 28 }
                    dim { size: 3 }
                  }
                }
              }
            }
          }
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: FLOAT
        }
        feature {
          name: "%s"
          type: BYTES
        }
        """ % (IMAGE_KEY, IMAGE_KEY, IMAGE_KEY, LABEL_KEY, GROUP_KEY)
  schema = text_format.Parse(schema_pbtxt, schema_pb2.Schema())
  coder = tf_example_record.TFExampleBeamRecord(
      physical_format='inmem', schema=schema,
      raw_record_column_name=tfma.ARROW_INPUT_COLUMN)
  tensor_adapter_config = tensor_adapter.TensorAdapterConfig(
    arrow_schema=coder.ArrowSchema(),
    tensor_representations=coder.TensorRepresentations())
  # Run the fairness evaluation.
  with beam.Pipeline() as pipeline:
    _ = (
          tfds_as_pcollection(pipeline, 'celeb_a', 'test')
          | 'ExamplesToRecordBatch' >> coder.BeamSource()
          | 'ExtractEvaluateAndWriteResults' >>
          tfma.ExtractEvaluateAndWriteResults(
              eval_config=eval_config,
              eval_shared_model=eval_shared_model,
              output_path=tfma_eval_result_path,
              tensor_adapter_config=tensor_adapter_config)
    )
  return tfma.load_eval_result(output_path=tfma_eval_result_path)

Huấn luyện & Đánh giá Mô hình Không bị ràng buộc

Với mô hình hiện đã được xác định và đường dẫn đầu vào đã có sẵn, chúng tôi hiện đã sẵn sàng đào tạo mô hình của mình. Để cắt giảm lượng thời gian thực thi và bộ nhớ, chúng tôi sẽ đào tạo mô hình bằng cách cắt dữ liệu thành các lô nhỏ chỉ với một vài lần lặp lại.

Lưu ý rằng máy tính xách tay chạy này trong TensorFlow <2.0.0 có thể dẫn đến một cảnh báo deprecation cho np.where . An toàn bỏ qua cảnh báo này như TensorFlow địa chỉ này trong 2.X bằng cách sử dụng tf.where ở vị trí của np.where .

BATCH_SIZE = 32

# Set seeds to get reproducible results
set_seeds()

model_unconstrained = create_model()
model_unconstrained.fit(celeb_a_train_data_wo_group(BATCH_SIZE), epochs=5, steps_per_epoch=1000)
Epoch 1/5
1000/1000 [==============================] - 12s 6ms/step - loss: 0.5038 - accuracy: 0.7733
Epoch 2/5
1000/1000 [==============================] - 7s 7ms/step - loss: 0.3800 - accuracy: 0.8301
Epoch 3/5
1000/1000 [==============================] - 6s 6ms/step - loss: 0.3598 - accuracy: 0.8427
Epoch 4/5
1000/1000 [==============================] - 25s 25ms/step - loss: 0.3435 - accuracy: 0.8474
Epoch 5/5
1000/1000 [==============================] - 5s 5ms/step - loss: 0.3402 - accuracy: 0.8479
<keras.callbacks.History at 0x7f0f5c476350>

Đánh giá mô hình trên dữ liệu thử nghiệm sẽ dẫn đến điểm chính xác cuối cùng chỉ hơn 85%. Không tồi đối với một mô hình đơn giản không có tinh chỉnh.

print('Overall Results, Unconstrained')
celeb_a_test_data = celeb_a_builder.as_dataset(split='test').batch(1).map(preprocess_input_dict).map(get_image_label_and_group)
results = model_unconstrained.evaluate(celeb_a_test_data)
Overall Results, Unconstrained
19962/19962 [==============================] - 50s 2ms/step - loss: 0.2125 - accuracy: 0.8636

Tuy nhiên, hiệu suất được đánh giá giữa các nhóm tuổi có thể bộc lộ một số thiếu sót.

Để khám phá thêm điều này, chúng tôi đánh giá mô hình bằng các Chỉ số Công bằng (thông qua TFMA). Đặc biệt, chúng tôi quan tâm đến việc xem liệu có khoảng cách đáng kể về hiệu suất giữa danh mục "Trẻ" và "Không trẻ" khi được đánh giá về tỷ lệ dương tính giả hay không.

Lỗi tích cực sai xảy ra khi mô hình dự đoán sai lớp tích cực. Trong bối cảnh này, một kết quả dương tính giả xảy ra khi sự thật cơ bản là hình ảnh của một người nổi tiếng 'Không cười' và mô hình dự đoán là 'Mỉm cười'. Nói cách khác, tỷ lệ dương tính giả, được sử dụng trong hình ảnh minh họa ở trên, là thước đo độ chính xác của xét nghiệm. Mặc dù đây là một lỗi tương đối dễ mắc phải trong bối cảnh này, nhưng lỗi xác định sai đôi khi có thể gây ra nhiều hành vi có vấn đề hơn. Ví dụ: lỗi xác thực sai trong bộ phân loại thư rác có thể khiến người dùng bỏ lỡ một email quan trọng.

model_location = save_model(model_unconstrained, 'model_export_unconstrained')
eval_results_unconstrained = get_eval_results(model_location, 'eval_results_unconstrained')
2022-01-07 18:46:05.881112: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelswhxcqdry/model_export_unconstrained/assets
WARNING:apache_beam.runners.interactive.interactive_environment:Dependencies required for Interactive Beam PCollection visualization are not available, please use: `pip install apache-beam[interactive]` to install necessary dependencies to enable all data visualization features.
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
WARNING:apache_beam.io.tfrecordio:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:107: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

Như đã đề cập ở trên, chúng tôi đang tập trung vào tỷ lệ dương tính giả. Phiên bản hiện tại của Chỉ báo Công bằng (0.1.2) chọn tỷ lệ âm sai theo mặc định. Sau khi chạy dòng bên dưới, bỏ chọn false_negative_rate và chọn false_positive_rate để xem chỉ số mà chúng tôi quan tâm.

tfma.addons.fairness.view.widget_view.render_fairness_indicator(eval_results_unconstrained)
FairnessIndicatorViewer(slicingMetrics=[{'sliceValue': 'Young', 'slice': 'Young:Young', 'metrics': {'example_c…

Như kết quả cho thấy ở trên, chúng tôi thấy một khoảng cách không cân xứng giữa "trẻ" và "Not Young" loại.

Đây là nơi TFCO có thể giúp đỡ bằng cách hạn chế tỷ lệ dương tính giả nằm trong một tiêu chí dễ chấp nhận hơn.

Thiết lập mô hình hạn chế

Như tài liệu trong thư viện TFCO của , có một số người giúp đỡ mà sẽ làm cho nó dễ dàng hơn để hạn chế các vấn đề:

  1. tfco.rate_context() - Đây là những gì sẽ được sử dụng trong việc xây dựng một hạn chế đối với từng loại nhóm tuổi.
  2. tfco.RateMinimizationProblem() - Các biểu hiện tỷ lệ để được giảm thiểu ở đây sẽ là đối tượng tỷ lệ dương tính giả với nhóm tuổi. Nói cách khác, hiệu suất bây giờ sẽ được đánh giá dựa trên sự khác biệt giữa tỷ lệ dương tính giả của nhóm tuổi và tỷ lệ của tập dữ liệu tổng thể. Đối với minh họa này, tỷ lệ dương tính giả nhỏ hơn hoặc bằng 5% sẽ được đặt làm giới hạn.
  3. tfco.ProxyLagrangianOptimizerV2() - Đây là helper mà thực sự sẽ giải quyết vấn đề tốc độ hạn chế.

Ô bên dưới sẽ kêu gọi những người trợ giúp này thiết lập đào tạo mô hình với ràng buộc công bằng.

# The batch size is needed to create the input, labels and group tensors.
# These tensors are initialized with all 0's. They will eventually be assigned
# the batch content to them. A large batch size is chosen so that there are
# enough number of "Young" and "Not Young" examples in each batch.
set_seeds()
model_constrained = create_model()
BATCH_SIZE = 32

# Create input tensor.
input_tensor = tf.Variable(
    np.zeros((BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 3), dtype="float32"),
    name="input")

# Create labels and group tensors (assuming both labels and groups are binary).
labels_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="labels")
groups_tensor = tf.Variable(
    np.zeros(BATCH_SIZE, dtype="float32"), name="groups")

# Create a function that returns the applied 'model' to the input tensor
# and generates constrained predictions.
def predictions():
  return model_constrained(input_tensor)

# Create overall context and subsetted context.
# The subsetted context contains subset of examples where group attribute < 1
# (i.e. the subset of "Not Young" celebrity images).
# "groups_tensor < 1" is used instead of "groups_tensor == 0" as the former
# would be a comparison on the tensor value, while the latter would be a
# comparison on the Tensor object.
context = tfco.rate_context(predictions, labels=lambda:labels_tensor)
context_subset = context.subset(lambda:groups_tensor < 1)

# Setup list of constraints.
# In this notebook, the constraint will just be: FPR to less or equal to 5%.
constraints = [tfco.false_positive_rate(context_subset) <= 0.05]

# Setup rate minimization problem: minimize overall error rate s.t. constraints.
problem = tfco.RateMinimizationProblem(tfco.error_rate(context), constraints)

# Create constrained optimizer and obtain train_op.
# Separate optimizers are specified for the objective and constraints
optimizer = tfco.ProxyLagrangianOptimizerV2(
      optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      constraint_optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
      num_constraints=problem.num_constraints)

# A list of all trainable variables is also needed to use TFCO.
var_list = (model_constrained.trainable_weights + list(problem.trainable_variables) +
            optimizer.trainable_variables())

Mô hình hiện đã được thiết lập và sẵn sàng được đào tạo với giới hạn tỷ lệ dương tính giả giữa các nhóm tuổi.

Bây giờ, vì lặp cuối cùng của mô hình bó buộc có thể không nhất thiết phải là mô hình thực hiện tốt nhất về các hạn chế được xác định, các thư viện TFCO được trang bị tfco.find_best_candidate_index() có thể giúp lựa chọn tốt nhất lặp ra khỏi những người tìm thấy sau mỗi lần kỷ nguyên. Hãy suy nghĩ về tfco.find_best_candidate_index() như một heuristic, nói thêm rằng đứng mỗi người trong số các kết quả dựa trên độ chính xác và công bằng hạn chế (trong trường hợp này, tỷ lệ dương tính giả trên nhóm tuổi) đối với dữ liệu huấn luyện riêng với. Bằng cách đó, nó có thể tìm kiếm sự cân bằng tốt hơn giữa độ chính xác tổng thể và ràng buộc về tính công bằng.

Các ô sau sẽ bắt đầu đào tạo với các ràng buộc đồng thời tìm ra mô hình hoạt động tốt nhất cho mỗi lần lặp.

# Obtain train set batches.

NUM_ITERATIONS = 100  # Number of training iterations.
SKIP_ITERATIONS = 10  # Print training stats once in this many iterations.

# Create temp directory for saving snapshots of models.
temp_directory = tempfile.mktemp()
os.mkdir(temp_directory)

# List of objective and constraints across iterations.
objective_list = []
violations_list = []

# Training iterations.
iteration_count = 0
for (image, label, group) in celeb_a_train_data_w_group(BATCH_SIZE):
  # Assign current batch to input, labels and groups tensors.
  input_tensor.assign(image)
  labels_tensor.assign(label)
  groups_tensor.assign(group)

  # Run gradient update.
  optimizer.minimize(problem, var_list=var_list)

  # Record objective and violations.
  objective = problem.objective()
  violations = problem.constraints()

  sys.stdout.write(
      "\r Iteration %d: Hinge Loss = %.3f, Max. Constraint Violation = %.3f"
      % (iteration_count + 1, objective, max(violations)))

  # Snapshot model once in SKIP_ITERATIONS iterations.
  if iteration_count % SKIP_ITERATIONS == 0:
    objective_list.append(objective)
    violations_list.append(violations)

    # Save snapshot of model weights.
    model_constrained.save_weights(
        temp_directory + "/celeb_a_constrained_" +
        str(iteration_count / SKIP_ITERATIONS) + ".h5")

  iteration_count += 1
  if iteration_count >= NUM_ITERATIONS:
    break

# Choose best model from recorded iterates and load that model.
best_index = tfco.find_best_candidate_index(
    np.array(objective_list), np.array(violations_list))

model_constrained.load_weights(
    temp_directory + "/celeb_a_constrained_" + str(best_index) + ".0.h5")

# Remove temp directory.
os.system("rm -r " + temp_directory)
Iteration 100: Hinge Loss = 0.614, Max. Constraint Violation = 0.268
0

Sau khi áp dụng các ràng buộc, chúng tôi đánh giá kết quả một lần nữa bằng cách sử dụng Các Chỉ số Công bằng.

model_location = save_model(model_constrained, 'model_export_constrained')
eval_result_constrained = get_eval_results(model_location, 'eval_results_constrained')
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
INFO:tensorflow:Assets written to: /tmp/saved_modelsbztxt9fy/model_export_constrained/assets
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.

Giống như lần trước, chúng tôi sử dụng Chỉ báo công bằng, bỏ chọn false_negative_rate và chọn false_positive_rate để xem chỉ số mà chúng tôi quan tâm.

Lưu ý rằng để so sánh công bằng giữa hai phiên bản của mô hình của chúng tôi, điều quan trọng là sử dụng các ngưỡng đặt tỷ lệ dương tính giả tổng thể gần bằng nhau. Điều này đảm bảo rằng chúng ta đang xem xét sự thay đổi thực tế chứ không phải chỉ là sự thay đổi trong mô hình tương đương với việc chỉ di chuyển ranh giới ngưỡng. Trong trường hợp của chúng tôi, việc so sánh mô hình không bị giới hạn ở mức 0,5 và mô hình bị hạn chế ở mức 0,22 cung cấp một so sánh công bằng cho các mô hình.

eval_results_dict = {
    'constrained': eval_result_constrained,
    'unconstrained': eval_results_unconstrained,
}
tfma.addons.fairness.view.widget_view.render_fairness_indicator(multi_eval_results=eval_results_dict)
FairnessIndicatorViewer(evalName='constrained', evalNameCompare='unconstrained', slicingMetrics=[{'sliceValue'…

Với khả năng của TFCO trong việc thể hiện một yêu cầu phức tạp hơn như một hạn chế về tỷ lệ, chúng tôi đã giúp mô hình này đạt được một kết quả mong muốn hơn mà không ảnh hưởng nhiều đến kết quả hoạt động chung. Tất nhiên, vẫn còn chỗ để cải thiện, nhưng ít nhất TFCO đã có thể tìm ra một mô hình gần thỏa mãn các hạn chế và giảm sự chênh lệch giữa các nhóm càng nhiều càng tốt.