این صفحه به‌وسیله ‏Cloud Translation API‏ ترجمه شده است.
Switch to English

رهگذر آموزش مدل

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub

این راهنما Swift را برای TensorFlow با ساخت یک مدل یادگیری ماشین که گلهای زنبق را بر اساس گونه ها دسته بندی می کند ، معرفی می کند. از Swift برای TensorFlow استفاده می کند تا:

  1. یک مدل بسازید ،
  2. این مدل را بر روی داده های مثال آموزش دهید ، و
  3. از مدل برای پیش بینی داده های ناشناخته استفاده کنید.

برنامه نویسی TensorFlow

این راهنما از این Swift سطح بالا برای مفاهیم TensorFlow استفاده می کند:

  • داده ها را با API Epochs وارد کنید.
  • با استفاده از انتزاعات Swift مدل بسازید.
  • هنگامی که کتابخانه های Swift خالص در دسترس نیست ، از کتابخانه های پایتون با استفاده از قابلیت همکاری Swift's Python استفاده کنید.

ساختار این آموزش مانند بسیاری از برنامه های TensorFlow است:

  1. مجموعه داده ها را وارد کرده و تجزیه کنید.
  2. نوع مدل را انتخاب کنید.
  3. مدل را آموزش دهید.
  4. اثربخشی مدل را ارزیابی کنید.
  5. از مدل آموزش دیده برای پیش بینی استفاده کنید.

برنامه راه اندازی

واردات را پیکربندی کنید

TensorFlow و چند ماژول مفید پایتون را وارد کنید.

import TensorFlow
import PythonKit
// This cell is here to display the plots in a Jupyter Notebook.
// Do not copy it into another environment.
%include "EnableIPythonDisplay.swift"
IPythonDisplay.shell.enable_matplotlib("inline")
('inline', 'module://ipykernel.pylab.backend_inline')

let plt = Python.import("matplotlib.pyplot")
import Foundation
import FoundationNetworking
func download(from sourceString: String, to destinationString: String) {
    let source = URL(string: sourceString)!
    let destination = URL(fileURLWithPath: destinationString)
    let data = try! Data.init(contentsOf: source)
    try! data.write(to: destination)
}

مشکل طبقه بندی عنبیه

تصور کنید که یک گیاه شناس هستید و به دنبال روشی خودکار برای دسته بندی هر گل عنبیه هستید. یادگیری ماشینی الگوریتم های بسیاری را برای طبقه بندی آماری گلها ارائه می دهد. به عنوان مثال ، یک برنامه پیچیده یادگیری ماشین می تواند گل ها را بر اساس عکس ها طبقه بندی کند. جاه طلبی های ما متوسط ​​تر است - ما می خواهیم گل های عنبیه را بر اساس اندازه گیری طول و عرض گلدان های گلبرگ و گلبرگ آنها طبقه بندی کنیم.

جنس Iris شامل 300 گونه است ، اما برنامه ما فقط سه مورد زیر را طبقه بندی می کند:

  • آیریس ستوسا
  • Iris virginica
  • آیریس رنگارنگ
هندسه گلبرگ در مقایسه با سه گونه عنبیه: Iris setosa ، Iris virginica و Iris versicolor
شکل 1. Iris setosa (توسط Radomil ، CC BY-SA 3.0)، Iris versicolor ، (توسط Dlanglois ، CC BY-SA 3.0)، و Iris virginica (توسط Frank Mayfield ، CC BY-SA 2.0).

خوشبختانه ، کسی قبلاً مجموعه ای از 120 گل زنبق را با اندازه گیری کاسبرگ و گلبرگ ایجاد کرده است. این یک مجموعه داده کلاسیک است که برای مشکلات طبقه بندی یادگیری ماشین مبتدی محبوب است.

مجموعه داده های آموزش را وارد کرده و تجزیه کنید

فایل مجموعه داده را بارگیری کرده و به ساختاری تبدیل کنید که می تواند توسط این برنامه Swift مورد استفاده قرار گیرد.

مجموعه داده را بارگیری کنید

فایل مجموعه آموزش را از http://download.tensorflow.org/data/iris_training.csv بارگیری کنید

let trainDataFilename = "iris_training.csv"
download(from: "http://download.tensorflow.org/data/iris_training.csv", to: trainDataFilename)

داده ها را بازرسی کنید

این مجموعه داده ، iris_training.csv ، یک فایل متنی ساده است که داده های جدولی قالب بندی شده به عنوان مقادیر جدا شده با کاما (CSV) را در خود ذخیره می کند. بیایید 5 ورودی اول را بررسی کنیم.

