רכיב Transform TFX Pipeline

רכיב הצינור של Transform TFX מבצע הנדסת תכונות על tf. דוגמאות הנפלטות מרכיב של ExampleGen , תוך שימוש בסכימת נתונים שנוצרה על ידי רכיב SchemaGen , ופולט גם SavedModel וגם סטטיסטיקות על נתונים של טרום-טרנספורמציה וגם שלאחר-טרנספורמציה. כאשר הוא מופעל, SavedModel יקבל tf.Examples הנפלטות מרכיב ExampleGen ויפלוט את נתוני התכונה שעברו טרנספורמציה.

  • צורכת: tf.Examples מרכיב ExampleGen, וסכימת נתונים מרכיב SchemaGen.
  • פולט: רכיב SavedModel ל-Trainer, סטטיסטיקות טרום טרנספורמציה ואחרי טרנספורמציה.

הגדרת רכיב טרנספורמציה

ברגע שה- preprocessing_fn שלך נכתב, יש להגדיר אותו במודול python שמסופק לרכיב Transform כקלט. מודול זה ייטען באמצעות טרנספורמציה והפונקציה בשם preprocessing_fn תימצא ותשתמש ב-Transform כדי לבנות את צינור העיבוד המקדים.

transform = Transform(
    examples=example_gen.outputs['examples'],
    schema=schema_gen.outputs['schema'],
    module_file=os.path.abspath(_taxi_transform_module_file))

בנוסף, ייתכן שתרצה לספק אפשרויות לחישוב סטטיסטיקה טרום-טרנספורמציה או לאחר-טרנספורמציה מבוסס TFDV . כדי לעשות זאת, הגדר stats_options_updater_fn בתוך אותו מודול.

Transform ו- TensorFlow Transform

Transform עושה שימוש נרחב ב- TensorFlow Transform לביצוע הנדסת תכונות במערך הנתונים שלך. TensorFlow Transform הוא כלי נהדר להמרת נתוני תכונות לפני שהם עוברים למודל שלך וכחלק מתהליך ההדרכה. טרנספורמציות תכונות נפוצות כוללות:

  • הטבעה : המרת תכונות דלילות (כמו מזהי מספרים שלמים המיוצרים על ידי אוצר מילים) לתכונות צפופות על ידי מציאת מיפוי משמעותי ממרחב בעל מימד גבוה למרחב בעל מימד נמוך. ראה את יחידת ההטבעות בקורס התרסקות למידת מכונה למבוא להטמעות.
  • יצירת אוצר מילים : המרת מחרוזות או תכונות אחרות שאינן מספריות למספרים שלמים על ידי יצירת אוצר מילים הממפה כל ערך ייחודי למספר מזהה.
  • מנרמל ערכים : שינוי תכונות מספריות כך שכולן נופלות בטווח דומה.
  • bucketization : המרת תכונות בעלות ערך רציף לתכונות קטגוריות על ידי הקצאת ערכים לדליים נפרדים.
  • תכונות טקסט מעשירות : הפקת תכונות מנתונים גולמיים כמו אסימונים, n-גרם, ישויות, סנטימנט וכו', כדי להעשיר את מערך התכונות.

TensorFlow Transform מספקת תמיכה לסוגים אלה ולסוגים רבים אחרים של טרנספורמציות:

  • הפק אוטומטית אוצר מילים מהנתונים העדכניים ביותר שלך.

  • בצע טרנספורמציות שרירותיות בנתונים שלך לפני שליחתם לדגם שלך. TensorFlow Transform בונה טרנספורמציות לתוך גרף TensorFlow עבור המודל שלך כך שאותן טרנספורמציות מבוצעות בזמן האימון וההסקה. אתה יכול להגדיר טרנספורמציות המתייחסות למאפיינים גלובליים של הנתונים, כמו הערך המקסימלי של תכונה בכל מופעי האימון.

אתה יכול לשנות את הנתונים שלך איך שאתה רוצה לפני הפעלת TFX. אבל אם אתה עושה את זה בתוך TensorFlow Transform, טרנספורמציות הופכות לחלק מגרף TensorFlow. גישה זו מסייעת להימנע מהטיית אימון/הגשה.

