Lưu ngày! Google I / O hoạt động trở lại từ ngày 18 đến 20 tháng 5 Đăng ký ngay
Trang này được dịch bởi Cloud Translation API.
Switch to English

Các ràng buộc về hình dạng với Tensorflow Lattice

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

Tổng quat

Hướng dẫn này là tổng quan về các ràng buộc và bộ điều chỉnh được cung cấp bởi thư viện TensorFlow Lattice (TFL). Ở đây chúng tôi sử dụng công cụ ước tính đóng hộp TFL trên tập dữ liệu tổng hợp, nhưng lưu ý rằng mọi thứ trong hướng dẫn này cũng có thể được thực hiện với các mô hình được xây dựng từ các lớp TFL Keras.

Trước khi tiếp tục, hãy đảm bảo rằng thời gian chạy của bạn đã cài đặt tất cả các gói bắt buộc (như được nhập trong các ô mã bên dưới).

Thiết lập

Cài đặt gói TF Lattice:

pip install -q tensorflow-lattice

Nhập các gói bắt buộc:

import tensorflow as tf

from IPython.core.pylabtools import figsize
import itertools
import logging
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import sys
import tensorflow_lattice as tfl
logging.disable(sys.maxsize)

Các giá trị mặc định được sử dụng trong hướng dẫn này:

NUM_EPOCHS = 1000
BATCH_SIZE = 64
LEARNING_RATE=0.01

Tập dữ liệu đào tạo để xếp hạng nhà hàng

Hãy tưởng tượng một tình huống đơn giản trong đó chúng ta muốn xác định xem liệu người dùng có nhấp vào kết quả tìm kiếm nhà hàng hay không. Nhiệm vụ là dự đoán tỷ lệ nhấp (CTR) cho các tính năng đầu vào:

  • Xếp hạng trung bình ( avg_rating ): một tính năng số với các giá trị trong phạm vi [1,5].
  • Số lượng đánh giá ( num_reviews ): một tính năng số với các giá trị được giới hạn ở 200, chúng tôi sử dụng làm thước đo mức độ xu hướng.
  • Xếp hạng đô la ( dollar_rating ): tính năng phân loại với các giá trị chuỗi trong tập hợp {"D", "DD", "DDD", "DDDD"}.

Ở đây, chúng tôi tạo một tập dữ liệu tổng hợp trong đó CTR thực sự được cung cấp bởi công thức:

$$ CTR = 1 / (1 + exp\{\mbox{b(dollar_rating)}-\mbox{avg_rating}\times log(\mbox{num_reviews}) /4 \}) $$

trong đó $ b (\ cdot) $ chuyển mỗi dollar_rating thành một giá trị cơ bản:

$$ \mbox{D}\to 3,\ \mbox{DD}\to 2,\ \mbox{DDD}\to 4,\ \mbox{DDDD}\to 4.5. $$

Công thức này phản ánh các mẫu người dùng điển hình. Ví dụ: khi mọi thứ khác đã được sửa, người dùng thích nhà hàng có xếp hạng sao cao hơn và nhà hàng "\ $ \ $" sẽ nhận được nhiều nhấp chuột hơn "\ $", tiếp theo là "\ $ \ $ \ $" và "\ $ \ $ \ $ \ $ ".

def click_through_rate(avg_ratings, num_reviews, dollar_ratings):
  dollar_rating_baseline = {"D": 3, "DD": 2, "DDD": 4, "DDDD": 4.5}
  return 1 / (1 + np.exp(
      np.array([dollar_rating_baseline[d] for d in dollar_ratings]) -
      avg_ratings * np.log1p(num_reviews) / 4))

Chúng ta hãy xem các biểu đồ đường bao của hàm CTR này.

def color_bar():
  bar = matplotlib.cm.ScalarMappable(
      norm=matplotlib.colors.Normalize(0, 1, True),
      cmap="viridis",
  )
  bar.set_array([0, 1])
  return bar


