מערכי נתונים

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

סיפקו עטיפות של מערך נתונים

אלו הן עטיפות הנתונים המסופקות כעת במאגר המודלים:

כדי להשתמש באחת מעוטפות הנתונים הללו בתוך פרויקט Swift, הוסף Datasets כתלות ליעד Swift שלך וייבא את המודול:

import Datasets

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

let dataset = CIFAR10(batchSize: 100)

בשימוש הראשון, עטיפות הנתונים של Swift for TensorFlow יוריד עבורך באופן אוטומטי את מערך הנתונים המקורי, יחלץ וינתח את כל הארכיונים הרלוונטיים, ולאחר מכן יאחסן את מערך הנתונים המעובד בספריית מטמון מקומית למשתמש. שימושים הבאים באותו מערך נתונים ייטענו ישירות מהמטמון המקומי.

כדי להגדיר לולאת אימון ידנית הכוללת מערך נתונים זה, תשתמש במשהו כמו הבא:

for (epoch, epochBatches) in dataset.training.prefix(100).enumerated() {
  Context.local.learningPhase = .training
  ...
  for batch in epochBatches {
    let (images, labels) = (batch.data, batch.label)
    ...
  }
}

האמור לעיל מגדיר איטרטור דרך 100 עידנים ( .prefix(100) ), ומחזיר את האינדקס המספרי של העידן הנוכחי ורצף ממופה בעצלתיים על פני אצווה מדשדשת המרכיבות אותה תקופה. בתוך כל עידן אימון, קבוצות עוברות שוב ושוב וחולצות לעיבוד. במקרה של מעטפת הנתונים CIFAR10 , כל אצווה היא LabeledImage , המספקת Tensor<Float> המכילה את כל התמונות מאותה אצווה ו- Tensor<Int32> עם התוויות התואמות שלהן.

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

ה-API של Epochs

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

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

כדוגמה, הבה נבחן את מעטפת הנתונים של CIFAR-10 וכיצד היא פועלת. הליבה של מערך ההדרכה מוגדרת כאן:

let trainingSamples = loadCIFARTrainingFiles(in: localStorageDirectory)
training = TrainingEpochs(samples: trainingSamples, batchSize: batchSize, entropy: entropy)
  .lazy.map { (batches: Batches) -> LazyMapSequence<Batches, LabeledImage> in
    return batches.lazy.map{
      makeBatch(samples: $0, mean: mean, standardDeviation: standardDeviation, device: device)
  }
}

התוצאה מהפונקציה loadCIFARTrainingFiles() היא מערך של (data: [UInt8], label: Int32) tuples עבור כל תמונה במערך האימון. לאחר מכן זה מסופק ל- TrainingEpochs(samples:batchSize:entropy:) כדי ליצור רצף אינסופי של תקופות עם קבוצות של batchSize . אתה יכול לספק מחולל מספרים אקראיים משלך במקרים שבהם תרצה התנהגות אצווה דטרמיניסטית, אך כברירת מחדל נעשה שימוש ב- SystemRandomNumberGenerator .

משם, מפות עצלניות מעל הקבוצות מגיעות לשיא בפונקציית makeBatch(samples:mean:standardDeviation:device:) . זוהי פונקציה מותאמת אישית שבה נמצא צינור עיבוד התמונה בפועל עבור מערך הנתונים של CIFAR-10, אז בואו נסתכל על זה:

fileprivate func makeBatch<BatchSamples: Collection>(
  samples: BatchSamples, mean: Tensor<Float>?, standardDeviation: Tensor<Float>?, device: Device
) -> LabeledImage where BatchSamples.Element == (data: [UInt8], label: Int32) {
  let bytes = samples.lazy.map(\.data).reduce(into: [], +=)
  let images = Tensor<UInt8>(shape: [samples.count, 3, 32, 32], scalars: bytes, on: device)

  var imageTensor = Tensor<Float>(images.transposed(permutation: [0, 2, 3, 1]))
  imageTensor /= 255.0
  if let mean = mean, let standardDeviation = standardDeviation {
    imageTensor = (imageTensor - mean) / standardDeviation
  }

  let labels = Tensor<Int32>(samples.map(\.label), on: device)
  return LabeledImage(data: imageTensor, label: labels)
}

שתי השורות של פונקציה זו משרשרות את כל בתים data מה- BatchSamples הנכנסים לתוך Tensor<UInt8> התואם את פריסת הביטים של התמונות בתוך מערך הנתונים הגולמי של CIFAR-10. לאחר מכן, ערוצי התמונה מסודרים מחדש כך שיתאימו לאלו הצפויים במודלים הסטנדרטיים של סיווג התמונות שלנו ונתוני התמונה נוצקים מחדש ל- Tensor<Float> לצריכת מודל.

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

לבסוף, תוויות המספרים השלמים ממוקמות ב- Tensor<Int32> וצמד הטנזור של התמונה/תווית מוחזר ב- LabeledImage . LabeledImage הוא מקרה ספציפי של LabeledData , מבנה עם נתונים ותוויות התואמים לפרוטוקול Collatable של Eppch API.

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