![]() | ![]() | ![]() |
このガイドでは、アヤメの花を種ごとに分類する機械学習モデルを構築することで、TensorFlow の Swift を紹介します。 TensorFlow に Swift を使用して、次のことを行います。
- モデルを構築し、
- このモデルをサンプル データでトレーニングし、
- モデルを使用して、未知のデータに関する予測を行います。
TensorFlow プログラミング
このガイドでは、次の高レベルの Swift for TensorFlow の概念を使用します。
- Epochs API を使用してデータをインポートします。
- 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 種のみを分類します。
- アイリス セトサ
- アイリス・バージニカ
- アイリスバーシカラー
![]() |
図 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 つの例があります。
- 最初の 4 つのフィールドはfeatures です: これらは例の特徴です。ここで、フィールドは花の測定値を表す浮動小数点数を保持します。
- 最後の列はラベルです。これは予測したい値です。このデータセットでは、花の名前に対応する 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
: アイリス・バージニカ
機能とラベルの詳細については、Machine Learning Crash Course の ML 用語セクションを参照してください。
let classNames = ["Iris setosa", "Iris versicolor", "Iris virginica"]
Epochs API を使用してデータセットを作成する
Swift for TensorFlow の 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 形式なので、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]プレースホルダー16
最初のbatchSize
の例の特徴は、 firstTrainFeatures にグループ化 (またはバッチ処理) され、最初の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 では、この予測は、 Iris setosaの場合は0.02
、 Iris versicolorの場合は0.95
、 Iris virginicaの場合は0.03
に分類されます。これは、モデルが (95% の確率で) ラベルのないサンプルの花がIris versicolorであることを予測することを意味します。
Swift for TensorFlow Deep Learning Library を使用してモデルを作成する
Swift for TensorFlow Deep Learning Libraryは、プリミティブ レイヤーとそれらを結び付ける規則を定義しているため、モデルの構築と実験が容易になります。
モデルは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()
アクティベーション関数は、レイヤー内の各ノードの出力形状を決定します。これらの非線形性は重要です。非線形性がなければ、モデルは 1 つのレイヤーと同等になります。利用可能なアクティベーションは多数ありますが、 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]]
ここで、各例は各クラスのロジットを返します。
これらのロジットを各クラスの確率に変換するには、 softmax関数を使用します。
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:)
関数を使用して損失を計算します。
現在のトレーニングされていないモデルの損失を計算しましょう。
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 ライセンス、画像クレジット: Alec Radford ) |
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.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
es の配列にロードします。
let testDataset = loadIrisDatasetFromCSV(
contentsOf: testDataFilename, hasHeader: true,
featureColumns: [0, 1, 2, 3], labelColumns: [4]).inBatches(of: batchSize)
テスト データセットでモデルを評価する
トレーニング ステージとは異なり、モデルはテスト データの 1 つのエポックのみを評価します。次のコード セルでは、テスト セットの各例を繰り返し処理し、モデルの予測を実際のラベルと比較します。これは、テスト セット全体でモデルの精度を測定するために使用されます。
// 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])