let f = Python.open(trainDataFilename)
for _ in 0..<5 {
    print(Python.next(f).strip())
}
f.close()
120,4,setosa,versicolor,virginica
6.4,2.8,5.6,2.2,2
5.0,2.3,3.3,1.0,1
4.9,2.5,4.5,1.7,2
4.9,3.1,1.5,0.1,0

None

از این نمای مجموعه داده ، به موارد زیر توجه کنید:

  1. خط اول یک عنوان است که شامل اطلاعاتی در مورد مجموعه داده است:
    • در کل 120 نمونه وجود دارد. هر مثال دارای چهار ویژگی و یکی از سه نام برچسب ممکن است.
  2. ردیف های بعدی سوابق داده ها هستند ، یک مثال در هر خط ، که در آن:
    • چهار زمینه اول ویژگی هستند: این ویژگی های یک مثال است. در اینجا ، فیلدها اعداد شناور را نشان می دهند که اندازه گیری گل را نشان می دهد.
    • ستون آخر برچسب است : این مقداری است که می خواهیم پیش بینی کنیم. برای این مجموعه داده ، یک عدد صحیح 0 ، 1 یا 2 است که با یک نام گل مطابقت دارد.

بیایید این را به صورت کد بنویسیم:

let featureNames = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
let labelName = "species"
let columnNames = featureNames + [labelName]

print("Features: \(featureNames)")
print("Label: \(labelName)")
Features: ["sepal_length", "sepal_width", "petal_length", "petal_width"]
Label: species

هر برچسب با نام رشته مرتبط است (به عنوان مثال ، "setosa") ، اما یادگیری ماشین به طور معمول به مقادیر عددی متکی است. شماره های برچسب به نمایندگی نامگذاری شده ، مانند:

  • 0 : آیریس ستوسا
  • 1 : زنبق عنكبوت
  • 2 : Iris virginica

برای کسب اطلاعات بیشتر در مورد ویژگی ها و برچسب ها ، به بخش اصطلاحات ML در دوره سقوط یادگیری ماشین مراجعه کنید .

let classNames = ["Iris setosa", "Iris versicolor", "Iris virginica"]

با استفاده از API Epochs یک مجموعه داده ایجاد کنید

Swift for TensorFlow's Epochs API یک API سطح بالا برای خواندن داده ها و تبدیل آن به فرم مورد استفاده برای آموزش است.

let batchSize = 32

/// A batch of examples from the iris dataset.
struct IrisBatch {
    /// [batchSize, featureCount] tensor of features.
    let features: Tensor<Float>

    /// [batchSize] tensor of labels.
    let labels: Tensor<Int32>
}

/// Conform `IrisBatch` to `Collatable` so that we can load it into a `TrainingEpoch`.
extension IrisBatch: Collatable {
    public init<BatchSamples: Collection>(collating samples: BatchSamples)
        where BatchSamples.Element == Self {
        /// `IrisBatch`es are collated by stacking their feature and label tensors
        /// along the batch axis to produce a single feature and label tensor
        features = Tensor<Float>(stacking: samples.map{$0.features})
        labels = Tensor<Int32>(stacking: samples.map{$0.labels})
    }
}

از آنجا که مجموعه داده های بارگیری شده ما در قالب CSV هستند ، بیایید یک تابع برای بارگذاری در داده ها به عنوان لیستی از اشیا I IrisBatch بنویسیم

/// Initialize an `IrisBatch` dataset from a CSV file.
func loadIrisDatasetFromCSV(
        contentsOf: String, hasHeader: Bool, featureColumns: [Int], labelColumns: [Int]) -> [IrisBatch] {
        let np = Python.import("numpy")

        let featuresNp = np.loadtxt(
            contentsOf,
            delimiter: ",",
            skiprows: hasHeader ? 1 : 0,
            usecols: featureColumns,
            dtype: Float.numpyScalarTypes.first!)
        guard let featuresTensor = Tensor<Float>(numpy: featuresNp) else {
            // This should never happen, because we construct featuresNp in such a
            // way that it should be convertible to tensor.
            fatalError("np.loadtxt result can't be converted to Tensor")
        }

        let labelsNp = np.loadtxt(
            contentsOf,
            delimiter: ",",
            skiprows: hasHeader ? 1 : 0,
            usecols: labelColumns,
            dtype: Int32.numpyScalarTypes.first!)
        guard let labelsTensor = Tensor<Int32>(numpy: labelsNp) else {
            // This should never happen, because we construct labelsNp in such a
            // way that it should be convertible to tensor.
            fatalError("np.loadtxt result can't be converted to Tensor")
        }

        return zip(featuresTensor.unstacked(), labelsTensor.unstacked()).map{IrisBatch(features: $0.0, labels: $0.1)}

    }