def plot_fns(fns, split_by_dollar=False, res=25):
  """Generates contour plots for a list of (name, fn) functions."""
  num_reviews, avg_ratings = np.meshgrid(
      np.linspace(0, 200, num=res),
      np.linspace(1, 5, num=res),
  )
  if split_by_dollar:
    dollar_rating_splits = ["D", "DD", "DDD", "DDDD"]
  else:
    dollar_rating_splits = [None]
  if len(fns) == 1:
    fig, axes = plt.subplots(2, 2, sharey=True, tight_layout=False)
  else:
    fig, axes = plt.subplots(
        len(dollar_rating_splits), len(fns), sharey=True, tight_layout=False)
  axes = axes.flatten()
  axes_index = 0
  for dollar_rating_split in dollar_rating_splits:
    for title, fn in fns:
      if dollar_rating_split is not None:
        dollar_ratings = np.repeat(dollar_rating_split, res**2)
        values = fn(avg_ratings.flatten(), num_reviews.flatten(),
                    dollar_ratings)
        title = "{}: dollar_rating={}".format(title, dollar_rating_split)
      else:
        values = fn(avg_ratings.flatten(), num_reviews.flatten())
      subplot = axes[axes_index]
      axes_index += 1
      subplot.contourf(
          avg_ratings,
          num_reviews,
          np.reshape(values, (res, res)),
          vmin=0,
          vmax=1)
      subplot.title.set_text(title)
      subplot.set(xlabel="Average Rating")
      subplot.set(ylabel="Number of Reviews")
      subplot.set(xlim=(1, 5))

  _ = fig.colorbar(color_bar(), cax=fig.add_axes([0.95, 0.2, 0.01, 0.6]))


figsize(11, 11)
plot_fns([("CTR", click_through_rate)], split_by_dollar=True)

png

Chuẩn bị dữ liệu

Bây giờ chúng ta cần tạo bộ dữ liệu tổng hợp của mình. Chúng tôi bắt đầu bằng cách tạo một tập dữ liệu mô phỏng về các nhà hàng và các tính năng của chúng.

def sample_restaurants(n):
  avg_ratings = np.random.uniform(1.0, 5.0, n)
  num_reviews = np.round(np.exp(np.random.uniform(0.0, np.log(200), n)))
  dollar_ratings = np.random.choice(["D", "DD", "DDD", "DDDD"], n)
  ctr_labels = click_through_rate(avg_ratings, num_reviews, dollar_ratings)
  return avg_ratings, num_reviews, dollar_ratings, ctr_labels


np.random.seed(42)
avg_ratings, num_reviews, dollar_ratings, ctr_labels = sample_restaurants(2000)

figsize(5, 5)
fig, axs = plt.subplots(1, 1, sharey=False, tight_layout=False)
for rating, marker in [("D", "o"), ("DD", "^"), ("DDD", "+"), ("DDDD", "x")]:
  plt.scatter(
      x=avg_ratings[np.where(dollar_ratings == rating)],
      y=num_reviews[np.where(dollar_ratings == rating)],
      c=ctr_labels[np.where(dollar_ratings == rating)],
      vmin=0,
      vmax=1,
      marker=marker,
      label=rating)
plt.xlabel("Average Rating")
plt.ylabel("Number of Reviews")
plt.legend()
plt.xlim((1, 5))
plt.title("Distribution of restaurants")
_ = fig.colorbar(color_bar(), cax=fig.add_axes([0.95, 0.2, 0.01, 0.6]))

png

Hãy tạo tập dữ liệu đào tạo, xác nhận và thử nghiệm. Khi một nhà hàng được xem trong kết quả tìm kiếm, chúng tôi có thể ghi lại mức độ tương tác của người dùng (nhấp chuột hoặc không nhấp chuột) như một điểm mẫu.

Trong thực tế, người dùng thường không xem qua tất cả các kết quả tìm kiếm. Điều này có nghĩa là người dùng có thể sẽ chỉ nhìn thấy các nhà hàng đã được coi là "tốt" theo mô hình xếp hạng hiện tại đang được sử dụng. Kết quả là, các nhà hàng "tốt" thường được ấn tượng hơn và được thể hiện nhiều hơn trong bộ dữ liệu đào tạo. Khi sử dụng nhiều tính năng hơn, tập dữ liệu huấn luyện có thể có khoảng trống lớn trong các phần "xấu" của không gian tính năng.

