مجموعات البيانات

في العديد من نماذج التعلم الآلي، وخاصةً التعلم الخاضع للإشراف، تعد مجموعات البيانات جزءًا حيويًا من عملية التدريب. يوفر 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، تكون مجموعة البيانات بأكملها صغيرة ويمكن تحميلها في الذاكرة في وقت واحد، ولكن بالنسبة لمجموعات البيانات الكبيرة الأخرى، يتم تحميل دفعات البيانات بتكاسل من القرص ومعالجتها عند النقطة التي يتم فيها الحصول على كل دفعة. وهذا يمنع استنفاد الذاكرة مع مجموعات البيانات الأكبر حجمًا.

واجهة برمجة تطبيقات العصور

تم إنشاء معظم أغلفة مجموعات البيانات هذه على بنية أساسية مشتركة أطلقنا عليها اسم Epochs API . توفر Epochs مكونات مرنة تهدف إلى دعم مجموعة واسعة من أنواع مجموعات البيانات، من النص إلى الصور والمزيد.

إذا كنت ترغب في إنشاء غلاف مجموعة بيانات Swift الخاص بك، فستحتاج على الأرجح إلى استخدام Epochs API للقيام بذلك. ومع ذلك، بالنسبة للحالات الشائعة، مثل مجموعات بيانات تصنيف الصور، نوصي بشدة بالبدء من قالب يستند إلى أحد أغلفة مجموعة البيانات الموجودة وتعديله لتلبية احتياجاتك الخاصة.

على سبيل المثال، دعونا نتفحص غلاف مجموعة البيانات 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 في أنواع مختلفة من مجموعات البيانات، يمكنك فحص أغلفة مجموعات البيانات الأخرى داخل مستودع النماذج.