اکنون می توانیم از تابع CSV loading برای بارگذاری مجموعه داده های آموزشی و ایجاد یک شی TrainingEpochs استفاده کنیم

let trainingDataset: [IrisBatch] = loadIrisDatasetFromCSV(contentsOf: trainDataFilename, 
                                                  hasHeader: true, 
                                                  featureColumns: [0, 1, 2, 3], 
                                                  labelColumns: [4])

let trainingEpochs: TrainingEpochs = TrainingEpochs(samples: trainingDataset, batchSize: batchSize)

شی TrainingEpochs توالی نامحدودی از دوره ها است. هر دوره شامل IrisBatch . بیایید به اولین عنصر دوران اول نگاه کنیم.

let firstTrainEpoch = trainingEpochs.next()!
let firstTrainBatch = firstTrainEpoch.first!.collated
let firstTrainFeatures = firstTrainBatch.features
let firstTrainLabels = firstTrainBatch.labels

print("First batch of features: \(firstTrainFeatures)")
print("firstTrainFeatures.shape: \(firstTrainFeatures.shape)")
print("First batch of labels: \(firstTrainLabels)")
print("firstTrainLabels.shape: \(firstTrainLabels.shape)")
First batch of features: [[5.0, 2.3, 3.3, 1.0],
 [5.6, 2.9, 3.6, 1.3],
 [5.7, 2.8, 4.1, 1.3],
 [4.4, 2.9, 1.4, 0.2],
 [5.0, 3.2, 1.2, 0.2],
 [4.9, 3.1, 1.5, 0.1],
 [4.9, 3.1, 1.5, 0.1],
 [5.8, 2.6, 4.0, 1.2],
 [5.8, 2.7, 5.1, 1.9],
 [5.0, 3.5, 1.3, 0.3],
 [6.3, 2.5, 5.0, 1.9],
 [4.6, 3.1, 1.5, 0.2],
 [5.9, 3.2, 4.8, 1.8],
 [6.9, 3.2, 5.7, 2.3],
 [5.7, 4.4, 1.5, 0.4],
 [5.8, 2.8, 5.1, 2.4],
 [5.4, 3.0, 4.5, 1.5],
 [6.3, 3.4, 5.6, 2.4],
 [5.9, 3.0, 5.1, 1.8],
 [4.6, 3.4, 1.4, 0.3],
 [5.0, 3.4, 1.6, 0.4],
 [6.3, 2.3, 4.4, 1.3],
 [4.4, 3.0, 1.3, 0.2],
 [5.5, 2.6, 4.4, 1.2],
 [5.4, 3.7, 1.5, 0.2],
 [5.0, 3.4, 1.5, 0.2],
 [6.8, 3.0, 5.5, 2.1],
 [6.2, 2.8, 4.8, 1.8],
 [5.4, 3.9, 1.7, 0.4],
 [7.7, 2.6, 6.9, 2.3],
 [4.9, 3.1, 1.5, 0.1],
 [5.8, 2.7, 4.1, 1.0]]
firstTrainFeatures.shape: [32, 4]
First batch of labels: [1, 1, 1, 0, 0, 0, 0, 1, 2, 0, 2, 0, 1, 2, 0, 2, 1, 2, 2, 0, 0, 1, 0, 1, 0, 0, 2, 2, 0, 2, 0, 1]
firstTrainLabels.shape: [32]

توجه داشته باشید که ویژگی های برای اولین batchSize نمونه با هم گروه بندی (یا بسته بندی های کوچک) به firstTrainFeatures ، و این که برچسب برای اولین batchSize نمونه به بسته بندی های کوچک firstTrainLabels .

با ترسیم چند ویژگی از دسته ، با استفاده از matplotlib پایتون می توانید شروع به دیدن برخی خوشه ها کنید:

let firstTrainFeaturesTransposed = firstTrainFeatures.transposed()
let petalLengths = firstTrainFeaturesTransposed[2].scalars
let sepalLengths = firstTrainFeaturesTransposed[0].scalars

plt.scatter(petalLengths, sepalLengths, c: firstTrainLabels.array.scalars)
plt.xlabel("Petal length")
plt.ylabel("Sepal length")
plt.show()

png

None

نوع مدل را انتخاب کنید

چرا مدل؟