Khi mô hình được sử dụng để xếp hạng, nó thường được đánh giá trên tất cả các kết quả có liên quan với sự phân bổ đồng đều hơn mà không được thể hiện tốt bởi tập dữ liệu đào tạo. Một mô hình linh hoạt và phức tạp có thể không thành công trong trường hợp này do trang bị quá nhiều các điểm dữ liệu được đại diện quá mức và do đó thiếu tính tổng quát hóa. Chúng tôi xử lý vấn đề này bằng cách áp dụng kiến ​​thức miền để thêm các ràng buộc hình dạng hướng dẫn mô hình đưa ra các dự đoán hợp lý khi nó không thể lấy chúng từ tập dữ liệu huấn luyện.

Trong ví dụ này, tập dữ liệu đào tạo chủ yếu bao gồm các tương tác của người dùng với các nhà hàng tốt và nổi tiếng. Tập dữ liệu thử nghiệm có một phân phối đồng nhất để mô phỏng cài đặt đánh giá được thảo luận ở trên. Lưu ý rằng tập dữ liệu thử nghiệm như vậy sẽ không khả dụng trong cài đặt vấn đề thực sự.

def sample_dataset(n, testing_set):
  (avg_ratings, num_reviews, dollar_ratings, ctr_labels) = sample_restaurants(n)
  if testing_set:
    # Testing has a more uniform distribution over all restaurants.
    num_views = np.random.poisson(lam=3, size=n)
  else:
    # Training/validation datasets have more views on popular restaurants.
    num_views = np.random.poisson(lam=ctr_labels * num_reviews / 50.0, size=n)

  return pd.DataFrame({
      "avg_rating": np.repeat(avg_ratings, num_views),
      "num_reviews": np.repeat(num_reviews, num_views),
      "dollar_rating": np.repeat(dollar_ratings, num_views),
      "clicked": np.random.binomial(n=1, p=np.repeat(ctr_labels, num_views))
  })


# Generate datasets.
np.random.seed(42)
data_train = sample_dataset(500, testing_set=False)
data_val = sample_dataset(500, testing_set=False)
data_test = sample_dataset(500, testing_set=True)

# Plotting dataset densities.
figsize(12, 5)
fig, axs = plt.subplots(1, 2, sharey=False, tight_layout=False)
for ax, data, title in [(axs[0], data_train, "training"),
                        (axs[1], data_test, "testing")]:
  _, _, _, density = ax.hist2d(
      x=data["avg_rating"],
      y=data["num_reviews"],
      bins=(np.linspace(1, 5, num=21), np.linspace(0, 200, num=21)),
      density=True,
      cmap="Blues",
  )
  ax.set(xlim=(1, 5))
  ax.set(ylim=(0, 200))
  ax.set(xlabel="Average Rating")
  ax.set(ylabel="Number of Reviews")
  ax.title.set_text("Density of {} examples".format(title))
  _ = fig.colorbar(density, ax=ax)

png

Định nghĩa input_fns được sử dụng để đào tạo và đánh giá:

train_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=data_train,
    y=data_train["clicked"],
    batch_size=BATCH_SIZE,
    num_epochs=NUM_EPOCHS,
    shuffle=False,
)

# feature_analysis_input_fn is used for TF Lattice estimators.
feature_analysis_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=data_train,
    y=data_train["clicked"],
    batch_size=BATCH_SIZE,
    num_epochs=1,
    shuffle=False,
)

val_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=data_val,
    y=data_val["clicked"],
    batch_size=BATCH_SIZE,
    num_epochs=1,
    shuffle=False,
)

test_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(
    x=data_test,
    y=data_test["clicked"],
    batch_size=BATCH_SIZE,
    num_epochs=1,
    shuffle=False,
)

Phù hợp với cây tăng cường Gradient

Hãy bắt đầu chỉ với hai tính năng: avg_ratingnum_reviews .

Chúng tôi tạo ra một số hàm hỗ trợ để vẽ và tính toán các chỉ số xác nhận và kiểm tra.