טרנספורמציות בתוך קוד הדוגמנות שלך משתמשות ב- FeatureColumns. באמצעות FeatureColumns, אתה יכול להגדיר bucketizations, שילובים שלמים המשתמשים באוצר מילים מוגדרים מראש, או כל טרנספורמציה אחרת שניתן להגדיר מבלי להסתכל על הנתונים.

לעומת זאת, TensorFlow Transform מיועד לטרנספורמציות הדורשות מעבר מלא על הנתונים כדי לחשב ערכים שאינם ידועים מראש. לדוגמה, יצירת אוצר מילים דורשת מעבר מלא על הנתונים.

בנוסף לחישוב ערכים באמצעות Apache Beam, TensorFlow Transform מאפשר למשתמשים להטמיע ערכים אלו בגרף TensorFlow, אשר לאחר מכן ניתן לטעון לתוך גרף האימון. למשל בעת נרמול תכונות, הפונקציה tft.scale_to_z_score תחשב את הממוצע ואת סטיית התקן של תכונה, וגם ייצוג, בגרף TensorFlow, של הפונקציה המפחיתה את הממוצע ומחלקת בסטיית התקן. על ידי פליטת גרף TensorFlow, לא רק סטטיסטיקה, TensorFlow Transform מפשטת את תהליך עריכת צינור העיבוד המוקדם שלך.

מכיוון שהעיבוד המקדים מתבטא כגרף, זה יכול לקרות בשרת, ומובטח שהוא יהיה עקבי בין אימון להגשה. עקביות זו מבטלת מקור אחד להטיית אימון/הגשה.

TensorFlow Transform מאפשר למשתמשים לציין את צינור העיבוד המקדים שלהם באמצעות קוד TensorFlow. המשמעות היא שצינור נבנה באותו אופן כמו גרף TensorFlow. אם רק אופציות של TensorFlow היו בשימוש בגרף זה, הצינור יהיה מפה טהורה שמקבלת קבוצות של קלט ומחזירה אצות של פלט. צינור כזה יהיה שווה ערך להצבת גרף זה בתוך input_fn שלך בעת שימוש ב- tf.Estimator API. על מנת לציין פעולות מעבר מלא כגון קוונטילי מחשוב, TensorFlow Transform מספקת פונקציות מיוחדות הנקראות analyzers המופיעות כמו TensorFlow ops, אך למעשה מציינים חישוב דחוי שייעשה על ידי Apache Beam, והפלט יוכנס לגרף כ- קָבוּעַ. בעוד שמבצע TensorFlow רגיל ייקח אצווה בודדת כקלט שלו, יבצע חישוב על אצווה זו בלבד ויפלוט אצווה, analyzer יבצע הפחתה גלובלית (מיושם ב- Apache Beam) על כל האצווה ויחזיר את התוצאה.

על ידי שילוב של TensorFlow אופציות רגילות ומנתחי TensorFlow Transform, משתמשים יכולים ליצור צינורות מורכבים כדי לעבד מראש את הנתונים שלהם. לדוגמה, הפונקציה tft.scale_to_z_score לוקחת טנזור קלט ומחזירה טנזור זה מנורמל לממוצע 0 ושונות 1 . הוא עושה זאת על ידי קריאת מנתחי mean וה- var מתחת למכסה המנוע, אשר יפיקו למעשה קבועים בגרף השווים לממוצע והשונות של טנזור הקלט. לאחר מכן הוא ישתמש ב- TensorFlow ops כדי להחסיר את הממוצע ולחלק בסטיית התקן.

ה-TensorFlow Transform preprocessing_fn

רכיב TFX Transform מפשט את השימוש ב-Transform על ידי טיפול בקריאות API הקשורות לקריאה וכתיבת נתונים, וכתיבת הפלט SavedModel לדיסק. כמשתמש TFX, אתה רק צריך להגדיר פונקציה בודדת בשם preprocessing_fn . ב- preprocessing_fn אתה מגדיר סדרה של פונקציות שמתפעלות את dict קלט של טנסורים כדי לייצר את dict הפלט של טנסורים. אתה יכול למצוא פונקציות מסייעות כמו scale_to_0_1 ו-compute_and_apply_vocabulary את TensorFlow Transform API או להשתמש בפונקציות TensorFlow רגילות כפי שמוצג להלן.