مدل رابطه ای بین ویژگی ها و برچسب است. برای مشکل طبقه بندی عنبیه ، مدل رابطه بین اندازه گیری گل ماسوره و گلبرگ و گونه های عنبیه پیش بینی شده را تعریف می کند. برخی از مدلهای ساده را می توان با چند خط جبر توصیف کرد ، اما مدلهای پیچیده یادگیری ماشین تعداد زیادی پارامتر دارند که خلاصه کردن آنها دشوار است.

آیا می توانید بدون استفاده از یادگیری ماشینی رابطه بین چهار ویژگی و گونه عنبیه را تعیین کنید؟ یعنی آیا می توانید از تکنیک های برنامه نویسی سنتی (به عنوان مثال بسیاری از عبارات شرطی) برای ایجاد یک مدل استفاده کنید؟ شاید — اگر مجموعه داده را آنقدر تجزیه و تحلیل کردید که بتوانید روابط بین اندازه گیری گلبرگ و کاسبرگ را با یک گونه خاص تعیین کنید. و این در مجموعه داده های پیچیده تر - شاید غیرممکن - دشوار می شود. یک رویکرد خوب یادگیری ماشین مدل را برای شما تعیین می کند . اگر به اندازه کافی نمونه های نمایشی را در مدل مناسب یادگیری ماشین تغذیه کنید ، برنامه روابط شما را پیدا می کند.

مدل را انتخاب کنید

ما باید نوع مدلی را برای آموزش انتخاب کنیم. انواع مختلفی از مدل ها وجود دارد و انتخاب یک مدل خوب به تجربه نیاز دارد. این آموزش برای حل مشکل طبقه بندی عنبیه از یک شبکه عصبی استفاده می کند. شبکه های عصبی می توانند روابط پیچیده ای بین ویژگی ها و برچسب پیدا کنند. این یک نمودار کاملاً ساختاریافته است که در یک یا چند لایه پنهان سازمان یافته است. هر لایه پنهان از یک یا چند نورون تشکیل شده است . چندین دسته از شبکه های عصبی وجود دارد و این برنامه از یک شبکه عصبی متراکم یا کاملاً متصل استفاده می کند : سلول های عصبی در یک لایه اتصالات ورودی را از هر نورون در لایه قبلی دریافت می کنند. به عنوان مثال ، شکل 2 یک شبکه عصبی متراکم را متشکل از یک لایه ورودی ، دو لایه مخفی و یک لایه خروجی نشان می دهد:

نمودار معماری شبکه: ورودی ها ، 2 لایه پنهان و خروجی ها
شکل 2. یک شبکه عصبی با ویژگی ها ، لایه های پنهان و پیش بینی ها.

هنگامی که مدل از شکل 2 آموزش داده شود و به عنوان نمونه ای بدون برچسب تغذیه شود ، سه پیش بینی به دست می دهد: احتمال اینکه این گل از نوع عنبیه داده شده باشد. این پیش بینی استنباط نامیده می شود . برای این مثال ، مجموع پیش بینی های خروجی 1.0 است. در شکل 2 ، این پیش بینی به شرح زیر تقسیم می شود: 0.02 برای Iris setosa ، 0.95 برای Iris versicolor و 0.03 برای Iris virginica . این بدان معناست که مدل پیش بینی کرده است - با احتمال 95٪ - که یک گل نمونه بدون برچسب یک گیاه زنبق است .

با استفاده از کتابخانه آموزش عمیق Swift for TensorFlow مدلی ایجاد کنید

کتابخانه Swift for TensorFlow Deep Learning لایه های اولیه و قراردادهایی را برای سیم کشی آنها با هم تعریف می کند که ساخت مدل ها و آزمایش را آسان می کند.

یک مدل است struct است که مطابق با Layer ، به این معنی که آن را به یک تعریف callAsFunction(_:) روش که نقشه ورودی Tensor به خروجی S Tensor است. callAsFunction(_:) معمولاً ورودی را از طریق لایه های callAsFunction(_:) توالی می کند. بیایید یک IrisModel تعریف کنیم که ورودی را از طریق سه زیر لایه Dense توالی می کند.

import TensorFlow

let hiddenSize: Int = 10
struct IrisModel: Layer {
    var layer1 = Dense<Float>(inputSize: 4, outputSize: hiddenSize, activation: relu)
    var layer2 = Dense<Float>(inputSize: hiddenSize, outputSize: hiddenSize, activation: relu)
    var layer3 = Dense<Float>(inputSize: hiddenSize, outputSize: 3)