def analyze_two_d_estimator(estimator, name):
  # Extract validation metrics.
  metric = estimator.evaluate(input_fn=val_input_fn)
  print("Validation AUC: {}".format(metric["auc"]))
  metric = estimator.evaluate(input_fn=test_input_fn)
  print("Testing AUC: {}".format(metric["auc"]))

  def two_d_pred(avg_ratings, num_reviews):
    results = estimator.predict(
        tf.compat.v1.estimator.inputs.pandas_input_fn(
            x=pd.DataFrame({
                "avg_rating": avg_ratings,
                "num_reviews": num_reviews,
            }),
            shuffle=False,
        ))
    return [x["logistic"][0] for x in results]

  def two_d_click_through_rate(avg_ratings, num_reviews):
    return np.mean([
        click_through_rate(avg_ratings, num_reviews,
                           np.repeat(d, len(avg_ratings)))
        for d in ["D", "DD", "DDD", "DDDD"]
    ],
                   axis=0)

  figsize(11, 5)
  plot_fns([("{} Estimated CTR".format(name), two_d_pred),
            ("CTR", two_d_click_through_rate)],
           split_by_dollar=False)

Chúng tôi có thể phù hợp với cây quyết định được tăng cường độ dốc TensorFlow trên tập dữ liệu:

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
gbt_estimator = tf.estimator.BoostedTreesClassifier(
    feature_columns=feature_columns,
    # Hyper-params optimized on validation set.
    n_batches_per_layer=1,
    max_depth=2,
    n_trees=50,
    learning_rate=0.05,
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
gbt_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(gbt_estimator, "GBT")
Validation AUC: 0.6333084106445312
Testing AUC: 0.774649977684021

png

Mặc dù mô hình đã nắm bắt được hình dạng chung của CTR thực và có các chỉ số xác thực phù hợp, nhưng nó có hành vi phản trực giác ở một số phần của không gian đầu vào: CTR ước tính giảm khi xếp hạng trung bình hoặc số lượng đánh giá tăng lên. Điều này là do thiếu các điểm mẫu ở các khu vực chưa được bộ dữ liệu đào tạo bao quát. Mô hình chỉ đơn giản là không có cách nào để suy ra hành vi chính xác chỉ từ dữ liệu.

Để giải quyết vấn đề này, chúng tôi thực thi ràng buộc hình dạng rằng mô hình phải xuất ra các giá trị tăng một cách đơn điệu đối với cả xếp hạng trung bình và số lượng đánh giá. Sau đó chúng ta sẽ xem cách thực hiện điều này trong TFL.

Phù hợp với một DNN

Chúng ta có thể lặp lại các bước tương tự với bộ phân loại DNN. Chúng ta có thể quan sát một mô hình tương tự: không có đủ điểm mẫu với số lượng đánh giá nhỏ dẫn đến ngoại suy vô nghĩa. Lưu ý rằng mặc dù chỉ số xác thực tốt hơn giải pháp dạng cây, nhưng chỉ số thử nghiệm lại kém hơn nhiều.

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
dnn_estimator = tf.estimator.DNNClassifier(
    feature_columns=feature_columns,
    # Hyper-params optimized on validation set.
    hidden_units=[16, 8, 8],
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
dnn_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(dnn_estimator, "DNN")
Validation AUC: 0.6696228981018066
Testing AUC: 0.750156044960022

png

Các ràng buộc về hình dạng

TensorFlow Lattice (TFL) tập trung vào việc thực thi các ràng buộc về hình dạng để bảo vệ hành vi của mô hình ngoài dữ liệu huấn luyện. Các ràng buộc hình dạng này được áp dụng cho các lớp TFL Keras. Chi tiết của chúng có thể được tìm thấy trong bài báo JMLR của chúng tôi .

Trong hướng dẫn này, chúng tôi sử dụng công cụ ước lượng đóng hộp TF để bao gồm các ràng buộc hình dạng khác nhau, nhưng lưu ý rằng tất cả các bước này có thể được thực hiện với các mô hình được tạo từ các lớp TFL Keras.

Như với bất kỳ công cụ ước lượng TensorFlow nào khác, công cụ ước tính đóng hộp TFL sử dụng các cột tính năng để xác định định dạng đầu vào và sử dụng input_fn huấn luyện để chuyển vào dữ liệu. Sử dụng công cụ ước tính đóng hộp TFL cũng yêu cầu:

  • một cấu hình mô hình : xác định kiến ​​trúc mô hình và các ràng buộc hình dạng cho mỗi tính năng và các bộ điều chỉnh.
  • phân tích tính năng input_fn : một TF input_fn truyền dữ liệu để khởi tạo TFL.

Để có mô tả kỹ lưỡng hơn, vui lòng tham khảo hướng dẫn công cụ ước tính đóng hộp hoặc tài liệu API.

Tính đơn điệu

Trước tiên, chúng tôi giải quyết các mối quan tâm về tính đơn điệu bằng cách thêm các ràng buộc về tính đơn điệu cho cả hai đối tượng địa lý.

Để hướng dẫn TFL thực thi các ràng buộc hình dạng, chúng tôi chỉ định các ràng buộc trong cấu hình tính năng . Đoạn mã sau đây cho thấy cách chúng ta có thể yêu cầu đầu ra tăng đơn điệu đối với cả num_reviewsavg_rating bằng cách đặt monotonicity="increasing" .

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    feature_configs=[
        tfl.configs.FeatureConfig(
            name="num_reviews",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
        ),
        tfl.configs.FeatureConfig(
            name="avg_rating",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
        )
    ])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(tfl_estimator, "TF Lattice")
Validation AUC: 0.6565533876419067
Testing AUC: 0.7784258723258972

png

Sử dụng CalibratedLatticeConfig tạo ra một bộ phân loại đóng hộp trước tiên áp dụng một bộ hiệu chuẩn cho mỗi đầu vào (một hàm tuyến tính thông minh cho các đối tượng số), tiếp theo là một lớp mạng để kết hợp phi tuyến tính các đối tượng đã hiệu chuẩn. Chúng ta có thể sử dụng tfl.visualization để hình dung mô hình. Đặc biệt, biểu đồ sau đây cho thấy hai mẫu chuẩn được đào tạo có trong bộ phân loại đóng hộp.

def save_and_visualize_lattice(tfl_estimator):
  saved_model_path = tfl_estimator.export_saved_model(
      "/tmp/TensorFlow_Lattice_101/",
      tf.estimator.export.build_parsing_serving_input_receiver_fn(
          feature_spec=tf.feature_column.make_parse_example_spec(
              feature_columns)))
  model_graph = tfl.estimators.get_model_graph(saved_model_path)
  figsize(8, 8)
  tfl.visualization.draw_model_graph(model_graph)
  return model_graph

_ = save_and_visualize_lattice(tfl_estimator)

png

Với các ràng buộc được thêm vào, CTR ước tính sẽ luôn tăng khi xếp hạng trung bình tăng hoặc số lượng đánh giá tăng. Điều này được thực hiện bằng cách đảm bảo rằng các đường chuẩn và mạng tinh thể là đơn ánh.

Lợi nhuận giảm dần

Lợi nhuận giảm dần có nghĩa là lợi nhuận cận biên của việc tăng một giá trị tính năng nhất định sẽ giảm khi chúng ta tăng giá trị. Trong trường hợp của chúng tôi, chúng tôi hy vọng rằng tính năng num_reviews tuân theo mẫu này, vì vậy chúng tôi có thể định cấu hình trình hiệu chuẩn của nó cho phù hợp. Lưu ý rằng chúng ta có thể phân tích lợi tức giảm dần thành hai điều kiện đủ:

  • trình hiệu chuẩn đang tăng một cách đơn điệu, và
  • bộ hiệu chuẩn bị lõm.
feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    feature_configs=[
        tfl.configs.FeatureConfig(
            name="num_reviews",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_convexity="concave",
            pwl_calibration_num_keypoints=20,
        ),
        tfl.configs.FeatureConfig(
            name="avg_rating",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
        )
    ])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(tfl_estimator, "TF Lattice")