def preprocessing_fn(inputs):
  """tf.transform's callback function for preprocessing inputs.

  Args:
    inputs: map from feature keys to raw not-yet-transformed features.

  Returns:
    Map from string feature key to transformed feature operations.
  """
  outputs = {}
  for key in _DENSE_FLOAT_FEATURE_KEYS:
    # If sparse make it dense, setting nan's to 0 or '', and apply zscore.
    outputs[_transformed_name(key)] = transform.scale_to_z_score(
        _fill_in_missing(inputs[key]))

  for key in _VOCAB_FEATURE_KEYS:
    # Build a vocabulary for this feature.
    outputs[_transformed_name(
        key)] = transform.compute_and_apply_vocabulary(
            _fill_in_missing(inputs[key]),
            top_k=_VOCAB_SIZE,
            num_oov_buckets=_OOV_SIZE)

  for key in _BUCKET_FEATURE_KEYS:
    outputs[_transformed_name(key)] = transform.bucketize(
        _fill_in_missing(inputs[key]), _FEATURE_BUCKET_COUNT)

  for key in _CATEGORICAL_FEATURE_KEYS:
    outputs[_transformed_name(key)] = _fill_in_missing(inputs[key])

  # Was this passenger a big tipper?
  taxi_fare = _fill_in_missing(inputs[_FARE_KEY])
  tips = _fill_in_missing(inputs[_LABEL_KEY])
  outputs[_transformed_name(_LABEL_KEY)] = tf.where(
      tf.is_nan(taxi_fare),
      tf.cast(tf.zeros_like(taxi_fare), tf.int64),
      # Test if the tip was > 20% of the fare.
      tf.cast(
          tf.greater(tips, tf.multiply(taxi_fare, tf.constant(0.2))), tf.int64))

  return outputs

הבנת התשומות ל-preprocessing_fn

ה- preprocessing_fn מתאר סדרה של פעולות על טנסורים (כלומר, Tensor s או SparseTensor s) ולכן כדי לכתוב את preprocessing_fn בצורה נכונה יש צורך להבין כיצד הנתונים שלך מיוצגים כטנסורים. הקלט ל- preprocessing_fn נקבע על ידי הסכימה. פרוטו של Schema מכיל רשימה של Feature , ו-Transform ממירה את אלה ל"מפרט תכונה" (נקרא לפעמים "מפרט ניתוח") שהוא dict שהמפתחות שלו הם שמות תכונה והערכים שלו הם אחד של FixedLenFeature או VarLenFeature (או אחר אפשרויות שאינן בשימוש על ידי TensorFlow Transform).

הכללים להסקת מפרט תכונה Schema הם

  • כל feature עם ערכת shape תגרום ל- tf.FixedLenFeature עם shape ו- default_value=None . presence.min_fraction חייב להיות 1 אחרת ותגרם שגיאה, שכן כאשר אין ערך ברירת מחדל, tf.FixedLenFeature מחייב את התכונה להיות קיימת תמיד.
  • כל feature עם shape לא מוגדרת תגרום ל- VarLenFeature .
  • כל sparse_feature תגרום ל- tf.SparseFeature size וה- is_sorted שלו נקבעים על ידי השדות fixed_shape ו- is_sorted של הודעת SparseFeature .
  • לתכונות המשמשות בתור index_feature או value_feature של sparse_feature לא תהיה ערך משלהם שנוצר במפרט התכונה.
  • ההתאמה בין שדה type של feature (או תכונת הערכים של פרוטו sparse_feature ) לבין ה- dtype של מפרט התכונה ניתנת על ידי הטבלה הבאה:
type dtype
schema_pb2.INT tf.int64
schema_pb2.FLOAT tf.float32
schema_pb2.BYTES tf.string

שימוש ב-TensorFlow Transform לטיפול בתוויות מחרוזות

בדרך כלל רוצים להשתמש ב-TensorFlow Transform גם כדי ליצור אוצר מילים וגם להחיל את אוצר המילים הזה כדי להמיר מחרוזות למספרים שלמים. כאשר עוקבים אחר זרימת עבודה זו, ה- input_fn שנבנה במודל יוציא את המחרוזת המשולמת. עם זאת התוויות הן חריגות, מכיוון שכדי שהמודל יוכל למפות את תוויות הפלט (מספר שלם) בחזרה למחרוזות, המודל צריך את ה- input_fn כדי להוציא תווית מחרוזת, יחד עם רשימה של ערכים אפשריים של התווית. למשל, אם התוויות הן cat dog אז הפלט של ה- input_fn צריך להיות מחרוזות גולמיות אלה, ויש להעביר את המפתחות ["cat", "dog"] לאומדן כפרמטר (ראה פרטים למטה).

