Trang này được dịch bởi Cloud Translation API.
Switch to English

Hướng dẫn đào tạo mô hình

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub

Hướng dẫn này giới thiệu Swift cho TensorFlow bằng cách xây dựng mô hình máy học phân loại hoa iris theo loài. Nó sử dụng Swift cho TensorFlow để:

  1. Xây dựng một mô hình,
  2. Đào tạo mô hình này dựa trên dữ liệu mẫu và
  3. Sử dụng mô hình để đưa ra dự đoán về dữ liệu chưa biết.

Lập trình TensorFlow

Hướng dẫn này sử dụng các khái niệm Swift cấp cao cho TensorFlow:

  • Nhập dữ liệu bằng API Epochs.
  • Xây dựng mô hình bằng cách sử dụng Swift trừu tượng.
  • Sử dụng thư viện Python bằng khả năng tương tác Python của Swift khi các thư viện Swift thuần túy không khả dụng.

Hướng dẫn này có cấu trúc giống như nhiều chương trình TensorFlow:

  1. Nhập và phân tích cú pháp các tập dữ liệu.
  2. Chọn loại mô hình.
  3. Huấn luyện mô hình.
  4. Đánh giá hiệu quả của mô hình.
  5. Sử dụng mô hình được đào tạo để đưa ra dự đoán.

Thiết lập chương trình

Định cấu hình nhập khẩu

Nhập TensorFlow và một số mô-đun Python hữu ích.

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)
}

Vấn đề phân loại mống mắt

Hãy tưởng tượng bạn là một nhà thực vật học đang tìm kiếm một cách tự động để phân loại từng bông hoa diên vĩ mà bạn tìm thấy. Máy học cung cấp nhiều thuật toán để phân loại hoa theo thống kê. Ví dụ, một chương trình máy học tinh vi có thể phân loại hoa dựa trên các bức ảnh. Tham vọng của chúng tôi khiêm tốn hơn — chúng tôi sẽ phân loại hoa iris dựa trên số đo chiều dài và chiều rộng của các đài hoacánh hoa của chúng .

Chi Iris có khoảng 300 loài, nhưng chương trình của chúng tôi sẽ chỉ phân loại ba loài sau:

  • Iris setosa
  • Iris virginica
  • Iris versicolor
Hình dạng cánh hoa được so sánh cho ba loài iris: Iris setosa, Iris virginica và Iris versicolor
Hình 1. Iris setosa (bởi Radomil , CC BY-SA 3.0), Iris versicolor , (bởi Dlanglois , CC BY-SA 3.0) và Iris virginica (bởi Frank Mayfield , CC BY-SA 2.0).

May mắn thay, ai đó đã tạo ra một bộ dữ liệu gồm 120 bông hoa iris với số đo đài hoa và cánh hoa. Đây là tập dữ liệu cổ điển phổ biến cho các bài toán phân loại học máy mới bắt đầu.

Nhập và phân tích cú pháp tập dữ liệu đào tạo

Tải xuống tệp tập dữ liệu và chuyển đổi nó thành một cấu trúc có thể được sử dụng bởi chương trình Swift này.

Tải xuống tập dữ liệu

Tải xuống tệp tập dữ liệu đào tạo từ 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)

Kiểm tra dữ liệu

Tập dữ liệu này, iris_training.csv , là một tệp văn bản thuần túy lưu trữ dữ liệu dạng bảng được định dạng dưới dạng các giá trị được phân tách bằng dấu phẩy (CSV). Hãy xem xét 5 mục đầu tiên.

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

Từ chế độ xem này của tập dữ liệu, hãy lưu ý những điều sau:

  1. Dòng đầu tiên là tiêu đề chứa thông tin về tập dữ liệu:
    • Có tổng cộng 120 ví dụ. Mỗi ví dụ có bốn tính năng và một trong ba tên nhãn có thể có.
  2. Các hàng tiếp theo là các bản ghi dữ liệu, một ví dụ trên mỗi dòng, trong đó:
    • Bốn trường đầu tiên là các tính năng : đây là các đặc điểm của một ví dụ. Ở đây, các trường chứa số thực thể hiện số đo hoa.
    • Cột cuối cùng là nhãn : đây là giá trị chúng ta muốn dự đoán. Đối với tập dữ liệu này, đó là một giá trị nguyên 0, 1 hoặc 2 tương ứng với tên hoa.

