مجموعه داده ها

در بسیاری از مدل‌های یادگیری ماشین، به‌ویژه برای یادگیری تحت نظارت، مجموعه داده‌ها بخش مهمی از فرآیند آموزش هستند. Swift for TensorFlow برای چندین مجموعه داده رایج در ماژول Datasets در مخزن مدل‌ها بسته‌بندی‌ها را فراهم می‌کند. این بسته‌بندی‌ها استفاده از مجموعه داده‌های رایج را با مدل‌های مبتنی بر سوئیفت آسان می‌کنند و به خوبی با حلقه آموزشی تعمیم‌یافته Swift for TensorFlow ادغام می‌شوند.

بسته های داده ارائه شده است

اینها بسته‌بندی‌های داده موجود در مخزن مدل‌ها هستند:

برای استفاده از یکی از این بسته‌های داده در پروژه سوئیفت، Datasets به عنوان یک وابستگی به هدف سوئیفت خود اضافه کنید و ماژول را وارد کنید:

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

بیشتر این بسته‌های داده بر روی یک زیرساخت مشترک ساخته شده‌اند که ما آن را Epochs API نامیده‌ایم. Epochs مؤلفه‌های انعطاف‌پذیری را ارائه می‌کند که برای پشتیبانی از طیف گسترده‌ای از انواع داده‌ها، از متن گرفته تا عکس و موارد دیگر طراحی شده است.

اگر می‌خواهید بسته داده سوئیفت خود را بسازید، به احتمال زیاد می‌خواهید از 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) برای هر تصویر در مجموعه داده آموزشی است. سپس به 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 مطابقت دارند.

برای مثال‌های بیشتر از Epochs API در انواع داده‌های مختلف، می‌توانید بسته‌های داده دیگر را در مخزن مدل‌ها بررسی کنید.