![]() | ![]() | ![]() |
このガイドでは、アイリスの花を種ごとに分類する機械学習モデルを構築することにより、Swift forTensorFlowを紹介します。 Swift forTensorFlowを使用して次のことを行います。
- モデルを構築し、
- サンプルデータでこのモデルをトレーニングし、
- モデルを使用して、未知のデータに関する予測を行います。
TensorFlowプログラミング
このガイドでは、TensorFlowの概念に次の高レベルのSwiftを使用しています。
- EpochsAPIを使用してデータをインポートします。
- Swift抽象化を使用してモデルを構築します。
- 純粋なSwiftライブラリが利用できない場合は、SwiftのPython相互運用性を使用してPythonライブラリを使用してください。
このチュートリアルは、多くのTensorFlowプログラムのように構成されています。
- データセットをインポートして解析します。
- モデルのタイプを選択します。
- モデルをトレーニングします。
- モデルの有効性を評価します。
- トレーニング済みモデルを使用して予測を行います。
セットアッププログラム
インポートを構成する
TensorFlowといくつかの便利なPythonモジュールをインポートします。
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"
print(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)
}
アイリス分類問題
あなたが見つけた各アイリスの花を分類する自動化された方法を探している植物学者であると想像してください。機械学習は、花を統計的に分類するための多くのアルゴリズムを提供します。たとえば、高度な機械学習プログラムでは、写真に基づいて花を分類できます。私たちの野心はもっと控えめです—がく片と花びらの長さと幅の測定値に基づいてアヤメの花を分類します。
アイリス属には約300種が含まれますが、私たちのプログラムでは次の3つのみを分類します。
- アイリスセトサ
- アイリスバージニカ
- アイリス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())
}
print(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
データセットのこのビューから、次のことに注意してください。
- 最初の行は、データセットに関する情報を含むヘッダーです。
- 合計120の例があります。各例には、4つの機能と、3つの可能なラベル名の1つがあります。
- 後続の行はデータレコードであり、1行に1つの例があります。ここで、
それをコードで書きましょう:
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
:アイリスバージニカ
機能とラベルの詳細については、機械学習クラッシュコースの「 ML用語」セクションを参照してください。
let classNames = ["Iris setosa", "Iris versicolor", "Iris virginica"]
EpochsAPIを使用してデータセットを作成します
Swift forTensorFlowのEpochsAPIは、データを読み取り、トレーニングに使用される形式に変換するための高レベル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形式なので、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読み込み関数を使用して、トレーニングデータセットを読み込み、 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.1, 2.5, 3.0, 1.1], [6.4, 3.2, 4.5, 1.5], [4.9, 3.1, 1.5, 0.1], [5.0, 2.0, 3.5, 1.0], [6.3, 2.5, 5.0, 1.9], [6.7, 3.1, 5.6, 2.4], [4.9, 3.1, 1.5, 0.1], [7.7, 2.8, 6.7, 2.0], [6.7, 3.0, 5.0, 1.7], [7.2, 3.6, 6.1, 2.5], [4.8, 3.0, 1.4, 0.1], [5.2, 3.4, 1.4, 0.2], [5.0, 3.5, 1.3, 0.3], [4.9, 3.1, 1.5, 0.1], [5.0, 3.5, 1.6, 0.6], [6.7, 3.3, 5.7, 2.1], [7.7, 3.8, 6.7, 2.2], [6.2, 3.4, 5.4, 2.3], [4.8, 3.4, 1.6, 0.2], [6.0, 2.9, 4.5, 1.5], [5.0, 3.0, 1.6, 0.2], [6.3, 3.4, 5.6, 2.4], [5.1, 3.8, 1.9, 0.4], [4.8, 3.1, 1.6, 0.2], [7.6, 3.0, 6.6, 2.1], [5.7, 3.0, 4.2, 1.2], [6.3, 3.3, 6.0, 2.5], [5.6, 2.5, 3.9, 1.1], [5.0, 3.4, 1.6, 0.4], [6.1, 3.0, 4.9, 1.8], [5.0, 3.3, 1.4, 0.2], [6.3, 3.3, 4.7, 1.6]] firstTrainFeatures.shape: [32, 4] First batch of labels: [1, 1, 0, 1, 2, 2, 0, 2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 0, 2, 0, 0, 2, 1, 2, 1, 0, 2, 0, 1] firstTrainLabels.shape: [32]
最初のために機能することを通知batchSize
例としては、一緒にグループ化(またはバッチ)にさfirstTrainFeatures
、最初のラベルことbatchSize
例はにバッチ処理さfirstTrainLabels
。
Pythonの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()
Use `print()` to show values.
モデルのタイプを選択します
なぜモデル化するのですか?
モデルは、機能とラベルの間の関係です。虹彩分類問題の場合、モデルはがく片と花びらの測定値と予測される虹彩種との関係を定義します。いくつかの単純なモデルは数行の代数で記述できますが、複雑な機械学習モデルには、要約するのが難しい多数のパラメーターがあります。
機械学習を使用せずに、4つの特徴と虹彩種の関係を判断できますか?つまり、従来のプログラミング手法(たとえば、多くの条件文)を使用してモデルを作成できますか?おそらく、特定の種に対する花びらとがく片の測定値の関係を判断するのに十分な長さのデータセットを分析した場合。そして、これは、より複雑なデータセットでは困難になり、おそらく不可能になります。優れた機械学習アプローチにより、モデルが決まります。適切な機械学習モデルタイプに十分な代表的な例を入力すると、プログラムが関係を把握します。
モデルを選択します
トレーニングするモデルの種類を選択する必要があります。モデルには多くの種類があり、良いものを選ぶには経験が必要です。このチュートリアルでは、ニューラルネットワークを使用して虹彩分類の問題を解決します。ニューラルネットワークは、機能とラベルの間の複雑な関係を見つけることができます。これは高度に構造化されたグラフであり、1つ以上の非表示レイヤーに編成されています。各隠れ層は、1つ以上のニューロンで構成されます。ニューラルネットワークにはいくつかのカテゴリがあり、このプログラムは高密度または完全に接続されたニューラルネットワークを使用します。1つの層のニューロンは、前の層のすべてのニューロンから入力接続を受け取ります。たとえば、図2は、入力層、2つの隠れ層、および出力層で構成される高密度ニューラルネットワークを示しています。
![]() |
図2.機能、隠れ層、および予測を備えたニューラルネットワーク。 |
図2のモデルがトレーニングされ、ラベルのない例が与えられると、3つの予測が得られます。この花が特定の虹彩種である可能性です。この予測は推論と呼ばれます。この例では、出力予測の合計は1.0です。図2において、この予測のようなブレークダウン: 0.02
ヒオウギアヤメのために、 0.95
アイリスversicolorのため、および0.03
アイリスvirginicaのため。モデルが予測-ていることを95%の確率という非標識の例の花はアイリスversicolorのである。この手段。
Swift forTensorFlowディープラーニングライブラリを使用してモデルを作成します
Swift for TensorFlowディープラーニングライブラリは、プリミティブレイヤーとそれらを相互に接続するための規則を定義します。これにより、モデルの構築と実験が簡単になります。
モデルは、 Layer
に準拠するstruct
です。つまり、入力Tensor
を出力Tensor
マップするcallAsFunction(_:)
メソッドを定義します。 callAsFunction(_:)
メソッドは、多くの場合、サブレイヤーを介して入力を単純にシーケンスします。 3つのDense
サブレイヤーを介して入力をシーケンスするIrisModel
を定義しましょう。
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は非表示レイヤーで一般的です。
隠れ層とニューロンの理想的な数は、問題とデータセットによって異なります。機械学習の多くの側面と同様に、ニューラルネットワークの最適な形状を選択するには、知識と実験を組み合わせる必要があります。経験則として、隠れ層とニューロンの数を増やすと、通常、より強力なモデルが作成され、効果的にトレーニングするにはより多くのデータが必要になります。
モデルの使用
このモデルが機能のバッチに対して何をするかを簡単に見てみましょう。
// Apply the model to a batch of features.
let firstTrainPredictions = model(firstTrainFeatures)
print(firstTrainPredictions[0..<5])
[[ 1.1514063, -0.7520321, -0.6730235], [ 1.4915676, -0.9158071, -0.9957161], [ 1.0549936, -0.7799266, -0.410466], [ 1.1725322, -0.69009197, -0.8345413], [ 1.4870572, -0.8644099, -1.0958937]]
ここで、各例は各クラスのロジットを返します。
各クラスの確率にこれらlogitsを変換するには、使用ソフトマックス関数:
print(softmax(firstTrainPredictions[0..<5]))
[[ 0.7631462, 0.11375094, 0.123102814], [ 0.8523791, 0.076757915, 0.07086295], [ 0.7191151, 0.11478964, 0.16609532], [ 0.77540654, 0.12039323, 0.10420021], [ 0.8541314, 0.08133837, 0.064530246]]
クラス間でargmax
を取得すると、予測されたクラスインデックスが得られます。ただし、モデルはまだトレーニングされていないため、これらは適切な予測ではありません。
print("Prediction: \(firstTrainPredictions.argmax(squeezingAxis: 1))")
print(" Labels: \(firstTrainLabels)")
Prediction: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] Labels: [1, 1, 0, 1, 2, 2, 0, 2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 0, 2, 0, 0, 2, 1, 2, 1, 0, 2, 0, 1]
モデルをトレーニングする
トレーニングは、モデルが徐々に最適化されるか、モデルがデータセットを学習する機械学習の段階です。目標は、トレーニングデータセットの構造について十分に学習し、見えないデータについて予測することです。トレーニングデータセットについて学びすぎると、予測はそれが見たデータに対してのみ機能し、一般化することはできません。この問題は過剰適合と呼ばれます。これは、問題の解決方法を理解するのではなく、答えを記憶するようなものです。
虹彩分類問題は、 教師あり機械学習の例です。モデルは、ラベルを含む例からトレーニングされます。 教師なし機械学習では、例にラベルが含まれていません。代わりに、モデルは通常、機能の中からパターンを見つけます。
損失関数を選択します
トレーニング段階と評価段階の両方で、モデルの損失を計算する必要があります。これは、モデルの予測が目的のラベルからどれだけ離れているか、つまり、モデルのパフォーマンスがどの程度悪いかを測定します。この値を最小化または最適化する必要があります。
モデルは、 softmaxCrossEntropy(logits:labels:)
関数を使用して損失を計算します。この関数は、モデルのクラス確率予測と目的のラベルをsoftmaxCrossEntropy(logits:labels:)
し、例全体の平均損失を返します。
現在のトレーニングされていないモデルの損失を計算してみましょう。
let untrainedLogits = model(firstTrainFeatures)
let untrainedLoss = softmaxCrossEntropy(logits: untrainedLogits, labels: firstTrainLabels)
print("Loss test: \(untrainedLoss)")
Loss test: 1.7598655
オプティマイザを作成する
オプティマイザーは、計算された勾配をモデルの変数に適用して、 loss
関数を最小化します。損失関数は曲面と考えることができ(図3を参照)、歩き回って最低点を見つけたいと思います。勾配は最も急な上りの方向を指しているので、反対方向に移動して丘を下ります。各バッチの損失と勾配を繰り返し計算することにより、トレーニング中にモデルを調整します。徐々に、モデルは、損失を最小限に抑えるための重みとバイアスの最適な組み合わせを見つけます。また、損失が少ないほど、モデルの予測は良くなります。
![]() |
図3.3D空間で時間の経過とともに視覚化された最適化アルゴリズム。 (出典:スタンフォードクラス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.7598655
次に、計算したばかりの勾配をオプティマイザーに渡します。オプティマイザーは、それに応じてモデルの微分可能変数を更新します。
optimizer.update(&model, along: grads)
損失を再度計算すると、勾配降下ステップが(通常)損失を減少させるため、損失は小さくなるはずです。
let logitsAfterOneStep = model(firstTrainFeatures)
let lossAfterOneStep = softmaxCrossEntropy(logits: logitsAfterOneStep, labels: firstTrainLabels)
print("Next loss: \(lossAfterOneStep)")
Next loss: 1.5318773
トレーニングループ
すべての部品が揃ったら、モデルはトレーニングの準備ができています!トレーニングループは、データセットの例をモデルにフィードして、より適切な予測を行うのに役立ちます。次のコードブロックは、これらのトレーニング手順を設定します。
- 各エポックを繰り返します。エポックは、データセットを1回通過することです。
- エポック内で、トレーニングエポックの各バッチを反復処理します
- バッチを照合し、その機能(
x
)とラベル(y
)を取得します。 - 照合されたバッチの機能を使用して、予測を行い、それをラベルと比較します。予測の不正確さを測定し、それを使用してモデルの損失と勾配を計算します。
- 最急降下法を使用して、モデルの変数を更新します。
- 視覚化のためにいくつかの統計を追跡します。
- エポックごとに繰り返します。
epochCount
変数は、データセットコレクションをループする回数です。直感に反して、モデルをより長くトレーニングしても、より良いモデルが保証されるわけではありません。 epochCount
は、調整可能なハイパーパラメータです。適切な数を選択するには、通常、経験と実験の両方が必要です。
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.475254, Accuracy: 0.34375 Epoch 50: Loss: 0.91668004, Accuracy: 0.6458333 Epoch 100: Loss: 0.68662673, Accuracy: 0.6979167 Epoch 150: Loss: 0.540665, Accuracy: 0.6979167 Epoch 200: Loss: 0.46283028, Accuracy: 0.6979167 Epoch 250: Loss: 0.4134724, Accuracy: 0.8229167 Epoch 300: Loss: 0.35054502, Accuracy: 0.8958333 Epoch 350: Loss: 0.2731444, Accuracy: 0.9375 Epoch 400: Loss: 0.23622067, Accuracy: 0.96875 Epoch 450: Loss: 0.18956228, Accuracy: 0.96875
時間の経過に伴う損失関数を視覚化する
モデルのトレーニングの進行状況を印刷すると便利ですが、多くの場合、この進行状況を確認する方が便利です。 Pythonの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()
Use `print()` to show values.
グラフの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.43.4 | 4.5 | 1.6 | 1 | 2 |
5.5 | 2.5 | 4.0 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ファイル、データフィードなど、さまざまなソースから取得される可能性があります。今のところ、ラベルを予測するために、ラベルのない3つの例を手動で提供します。ラベル番号は、次のように名前付き表現にマップされていることを思い出してください。
-
0
:アイリスセトサ 1
:アイリスバーシカラー2
:アイリスバージニカ
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.98731947, 0.012679046, 1.4035809e-06]) Example 1 prediction: Iris versicolor ([0.005065103, 0.85957265, 0.13536224]) Example 2 prediction: Iris virginica ([2.9613977e-05, 0.2637373, 0.73623306])