Hãy viết điều đó ra mã:

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

Mỗi nhãn được liên kết với tên chuỗi (ví dụ: "setosa"), nhưng học máy thường dựa vào các giá trị số. Các số nhãn được ánh xạ tới một đại diện được đặt tên, chẳng hạn như:

  • 0 : Iris setosa
  • 1 : Màu mống mắt
  • 2 : Iris virginica

Để biết thêm thông tin về các tính năng và nhãn, hãy xem phần Thuật ngữ ML của Khóa học về sự cố học máy .

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

Tạo tập dữ liệu bằng API Epochs

Swift for TensorFlow's Epoch API là một API cấp cao để đọc dữ liệu và chuyển đổi nó thành một biểu mẫu được sử dụng để đào tạo.

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})
    }
}

Vì các tập dữ liệu chúng tôi đã tải xuống ở định dạng CSV, hãy viết một hàm để tải dữ liệu dưới dạng danh sách các đối tượng 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)}

    }

Bây giờ chúng ta có thể sử dụng chức năng tải CSV để tải tập dữ liệu đào tạo và tạo đối tượng TrainingEpochs

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

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

Đối tượng TrainingEpochs là một chuỗi các kỷ nguyên vô hạn. Mỗi kỷ nguyên chứa các IrisBatch es. Hãy xem xét yếu tố đầu tiên của kỷ nguyên đầu tiên.

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]

Lưu ý rằng các tính năng cho các ví dụ batchSize đầu tiên được nhóm lại với nhau (hoặc theo ) thành firstTrainFeatures và các nhãn cho các ví dụ batchSize đầu tiên được batchSize vào firstTrainLabels .

Bạn có thể bắt đầu thấy một số cụm bằng cách vẽ một vài tính năng từ lô, sử dụng matplotlib của Python:

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

Chọn loại mô hình

Tại sao mô hình?

Mô hình là mối quan hệ giữa các tính năng và nhãn. Đối với bài toán phân loại mống mắt, mô hình xác định mối quan hệ giữa các phép đo đài hoa và cánh hoa và các loài mống mắt được dự đoán. Một số mô hình đơn giản có thể được mô tả bằng một vài dòng đại số, nhưng các mô hình học máy phức tạp có một số lượng lớn các tham số rất khó để tóm tắt.

Bạn có thể xác định mối quan hệ giữa bốn đặc điểm và loài mống mắt mà không sử dụng máy học không? Đó là, bạn có thể sử dụng các kỹ thuật lập trình truyền thống (ví dụ, rất nhiều câu lệnh điều kiện) để tạo một mô hình không? Có lẽ — nếu bạn đã phân tích tập dữ liệu đủ lâu để xác định mối quan hệ giữa các phép đo cánh hoa và lá đài đối với một loài cụ thể. Và điều này trở nên khó khăn - có thể là không thể - trên các bộ dữ liệu phức tạp hơn. Một cách tiếp cận máy học tốt sẽ xác định mô hình cho bạn . Nếu bạn cung cấp đủ các ví dụ đại diện vào loại mô hình học máy phù hợp, chương trình sẽ tìm ra các mối quan hệ cho bạn.

Chọn mô hình

Chúng ta cần chọn loại mô hình để đào tạo. Có nhiều loại mô hình và chọn một mô hình tốt cần có kinh nghiệm. Hướng dẫn này sử dụng mạng nơ-ron để giải quyết vấn đề phân loại mống mắt. Mạng nơron có thể tìm thấy các mối quan hệ phức tạp giữa các tính năng và nhãn. Nó là một biểu đồ có cấu trúc cao, được tổ chức thành một hoặc nhiều lớp ẩn . Mỗi lớp ẩn bao gồm một hoặc nhiều nơ-ron . Có một số loại mạng nơ-ron và chương trình này sử dụng một mạng nơ-ron dày đặc, hoặc được kết nối đầy đủ : các nơ-ron trong một lớp nhận các kết nối đầu vào từ mọi nơ-ron trong lớp trước đó. Ví dụ, Hình 2 minh họa một mạng nơ-ron dày đặc bao gồm một lớp đầu vào, hai lớp ẩn và một lớp đầu ra:

Sơ đồ kiến ​​trúc mạng: Đầu vào, 2 lớp ẩn và đầu ra
Hình 2. Một mạng nơ-ron với các tính năng, lớp ẩn và dự đoán.

Khi mô hình từ Hình 2 được huấn luyện và cung cấp một ví dụ không gắn nhãn, nó sẽ đưa ra ba dự đoán: khả năng bông hoa này là loài hoa diên vĩ đã cho. Dự đoán này được gọi là suy luận . Đối với ví dụ này, tổng các dự đoán đầu ra là 1,0. Trong Hình 2, dự đoán này được chia thành: 0.02 cho Iris setosa , 0.95 cho Iris versicolor0.03 cho Iris virginica . Điều này có nghĩa là mô hình dự đoán - với xác suất 95% - rằng một bông hoa mẫu không được dán nhãn là một loài hoa có màu Iris .

Tạo một mô hình bằng Swift for TensorFlow Deep Learning Library

Thư viện học sâu Swift cho TensorFlow xác định các lớp và quy ước nguyên thủy để kết nối chúng với nhau, giúp dễ dàng xây dựng mô hình và thử nghiệm.

Mô hình là một struct tuân theo Layer , có nghĩa là nó định nghĩa một phương thức callAsFunction(_:) ánh xạ các Tensor đầu vào đến Tensor đầu ra. Phương thức callAsFunction(_:) thường đơn giản trình tự đầu vào thông qua các lớp con. Hãy xác định một IrisModel trình tự đầu vào thông qua ba lớp con 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()

Hàm kích hoạt xác định hình dạng đầu ra của mỗi nút trong lớp. Những điểm phi tuyến tính này rất quan trọng — nếu không có chúng, mô hình sẽ tương đương với một lớp duy nhất. Có rất nhiều kích hoạt có sẵn, nhưng ReLU là phổ biến cho các lớp ẩn.

Số lượng lớp ẩn và tế bào thần kinh lý tưởng phụ thuộc vào vấn đề và tập dữ liệu. Giống như nhiều khía cạnh của học máy, việc chọn ra hình dạng tốt nhất của mạng nơ-ron đòi hỏi sự kết hợp giữa kiến ​​thức và thử nghiệm. Theo quy luật chung, việc tăng số lượng lớp ẩn và tế bào thần kinh thường tạo ra một mô hình mạnh mẽ hơn, đòi hỏi nhiều dữ liệu hơn để đào tạo hiệu quả.

Sử dụng mô hình

Chúng ta hãy xem nhanh những gì mô hình này làm với một loạt các tính năng:

// 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]]

Ở đây, mỗi ví dụ trả về một logit cho mỗi lớp.

Để chuyển đổi các logits này thành xác suất cho mỗi lớp, hãy sử dụng hàm 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]]

Lấy argmax qua các lớp cho chúng ta chỉ số lớp được dự đoán. Tuy nhiên, mô hình vẫn chưa được đào tạo, vì vậy đây không phải là những dự đoán tốt.

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]

Đào tạo mô hình

Đào tạo là giai đoạn học máy khi mô hình được tối ưu hóa dần dần, hoặc mô hình học tập dữ liệu. Mục tiêu là tìm hiểu đủ về cấu trúc của tập dữ liệu đào tạo để đưa ra dự đoán về dữ liệu không nhìn thấy. Nếu bạn tìm hiểu quá nhiều về tập dữ liệu đào tạo, thì các dự đoán chỉ hoạt động đối với dữ liệu mà nó đã thấy và sẽ không thể tổng quát hóa được. Vấn đề này được gọi là overfitting — nó giống như ghi nhớ các câu trả lời thay vì hiểu cách giải quyết một vấn đề.

Bài toán phân loại mống mắt là một ví dụ về học máy có giám sát : mô hình được đào tạo từ các ví dụ có chứa nhãn. Trong học máy không giám sát , các ví dụ không chứa nhãn. Thay vào đó, mô hình thường tìm thấy các mẫu trong số các tính năng.

Chọn một chức năng mất mát