    @differentiable
    func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
        return input.sequenced(through: layer1, layer2, layer3)
    }
}

var model = IrisModel()

تابع فعال سازی شکل خروجی هر گره در لایه را تعیین می کند. این غیرخطی بودن مهم است - بدون آنها مدل معادل یک لایه است. تعداد زیادی فعال سازی در دسترس است ، اما ReLU برای لایه های پنهان معمول است.

تعداد ایده آل لایه ها و نورون های پنهان به مسئله و مجموعه داده بستگی دارد. مانند بسیاری از جنبه های یادگیری ماشینی ، انتخاب بهترین شکل شبکه عصبی نیاز به ترکیبی از دانش و آزمایش دارد. به عنوان یک قاعده کلی ، افزایش تعداد لایه های پنهان و نورون ها به طور معمول مدل قدرتمندتری ایجاد می کند که برای آموزش م trainثر به داده های بیشتری نیاز دارد.

با استفاده از مدل

بیایید نگاهی گذرا به آنچه این مدل با مجموعه ای از ویژگی ها انجام می دهد ، داشته باشیم:

// Apply the model to a batch of features.
let firstTrainPredictions = model(firstTrainFeatures)
firstTrainPredictions[0..<5]
[[ -0.8188498,   1.5179185,  -0.3823631],
 [ -0.8939362,   1.8654141,   -0.431251],
 [  -0.877989,   1.6670536, -0.37928653],
 [-0.62468827,   1.7252572,  -0.3766331],
 [-0.68565977,   2.0301576, -0.44697276]]

در اینجا ، هر مثال برای هر کلاس یک logit برمی گرداند.

برای تبدیل این logits به احتمال برای هر کلاس، استفاده از softmax تابع:

softmax(firstTrainPredictions[0..<5])
[[ 0.07754943,   0.8024614, 0.119989246],
 [ 0.05441314,   0.8591607,   0.0864262],
 [ 0.06497577,   0.8280362,  0.10698802],
 [ 0.07832983,   0.8212881, 0.100382075],
 [0.057515744,   0.8694633,   0.0730209]]

با توجه به argmax در بین کلاس ها ، شاخص کلاس پیش بینی شده به ما می دهد. اما ، این مدل هنوز آموزش داده نشده است ، بنابراین این پیش بینی های خوبی نیست.

print("Prediction: \(firstTrainPredictions.argmax(squeezingAxis: 1))")
print("    Labels: \(firstTrainLabels)")
Prediction: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    Labels: [1, 1, 1, 0, 0, 0, 0, 1, 2, 0, 2, 0, 1, 2, 0, 2, 1, 2, 2, 0, 0, 1, 0, 1, 0, 0, 2, 2, 0, 2, 0, 1]

مدل را آموزش دهید

آموزش مرحله یادگیری ماشین است که مدل به تدریج بهینه می شود ، یا مدل مجموعه داده را یاد می گیرد . هدف یادگیری کافی در مورد ساختار مجموعه داده های آموزشی برای پیش بینی داده های دیده نشده است. اگر بیش از حد در مورد مجموعه داده های آموزشی بیاموزید ، پیش بینی ها فقط برای داده هایی که دیده است کارساز هستند و قابل تعمیم نخواهند بود. به این مشکل ، نصب بیش از حد گفته می شود - این مانند یادآوری پاسخها به جای درک نحوه حل مسئله است.

مشکل طبقه بندی عنبیه نمونه ای از یادگیری ماشین تحت نظارت است : مدل از نمونه هایی که حاوی برچسب هستند آموزش داده می شود. در یادگیری ماشین بدون نظارت ، نمونه ها حاوی برچسب نیستند. در عوض ، مدل به طور معمول الگوهایی را در میان ویژگی ها پیدا می کند.

عملکرد ضرر را انتخاب کنید

هر دو مرحله آموزش و ارزیابی نیاز به محاسبه افت مدل دارند. این اندازه گیری میزان پیش بینی مدل از برچسب مورد نظر ، به عبارت دیگر ، عملکرد بد مدل را اندازه گیری می کند. ما می خواهیم این مقدار را به حداقل برسانیم یا بهینه کنیم.

مدل ما با استفاده از softmaxCrossEntropy(logits:labels:) که پیش بینی احتمال کلاس مدل و برچسب مورد نظر را می گیرد و میانگین افت را در بین مثال ها برمی گرداند ، ضرر خود را محاسبه می کند.

بیایید ضرر را برای مدل آموزش ندیده فعلی محاسبه کنیم:

let untrainedLogits = model(firstTrainFeatures)
let untrainedLoss = softmaxCrossEntropy(logits: untrainedLogits, labels: firstTrainLabels)
print("Loss test: \(untrainedLoss)")
Loss test: 1.8843782

یک بهینه ساز ایجاد کنید

یک بهینه ساز شیب های محاسبه شده را به متغیرهای مدل اعمال می کند تا عملکرد loss به حداقل برساند. شما می توانید عملکرد از دست دادن را به عنوان یک سطح منحنی در نظر بگیرید (شکل 3 را ببینید) و ما می خواهیم با راه رفتن در پایین ترین نقطه آن را پیدا کنیم. شیب ها در جهت شیب دارترین صعود قرار دارند - بنابراین ما مسیر مخالف را طی می کنیم و از تپه پایین می رویم. با محاسبه تکراری میزان افت و گرادیان برای هر دسته ، مدل را در حین آموزش تنظیم می کنیم. به تدریج ، این مدل بهترین ترکیب وزن و بایاس را برای به حداقل رساندن از دست دادن پیدا خواهد کرد. و هرچه ضرر کمتر باشد ، پیش بینی های مدل بهتر خواهد بود.

الگوریتم های بهینه سازی با گذشت زمان در فضای سه بعدی تجسم می شوند.
شکل 3. الگوریتم های بهینه سازی با گذشت زمان در فضای سه بعدی تجسم می شوند.
(منبع: کلاس استنفورد CS231n ، مجوز MIT ، اعتبار تصویر: الک ردفورد )

Swift for TensorFlow الگوریتم های بهینه سازی بسیاری برای آموزش در دسترس دارد. این مدل از بهینه ساز SGD استفاده می کند که الگوریتم نزول شیب تصادفی (SGD) را پیاده سازی می کند. learningRate مجموعه به اندازه گام به برای هر تکرار پایین تپه. این یک ابر پارامتر است که معمولاً برای دستیابی به نتایج بهتر آن را تنظیم می کنید.

let optimizer = SGD(for: model, learningRate: 0.01)

بیایید از optimizer برای برداشتن یک مرحله نزولی شیب دار استفاده کنیم. ابتدا شیب از دست دادن را با توجه به مدل محاسبه می کنیم:

let (loss, grads) = valueWithGradient(at: model) { model -> Tensor<Float> in
    let logits = model(firstTrainFeatures)
    return softmaxCrossEntropy(logits: logits, labels: firstTrainLabels)
}
print("Current loss: \(loss)")
Current loss: 1.8843782

بعد ، ما شیب را که فقط محاسبه کردیم ، به بهینه ساز منتقل می کنیم ، که متغیرهای قابل تغییر مدل را بر این اساس به روز می کند:

optimizer.update(&model, along: grads)

اگر دوباره ضرر را محاسبه کنیم ، باید کوچکتر باشد ، زیرا مراحل نزول شیب (معمولاً) ضرر را کاهش می دهد:

let logitsAfterOneStep = model(firstTrainFeatures)
let lossAfterOneStep = softmaxCrossEntropy(logits: logitsAfterOneStep, labels: firstTrainLabels)
print("Next loss: \(lossAfterOneStep)")
Next loss: 1.327492

حلقه آموزش

با در دست داشتن تمام قطعات ، مدل آماده آموزش است! یک حلقه آموزشی برای کمک به آن در پیش بینی بهتر ، نمونه های مجموعه داده را در مدل تغذیه می کند. بلوک کد زیر این مراحل آموزش را تنظیم می کند:

  1. هر دوره را تکرار کنید. دوره یک گذر از مجموعه داده است.
  2. در یک دوره ، در هر دوره در دوره آموزش تکرار کنید
  3. دسته را جمع کنید و ویژگی های آن ( x ) و برچسب ( y ) را بگیرید.
  4. با استفاده از ویژگی های دسته بندی شده ، پیش بینی کرده و آن را با برچسب مقایسه کنید. عدم صحت پیش بینی را اندازه گیری کنید و از آن برای محاسبه افت و شیب مدل استفاده کنید.
  5. برای به روزرسانی متغیرهای مدل از نزولی شیب دار استفاده کنید.
  6. برخی از آمارها را برای تجسم ثبت کنید.
  7. برای هر دوره تکرار کنید.

متغیر epochCount تعداد دفعات مراجعه به مجموعه داده است. خلاف بصری ، آموزش بیشتر یک مدل الگوی بهتر را تضمین نمی کند. epochCount است hyperparameter که شما می توانید تنظیم. انتخاب عدد مناسب معمولاً به تجربه و آزمایش نیاز دارد.