_ = save_and_visualize_lattice(tfl_estimator)
Validation AUC: 0.6409633755683899
Testing AUC: 0.7891247272491455

png

png

Lưu ý cách cải thiện chỉ số thử nghiệm bằng cách thêm giới hạn ngắn gọn. Cốt truyện dự đoán cũng giống với sự thật trên mặt đất hơn.

Ràng buộc hình dạng 2D: Tin cậy

Xếp hạng 5 sao cho một nhà hàng chỉ có một hoặc hai đánh giá có thể là một xếp hạng không đáng tin cậy (nhà hàng có thể không thực sự tốt), trong khi xếp hạng 4 sao cho một nhà hàng có hàng trăm đánh giá thì đáng tin cậy hơn nhiều (nhà hàng đó có thể tốt trong trường hợp này). Chúng ta có thể thấy rằng số lượng đánh giá về một nhà hàng ảnh hưởng đến mức độ tin tưởng mà chúng ta đặt vào xếp hạng trung bình của nó.

Chúng ta có thể thực hiện các ràng buộc tin cậy TFL để thông báo cho mô hình rằng giá trị lớn hơn (hoặc nhỏ hơn) của một đối tượng địa lý cho thấy mức độ tin cậy hoặc tin cậy đối với đối tượng địa lý khác nhiều hơn. Này được thực hiện bằng cách thiết lập reflects_trust_in cấu hình trong tính năng config.

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    feature_configs=[
        tfl.configs.FeatureConfig(
            name="num_reviews",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_convexity="concave",
            pwl_calibration_num_keypoints=20,
            # Larger num_reviews indicating more trust in avg_rating.
            reflects_trust_in=[
                tfl.configs.TrustConfig(
                    feature_name="avg_rating", trust_type="edgeworth"),
            ],
        ),
        tfl.configs.FeatureConfig(
            name="avg_rating",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
        )
    ])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(tfl_estimator, "TF Lattice")