Cả hai giai đoạn đào tạo và đánh giá đều cần tính toán sự mất mát của mô hình. Điều này đo lường mức độ dự đoán của mô hình khác với nhãn mong muốn, nói cách khác, mô hình hoạt động tồi tệ như thế nào. Chúng tôi muốn giảm thiểu hoặc tối ưu hóa giá trị này.

Mô hình của chúng tôi sẽ tính toán tổn thất của nó bằng cách sử dụng hàm softmaxCrossEntropy(logits:labels:) lấy các dự đoán xác suất lớp của mô hình và nhãn mong muốn và trả về tổn thất trung bình trên các ví dụ.

Hãy tính toán khoản lỗ cho mô hình chưa được đào tạo hiện tại:

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

Tạo một trình tối ưu hóa

Trình tối ưu hóa áp dụng các gradient được tính toán cho các biến của mô hình để giảm thiểu hàm loss . Bạn có thể coi hàm mất mát như một mặt cong (xem Hình 3) và chúng ta muốn tìm điểm thấp nhất của nó bằng cách đi vòng quanh. Các gradient hướng theo hướng đi lên dốc nhất — vì vậy chúng ta sẽ đi theo hướng ngược lại và di chuyển xuống đồi. Bằng cách tính toán lặp đi lặp lại tổn thất và độ dốc cho từng lô, chúng tôi sẽ điều chỉnh mô hình trong quá trình đào tạo. Dần dần, mô hình sẽ tìm ra sự kết hợp tốt nhất giữa trọng lượng và độ lệch để giảm thiểu sự mất mát. Và tổn thất càng thấp, dự đoán của mô hình càng tốt.

Các thuật toán tối ưu hóa được hiển thị theo thời gian trong không gian 3D.
Hình 3. Các thuật toán tối ưu hóa được hiển thị theo thời gian trong không gian 3D.
(Nguồn: Stanford lớp CS231n , Giấy phép MIT, Tín dụng hình ảnh: Alec Radford )

Swift for TensorFlow có nhiều thuật toán tối ưu hóa có sẵn để đào tạo. Mô hình này sử dụng trình tối ưu hóa SGD triển khai thuật toán giảm độ dốc ngẫu nhiên (SGD). learningRate đặt kích thước bước cần thực hiện cho mỗi lần lặp xuống đồi. Đây là một siêu thông số mà bạn sẽ thường điều chỉnh để đạt được kết quả tốt hơn.

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

Hãy sử dụng trình optimizer để thực hiện một bước giảm độ dốc duy nhất. Đầu tiên, chúng tôi tính toán gradient của sự mất mát đối với mô hình:

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

Tiếp theo, chúng tôi chuyển gradient mà chúng tôi vừa tính toán đến trình tối ưu hóa, công cụ này sẽ cập nhật các biến có thể phân biệt của mô hình cho phù hợp:

optimizer.update(&model, along: grads)

Nếu chúng ta tính toán tổn thất một lần nữa, nó phải nhỏ hơn, bởi vì các bước giảm dần độ dốc (thường) làm giảm tổn thất:

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

Vòng lặp đào tạo

Với tất cả các mảnh ở vị trí, mô hình đã sẵn sàng để đào tạo! Vòng huấn luyện cung cấp các ví dụ về tập dữ liệu vào mô hình để giúp mô hình đưa ra dự đoán tốt hơn. Khối mã sau thiết lập các bước đào tạo sau:

  1. Lặp lại từng kỷ nguyên . Một kỷ nguyên là một lần đi qua tập dữ liệu.
  2. Trong một kỷ nguyên, hãy lặp lại từng đợt trong kỷ nguyên đào tạo
  3. Đối chiếu lô và lấy các đặc điểm của nó ( x ) và nhãn ( y ).
  4. Sử dụng các tính năng của lô được đối chiếu, đưa ra dự đoán và so sánh với nhãn. Đo lường mức độ không chính xác của dự đoán và sử dụng nó để tính toán độ mất và độ dốc của mô hình.
  5. Sử dụng gradient descent để cập nhật các biến của mô hình.
  6. Theo dõi một số thống kê để dễ hình dung.
  7. Lặp lại cho mỗi kỷ nguyên.