let epochCount = 500
var trainAccuracyResults: [Float] = []
var trainLossResults: [Float] = []
func accuracy(predictions: Tensor<Int32>, truths: Tensor<Int32>) -> Float {
    return Tensor<Float>(predictions .== truths).mean().scalarized()
}

for (epochIndex, epoch) in trainingEpochs.prefix(epochCount).enumerated() {
    var epochLoss: Float = 0
    var epochAccuracy: Float = 0
    var batchCount: Int = 0
    for batchSamples in epoch {
        let batch = batchSamples.collated
        let (loss, grad) = valueWithGradient(at: model) { (model: IrisModel) -> Tensor<Float> in
            let logits = model(batch.features)
            return softmaxCrossEntropy(logits: logits, labels: batch.labels)
        }
        optimizer.update(&model, along: grad)

        let logits = model(batch.features)
        epochAccuracy += accuracy(predictions: logits.argmax(squeezingAxis: 1), truths: batch.labels)
        epochLoss += loss.scalarized()
        batchCount += 1
    }
    epochAccuracy /= Float(batchCount)
    epochLoss /= Float(batchCount)
    trainAccuracyResults.append(epochAccuracy)
    trainLossResults.append(epochLoss)
    if epochIndex % 50 == 0 {
        print("Epoch \(epochIndex): Loss: \(epochLoss), Accuracy: \(epochAccuracy)")
    }
}
Epoch 0: Loss: 1.2097169, Accuracy: 0.4375
Epoch 50: Loss: 0.52431935, Accuracy: 0.875
Epoch 100: Loss: 0.3710712, Accuracy: 0.8958333
Epoch 150: Loss: 0.2160871, Accuracy: 0.9583333
Epoch 200: Loss: 0.14524944, Accuracy: 0.9791667
Epoch 250: Loss: 0.12487585, Accuracy: 0.9583333
Epoch 300: Loss: 0.122261345, Accuracy: 0.9791667
Epoch 350: Loss: 0.10571604, Accuracy: 0.9895833
Epoch 400: Loss: 0.09489065, Accuracy: 0.9791667
Epoch 450: Loss: 0.09057075, Accuracy: 0.9895833

به مرور زمان عملکرد ضرر را تجسم کنید

در حالی که این برای چاپ کردن پیشرفت آموزشی مدل های مفید، آن را اغلب مفید تر برای دیدن این پیشرفت است. ما می توانیم نمودارهای اساسی را با استفاده از ماژول matplotlib پایتون ایجاد کنیم.

تفسیر این نمودارها به تجربه خاصی نیاز دارد ، اما شما واقعاً می خواهید که ضرر کاهش یافته و دقت بالا می رود.

plt.figure(figsize: [12, 8])

let accuracyAxes = plt.subplot(2, 1, 1)
accuracyAxes.set_ylabel("Accuracy")
accuracyAxes.plot(trainAccuracyResults)

let lossAxes = plt.subplot(2, 1, 2)
lossAxes.set_ylabel("Loss")
lossAxes.set_xlabel("Epoch")
lossAxes.plot(trainLossResults)

plt.show()

png

None

توجه داشته باشید که محورهای y نمودارها صفر نیستند.

اثربخشی مدل را ارزیابی کنید

اکنون که این مدل آموزش دیده است ، می توانیم آماری از عملکرد آن بدست آوریم.

ارزیابی به معنای تعیین میزان تأثیرگذاری مدل در پیش بینی است. برای تعیین اثربخشی مدل در طبقه بندی عنبیه ، برخی از اندازه گیریهای گلبرگ و گلبرگ را به مدل منتقل کنید و از مدل بخواهید پیش بینی کند که کدام گونه عنبیه را نشان می دهد. سپس پیش بینی مدل را با برچسب واقعی مقایسه کنید. به عنوان مثال ، مدلی که گونه های صحیح را در نیمی از نمونه های ورودی انتخاب کرده است ، دارای دقت 0.5 . شکل 4 یک مدل کمی موثرتر را نشان می دهد ، از هر 5 پیش بینی 4 با صحت 80٪ درست است:

ویژگی های نمونه برچسب پیش بینی مدل
5.9 3.0 4.3 1.5 1 1
6.9 3.1 5.4 2.1 2 2
5.1 3.3 1.7 0.5 0 0
6.0 3.4 4.5 1.6 1 2
5.5 2.5 4.0 1.3 1 1
شکل 4. طبقه بندی عنبیه که 80٪ دقیق است.