model_graph = save_and_visualize_lattice(tfl_estimator)
Validation AUC: 0.6409633755683899
Testing AUC: 0.7891043424606323

png

png

Biểu đồ sau đây trình bày hàm mạng tinh thể được đào tạo. Do hạn chế về độ tin cậy, chúng tôi hy vọng rằng các giá trị lớn hơn của num_reviews hiệu chỉnh sẽ buộc độ dốc cao hơn đối với avg_rating hiệu chỉnh, dẫn đến sự thay đổi đáng kể hơn trong đầu ra của mạng tinh thể.

lat_mesh_n = 12
lat_mesh_x, lat_mesh_y = tfl.test_utils.two_dim_mesh_grid(
    lat_mesh_n**2, 0, 0, 1, 1)
lat_mesh_fn = tfl.test_utils.get_hypercube_interpolation_fn(
    model_graph.output_node.weights.flatten())
lat_mesh_z = [
    lat_mesh_fn([lat_mesh_x.flatten()[i],
                 lat_mesh_y.flatten()[i]]) for i in range(lat_mesh_n**2)
]
trust_plt = tfl.visualization.plot_outputs(
    (lat_mesh_x, lat_mesh_y),
    {"Lattice Lookup": lat_mesh_z},
    figsize=(6, 6),
)
trust_plt.title("Trust")
trust_plt.xlabel("Calibrated avg_rating")
trust_plt.ylabel("Calibrated num_reviews")
trust_plt.show()

png

Máy hiệu chuẩn làm mịn

Bây giờ chúng ta hãy xem xét trình hiệu chỉnh của avg_rating . Mặc dù nó đang tăng một cách đơn điệu, nhưng những thay đổi về độ dốc của nó rất đột ngột và khó có thể giải thích được. Điều đó cho thấy chúng tôi có thể muốn xem xét việc làm mịn bộ hiệu chuẩn này bằng cách sử dụng thiết lập bộ regularizer_configs trong regularizer_configs .

Ở đây chúng tôi áp dụng một bộ điều chỉnh wrinkle để giảm những thay đổi về độ cong. Bạn cũng có thể sử dụng bộ điều chỉnh laplacian để làm phẳng mẫu chuẩn và bộ điều chỉnh hessian để làm cho nó tuyến tính hơn.

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    feature_configs=[
        tfl.configs.FeatureConfig(
            name="num_reviews",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_convexity="concave",
            pwl_calibration_num_keypoints=20,
            regularizer_configs=[
                tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
            ],
            reflects_trust_in=[
                tfl.configs.TrustConfig(
                    feature_name="avg_rating", trust_type="edgeworth"),
            ],
        ),
        tfl.configs.FeatureConfig(
            name="avg_rating",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
            regularizer_configs=[
                tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
            ],
        )
    ])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_two_d_estimator(tfl_estimator, "TF Lattice")