על מנת לטפל במיפוי של תוויות מחרוזות למספרים שלמים, עליך להשתמש ב-TensorFlow Transform כדי ליצור אוצר מילים. אנו מדגימים זאת בקטע הקוד שלהלן:

def _preprocessing_fn(inputs):
  """Preprocess input features into transformed features."""

  ...


  education = inputs[features.RAW_LABEL_KEY]
  _ = tft.vocabulary(education, vocab_filename=features.RAW_LABEL_KEY)

  ...

פונקציית העיבוד הקדם שלמעלה לוקחת את תכונת הקלט הגולמית (שאף היא תוחזר כחלק מהפלט של פונקציית העיבוד הקדם) וקוראת tft.vocabulary . כתוצאה מכך נוצר אוצר מילים education שניתן לגשת אליו במודל.

הדוגמה מראה גם כיצד להפוך תווית ולאחר מכן ליצור אוצר מילים עבור התווית שעברה שינוי. בפרט זה לוקח את התווית הגולמית education וממיר את כל התוויות מלבד 5 התוויות המובילות (לפי תדירות) ל- UNKNOWN , מבלי להמיר את התווית למספר שלם.

בקוד המודל, יש לתת למסווג את אוצר המילים שנוצר על ידי tft.vocabulary כארגומנט label_vocabulary . זה נעשה על ידי קריאה ראשונה של אוצר מילים זה כרשימה עם פונקציית עוזר. זה מוצג בקטע למטה. שימו לב שהקוד לדוגמה משתמש בתווית שעברה הטרנספורמציה שנדונה לעיל, אבל כאן אנו מציגים קוד לשימוש בתווית הגולמית.

def create_estimator(pipeline_inputs, hparams):

  ...

  tf_transform_output = trainer_util.TFTransformOutput(
      pipeline_inputs.transform_dir)

  # vocabulary_by_name() returns a Python list.
  label_vocabulary = tf_transform_output.vocabulary_by_name(
      features.RAW_LABEL_KEY)

  return tf.contrib.learn.DNNLinearCombinedClassifier(
      ...
      n_classes=len(label_vocab),
      label_vocabulary=label_vocab,
      ...)

הגדרת נתונים סטטיסטיים לפני טרנספורמציה ואחרי טרנספורמציה

כפי שהוזכר לעיל, רכיב הטרנספורמציה מפעיל את TFDV כדי לחשב סטטיסטיקות טרום-טרנספורמציה וגם לאחר-טרנספורמציה. TFDV לוקח כקלט אובייקט StatsOptions אופציונלי. ייתכן שמשתמשים ירצו להגדיר את האובייקט הזה כדי לאפשר נתונים סטטיסטיים נוספים מסוימים (למשל סטטיסטיקות NLP) או להגדיר ספים מאומתים (למשל תדירות אסימון מינימלי/מקסימלית). לשם כך, הגדר stats_options_updater_fn בקובץ המודול.

def stats_options_updater_fn(stats_type, stats_options):
  ...
  if stats_type == stats_options_util.StatsType.PRE_TRANSFORM:
    # Update stats_options to modify pre-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  if stats_type == stats_options_util.StatsType.POST_TRANSFORM
    # Update stats_options to modify post-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  return stats_options

נתונים סטטיסטיים לאחר טרנספורמציה נהנים לעתים קרובות מהידע על אוצר המילים המשמש לעיבוד מקדים של תכונה. שם אוצר המילים למיפוי נתיב מסופק ל-StatsOptions (ומכאן ל-TFDV) עבור כל אוצר מילים שנוצר באמצעות TFT. בנוסף, ניתן להוסיף מיפויים עבור אוצר מילים שנוצרו באופן חיצוני על ידי (i) שינוי ישיר של מילון vocab_paths בתוך StatsOptions או על ידי (ii) שימוש ב- tft.annotate_asset .