مجموعه داده آزمون را تنظیم کنید

ارزیابی مدل مشابه آموزش مدل است. بزرگترین تفاوت در این است که نمونه ها از یک مجموعه آزمون جداگانه به جای مجموعه آموزش آمده اند. برای ارزیابی منصفانه اثر بخشی یک مدل ، مثالهایی که برای ارزیابی یک مدل استفاده می شود باید با نمونه های مورد استفاده برای آموزش مدل متفاوت باشد.

تنظیم برای مجموعه داده آزمون مشابه تنظیم برای مجموعه داده آموزش است. مجموعه آزمون را از http://download.tensorflow.org/data/iris_test.csv بارگیری کنید:

let testDataFilename = "iris_test.csv"
download(from: "http://download.tensorflow.org/data/iris_test.csv", to: testDataFilename)

اکنون آن را در آرایه ای از IrisBatch :

let testDataset = loadIrisDatasetFromCSV(
    contentsOf: testDataFilename, hasHeader: true,
    featureColumns: [0, 1, 2, 3], labelColumns: [4]).inBatches(of: batchSize)

مدل را بر روی مجموعه داده های آزمون ارزیابی کنید

برخلاف مرحله آموزش ، مدل فقط یک دوره از داده های آزمون را ارزیابی می کند. در سلول کد زیر ، ما در مورد هر نمونه از مجموعه آزمایش تکرار می کنیم و پیش بینی مدل را با برچسب واقعی مقایسه می کنیم. این برای اندازه گیری دقت مدل در کل مجموعه آزمایش استفاده می شود.

// NOTE: Only a single batch will run in the loop since the batchSize we're using is larger than the test set size
for batchSamples in testDataset {
    let batch = batchSamples.collated
    let logits = model(batch.features)
    let predictions = logits.argmax(squeezingAxis: 1)
    print("Test batch accuracy: \(accuracy(predictions: predictions, truths: batch.labels))")
}
Test batch accuracy: 0.96666664

می توانیم در دسته اول ببینیم ، به عنوان مثال ، مدل معمولاً صحیح است:

let firstTestBatch = testDataset.first!.collated
let firstTestBatchLogits = model(firstTestBatch.features)
let firstTestBatchPredictions = firstTestBatchLogits.argmax(squeezingAxis: 1)

print(firstTestBatchPredictions)
print(firstTestBatch.labels)
[1, 2, 0, 1, 1, 1, 0, 2, 1, 2, 2, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 1, 2, 2, 1, 1, 0, 1, 2, 1]
[1, 2, 0, 1, 1, 1, 0, 2, 1, 2, 2, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 1, 2, 1, 1, 1, 0, 1, 2, 1]

از مدل آموزش دیده برای پیش بینی استفاده کنید

ما یک مدل را آموزش داده ایم و نشان داده ایم که در طبقه بندی گونه های عنبیه خوب است - اما عالی نیست. حال بیایید از مدل آموزش دیده برای پیش بینی نمونه های غیر برچسب استفاده کنیم . یعنی روی نمونه هایی که حاوی ویژگی هستند اما برچسب ندارند.

در زندگی واقعی ، نمونه های بدون برچسب می توانند از منابع مختلفی از جمله برنامه ها ، پرونده های CSV و فیدهای داده تهیه شوند. در حال حاضر ، ما می خواهیم سه نمونه بدون برچسب را به طور دستی برای پیش بینی برچسب های آنها ارائه دهیم. به یاد بیاورید ، شماره های برچسب به نمایندگی نامگذاری شده به شرح زیر است:

  • 0 : آیریس ستوسا
  • 1 : زنبق عنكبوت
  • 2 : Iris virginica
let unlabeledDataset: Tensor<Float> =
    [[5.1, 3.3, 1.7, 0.5],
     [5.9, 3.0, 4.2, 1.5],
     [6.9, 3.1, 5.4, 2.1]]

let unlabeledDatasetPredictions = model(unlabeledDataset)

for i in 0..<unlabeledDatasetPredictions.shape[0] {
    let logits = unlabeledDatasetPredictions[i]
    let classIdx = logits.argmax().scalar!
    print("Example \(i) prediction: \(classNames[Int(classIdx)]) (\(softmax(logits)))")
}
Example 0 prediction: Iris setosa ([    0.9872727,  0.0124736205, 0.00025379486])
Example 1 prediction: Iris versicolor ([0.0026452888,     0.973102,  0.024252668])
Example 2 prediction: Iris virginica ([9.066205e-05,    0.0736953,    0.9262141])