_ = save_and_visualize_lattice(tfl_estimator)
Validation AUC: 0.6465646028518677
Testing AUC: 0.7948372960090637

png

png

Các thiết bị hiệu chuẩn hiện hoạt động trơn tru và CTR ước tính tổng thể phù hợp hơn với sự thật trên mặt đất. Điều này được phản ánh cả trong chỉ số thử nghiệm và trong các đồ thị đường viền.

Tính đơn điệu một phần để hiệu chuẩn phân loại

Cho đến nay, chúng tôi chỉ sử dụng hai trong số các tính năng số trong mô hình. Ở đây chúng tôi sẽ thêm một tính năng thứ ba bằng cách sử dụng một lớp hiệu chuẩn phân loại. Một lần nữa, chúng tôi bắt đầu bằng cách thiết lập các hàm trợ giúp để vẽ biểu đồ và tính toán số liệu.

def analyze_three_d_estimator(estimator, name):
  # Extract validation metrics.
  metric = estimator.evaluate(input_fn=val_input_fn)
  print("Validation AUC: {}".format(metric["auc"]))
  metric = estimator.evaluate(input_fn=test_input_fn)
  print("Testing AUC: {}".format(metric["auc"]))

  def three_d_pred(avg_ratings, num_reviews, dollar_rating):
    results = estimator.predict(
        tf.compat.v1.estimator.inputs.pandas_input_fn(
            x=pd.DataFrame({
                "avg_rating": avg_ratings,
                "num_reviews": num_reviews,
                "dollar_rating": dollar_rating,
            }),
            shuffle=False,
        ))
    return [x["logistic"][0] for x in results]

  figsize(11, 22)
  plot_fns([("{} Estimated CTR".format(name), three_d_pred),
            ("CTR", click_through_rate)],
           split_by_dollar=True)

Để liên quan đến tính năng thứ ba, dollar_rating , chúng ta nên nhớ lại rằng các tính năng phân loại yêu cầu một cách xử lý hơi khác trong TFL, cả dưới dạng một cột tính năng và như một cấu hình tính năng. Ở đây chúng tôi thực thi ràng buộc tính đơn điệu từng phần rằng đầu ra cho nhà hàng "DD" phải lớn hơn nhà hàng "D" khi tất cả các đầu vào khác được cố định. Điều này được thực hiện bằng cách sử dụng cài đặt monotonicity trong cấu hình tính năng.

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
    tf.feature_column.categorical_column_with_vocabulary_list(
        "dollar_rating",
        vocabulary_list=["D", "DD", "DDD", "DDDD"],
        dtype=tf.string,
        default_value=0),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    feature_configs=[
        tfl.configs.FeatureConfig(
            name="num_reviews",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_convexity="concave",
            pwl_calibration_num_keypoints=20,
            regularizer_configs=[
                tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
            ],
            reflects_trust_in=[
                tfl.configs.TrustConfig(
                    feature_name="avg_rating", trust_type="edgeworth"),
            ],
        ),
        tfl.configs.FeatureConfig(
            name="avg_rating",
            lattice_size=2,
            monotonicity="increasing",
            pwl_calibration_num_keypoints=20,
            regularizer_configs=[
                tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
            ],
        ),
        tfl.configs.FeatureConfig(
            name="dollar_rating",
            lattice_size=2,
            pwl_calibration_num_keypoints=4,
            # Here we only specify one monotonicity:
            # `D` resturants has smaller value than `DD` restaurants
            monotonicity=[("D", "DD")],
        ),
    ])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_three_d_estimator(tfl_estimator, "TF Lattice")
_ = save_and_visualize_lattice(tfl_estimator)
Validation AUC: 0.7699775695800781
Testing AUC: 0.8594040274620056

png

png

Bộ hiệu chuẩn phân loại này hiển thị ưu tiên của đầu ra mô hình: DD> D> DDD> DDDD, phù hợp với thiết lập của chúng tôi. Lưu ý rằng cũng có một cột cho các giá trị bị thiếu. Mặc dù không có tính năng nào bị thiếu trong dữ liệu đào tạo và thử nghiệm của chúng tôi, nhưng mô hình cung cấp cho chúng tôi giá trị bị thiếu nếu nó xảy ra trong quá trình phân phối mô hình hạ lưu.