Biến epochCount là số lần lặp qua tập hợp dữ liệu. Theo trực giác, đào tạo một mô hình lâu hơn không đảm bảo một mô hình tốt hơn. epochCount là một siêu thông số mà bạn có thể điều chỉnh. Việc chọn đúng số thường cần cả kinh nghiệm và thử nghiệm.

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

Hình dung hàm mất mát theo thời gian

Mặc dù việc in ra tiến trình đào tạo của mô hình là hữu ích, nhưng việc xem tiến trình này thường hữu ích hơn . Chúng ta có thể tạo các biểu đồ cơ bản bằng cách sử dụng mô-đun matplotlib của Python.

Việc diễn giải các biểu đồ này cần một số kinh nghiệm, nhưng bạn thực sự muốn thấy khoản lỗ giảm xuống và độ chính xác tăng lên.

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

Lưu ý rằng trục y của đồ thị không dựa trên 0.

Đánh giá hiệu quả của mô hình

Bây giờ mô hình đã được đào tạo, chúng tôi có thể nhận được một số thống kê về hiệu suất của nó.

Đánh giá có nghĩa là xác định mức độ hiệu quả của mô hình đưa ra các dự đoán. Để xác định hiệu quả của mô hình trong việc phân loại mống mắt, hãy chuyển một số phép đo đài hoa và cánh hoa cho mô hình và yêu cầu mô hình dự đoán loài mống mắt mà chúng đại diện. Sau đó, so sánh dự đoán của mô hình với nhãn thực tế. Ví dụ, một mô hình đã chọn đúng loài trên một nửa số ví dụ đầu vào có độ chính xác0.5 . Hình 4 cho thấy một mô hình hiệu quả hơn một chút, có 4 trong số 5 dự đoán đúng với độ chính xác 80%:

Các tính năng ví dụ Nhãn Dự đoán mô hình
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
Hình 4. Máy phân loại mống mắt có độ chính xác 80%.

Thiết lập tập dữ liệu thử nghiệm

Đánh giá mô hình tương tự như đào tạo mô hình. Sự khác biệt lớn nhất là các ví dụ đến từ một tập thử nghiệm riêng biệt chứ không phải tập huấn luyện. Để đánh giá một cách công bằng hiệu quả của một mô hình, các ví dụ được sử dụng để đánh giá một mô hình phải khác với các ví dụ được sử dụng để đào tạo mô hình.

Thiết lập cho tập dữ liệu kiểm tra tương tự như thiết lập cho tập dữ liệu đào tạo. Tải xuống bộ thử nghiệm từ 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)

Bây giờ hãy tải nó vào một mảng IrisBatch es:

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

Đánh giá mô hình trên tập dữ liệu thử nghiệm

Không giống như giai đoạn đào tạo, mô hình chỉ đánh giá một kỷ nguyên duy nhất của dữ liệu thử nghiệm. Trong ô mã sau, chúng tôi lặp lại từng ví dụ trong bộ thử nghiệm và so sánh dự đoán của mô hình với nhãn thực tế. Điều này được sử dụng để đo độ chính xác của mô hình trên toàn bộ bộ thử nghiệm.

// 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

Ví dụ, chúng ta có thể thấy ở lô đầu tiên, mô hình thường đúng:

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]

Sử dụng mô hình được đào tạo để đưa ra dự đoán

Chúng tôi đã đào tạo một mô hình và chứng minh rằng nó tốt - nhưng không hoàn hảo - trong việc phân loại các loài mống mắt. Bây giờ, hãy sử dụng mô hình đã đào tạo để đưa ra một số dự đoán về các ví dụ không được gắn nhãn ; nghĩa là, trên các ví dụ có chứa các tính năng nhưng không chứa nhãn.

Trong thực tế, các ví dụ không được gắn nhãn có thể đến từ nhiều nguồn khác nhau, bao gồm ứng dụng, tệp CSV và nguồn cấp dữ liệu. Hiện tại, chúng tôi sẽ cung cấp thủ công ba ví dụ không được gắn nhãn để dự đoán nhãn của chúng. Nhớ lại, các số nhãn được ánh xạ tới một biểu diễn được đặt tên là:

  • 0 : Iris setosa
  • 1 : Màu mống mắt
  • 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])