Ở đây, chúng tôi cũng vẽ biểu đồ CTR dự đoán của mô hình này với điều kiện là dollar_rating . Lưu ý rằng tất cả các ràng buộc mà chúng tôi yêu cầu đều được đáp ứng trong mỗi lát cắt.

Hiệu chuẩn đầu ra

Đối với tất cả các mô hình TFL mà chúng tôi đã đào tạo cho đến nay, lớp mạng tinh thể (được chỉ định là "Lưới" trong biểu đồ mô hình) trực tiếp đưa ra dự đoán mô hình. Đôi khi chúng tôi không chắc liệu đầu ra mạng có nên được thay đổi tỷ lệ để phát ra đầu ra mô hình hay không:

  • các tính năng là $ log $ counts trong khi các nhãn là số lượng.
  • mạng tinh thể được cấu hình để có rất ít đỉnh nhưng sự phân bố nhãn tương đối phức tạp.

Trong những trường hợp đó, chúng ta có thể thêm một bộ hiệu chuẩn khác giữa đầu ra mạng tinh thể và đầu ra mô hình để tăng tính linh hoạt của mô hình. Ở đây, hãy thêm một lớp hiệu chuẩn với 5 điểm chính vào mô hình mà chúng ta vừa tạo. Chúng tôi cũng thêm một bộ điều chỉnh cho bộ hiệu chuẩn đầu ra để giữ cho chức năng hoạt động trơn tru.

feature_columns = [
    tf.feature_column.numeric_column("num_reviews"),
    tf.feature_column.numeric_column("avg_rating"),
    tf.feature_column.categorical_column_with_vocabulary_list(
        "dollar_rating",
        vocabulary_list=["D", "DD", "DDD", "DDDD"],
        dtype=tf.string,
        default_value=0),
]
model_config = tfl.configs.CalibratedLatticeConfig(
    output_calibration=True,
    output_calibration_num_keypoints=5,
    regularizer_configs=[
        tfl.configs.RegularizerConfig(name="output_calib_wrinkle", l2=0.1),
    ],
    feature_configs=[
    tfl.configs.FeatureConfig(
        name="num_reviews",
        lattice_size=2,
        monotonicity="increasing",
        pwl_calibration_convexity="concave",
        pwl_calibration_num_keypoints=20,
        regularizer_configs=[
            tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
        ],
        reflects_trust_in=[
            tfl.configs.TrustConfig(
                feature_name="avg_rating", trust_type="edgeworth"),
        ],
    ),
    tfl.configs.FeatureConfig(
        name="avg_rating",
        lattice_size=2,
        monotonicity="increasing",
        pwl_calibration_num_keypoints=20,
        regularizer_configs=[
            tfl.configs.RegularizerConfig(name="calib_wrinkle", l2=1.0),
        ],
    ),
    tfl.configs.FeatureConfig(
        name="dollar_rating",
        lattice_size=2,
        pwl_calibration_num_keypoints=4,
        # Here we only specify one monotonicity:
        # `D` resturants has smaller value than `DD` restaurants
        monotonicity=[("D", "DD")],
    ),
])
tfl_estimator = tfl.estimators.CannedClassifier(
    feature_columns=feature_columns,
    model_config=model_config,
    feature_analysis_input_fn=feature_analysis_input_fn,
    optimizer=tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE),
    config=tf.estimator.RunConfig(tf_random_seed=42),
)
tfl_estimator.train(input_fn=train_input_fn)
analyze_three_d_estimator(tfl_estimator, "TF Lattice")
_ = save_and_visualize_lattice(tfl_estimator)
Validation AUC: 0.7697908878326416
Testing AUC: 0.861327052116394

png

png

Số liệu và đồ thị thử nghiệm cuối cùng cho thấy cách sử dụng các ràng buộc thông thường có thể giúp mô hình tránh được hành vi không mong muốn và ngoại suy tốt hơn cho toàn bộ không gian đầu vào.