W tym przewodniku założono, że znasz już przewodnik po modelach i warstwach .
W TensorFlow.js istnieją dwa sposoby trenowania modelu uczenia maszynowego:
- za pomocą interfejsu Layers API z
LayersModel.fit()
lubLayersModel.fitDataset()
. - używając Core API z
Optimizer.minimize()
.
Najpierw przyjrzymy się interfejsowi Layers API, który jest interfejsem API wyższego poziomu do budowania i uczenia modeli. Następnie pokażemy, jak trenować ten sam model za pomocą Core API.
Wstęp
Model uczenia maszynowego to funkcja z możliwymi do uczenia się parametrami, która mapuje dane wejściowe do żądanych danych wyjściowych. Optymalne parametry uzyskuje się poprzez uczenie modelu na danych.
Szkolenie obejmuje kilka kroków:
- Pobieranie partii danych do modelu.
- Proszenie modelu o wykonanie prognozy.
- Porównanie tej prognozy z wartością „prawdziwą”.
- Decydowanie o tym, jak bardzo zmienić każdy parametr, aby model mógł lepiej przewidywać w przyszłości dla tej partii.
Dobrze wyszkolony model zapewni dokładne odwzorowanie danych wejściowych na pożądane dane wyjściowe.
Parametry modelu
Zdefiniujmy prosty model dwuwarstwowy za pomocą interfejsu Layers API:
const model = tf.sequential({
layers: [
tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
tf.layers.dense({units: 10, activation: 'softmax'}),
]
});
Pod maską modele mają parametry (często określane jako wagi ), których można się nauczyć poprzez trenowanie na danych. Wydrukujmy nazwy wag powiązanych z tym modelem i ich kształtów:
model.weights.forEach(w => {
console.log(w.name, w.shape);
});
Otrzymujemy następujący wynik:
> dense_Dense1/kernel [784, 32]
> dense_Dense1/bias [32]
> dense_Dense2/kernel [32, 10]
> dense_Dense2/bias [10]
W sumie są 4 ciężarki, po 2 na gęstą warstwę. Jest to oczekiwane, ponieważ gęste warstwy reprezentują funkcję, która odwzorowuje tensor wejściowy x
na tensor wyjściowy y
za pomocą równania y = Ax + b
, gdzie A
(jądro) b
(odchylenie) są parametrami gęstej warstwy.
UWAGA: Domyślnie gęste warstwy zawierają odchylenie, ale możesz je wykluczyć, określając
{useBias: false}
w opcjach podczas tworzenia gęstej warstwy.
model.summary()
jest przydatną metodą, jeśli chcesz uzyskać przegląd swojego modelu i zobaczyć całkowitą liczbę parametrów:
Warstwa (typ) | Kształt wyjściowy | Parametr # |
gęsty_Gęsty1 (Gęsty) | [null,32] | 25120 |
gęsty_Gęsty2 (Gęsty) | [null,10] | 330 |
Całkowite parametry: 25450 Parametry, które można trenować: 25450 Parametry nietreningowe: 0 |
Każda waga w modelu jest zaplecza przez obiekt Variable
. W TensorFlow.js Variable
jest zmiennoprzecinkowym Tensor
z jedną dodatkową metodą assign()
używaną do aktualizacji jej wartości. Interfejs Layers API automatycznie inicjuje wagi, korzystając ze sprawdzonych metod. Dla celów demonstracyjnych możemy nadpisać wagi, wywołując assign()
na bazowych zmiennych:
model.weights.forEach(w => {
const newVals = tf.randomNormal(w.shape);
// w.val is an instance of tf.Variable
w.val.assign(newVals);
});
Optymalizator, strata i metryka
Zanim rozpoczniesz jakikolwiek trening, musisz zdecydować się na trzy rzeczy:
- Optymalizator . Zadaniem optymalizatora jest podjęcie decyzji o tym, jak bardzo zmienić każdy parametr w modelu, biorąc pod uwagę bieżące przewidywanie modelu. Korzystając z interfejsu Layers API, możesz podać identyfikator ciągu istniejącego optymalizatora (np.
'sgd'
lub'adam'
) albo instancję klasyOptimizer
. - Funkcja straty . Cel, który model będzie starał się zminimalizować. Jego celem jest podanie jednej liczby określającej „jak błędne” było przewidywanie modelu. Strata jest obliczana dla każdej partii danych, aby model mógł aktualizować swoje wagi. Korzystając z interfejsu API warstw, możesz podać identyfikator ciągu istniejącej funkcji straty (np.
'categoricalCrossentropy'
) lub dowolnej funkcji, która przyjmuje przewidywaną i prawdziwą wartość i zwraca stratę. Zobacz listę dostępnych strat w naszej dokumentacji API. - Lista metryk. Podobnie jak w przypadku strat, metryki obliczają pojedynczą liczbę, podsumowując, jak dobrze radzi sobie nasz model. Metryki są zwykle obliczane na całych danych pod koniec każdej epoki. Przynajmniej chcemy monitorować, czy nasza strata maleje z biegiem czasu. Jednak często chcemy bardziej przyjaznych dla człowieka wskaźników, takich jak dokładność. Korzystając z interfejsu Layers API, możesz podać identyfikator ciągu istniejącej metryki (na przykład
'accuracy'
) lub dowolną funkcję, która pobiera przewidywaną i prawdziwą wartość i zwraca wynik. Zobacz listę dostępnych metryk w naszej dokumentacji API.
Kiedy już zdecydujesz, skompiluj LayersModel
, wywołując model.compile()
z podanymi opcjami:
model.compile({
optimizer: 'sgd',
loss: 'categoricalCrossentropy',
metrics: ['accuracy']
});
Podczas kompilacji model przeprowadzi pewną walidację, aby upewnić się, że wybrane opcje są ze sobą kompatybilne.
Trening
Istnieją dwa sposoby trenowania LayersModel
:
- Używanie
model.fit()
i dostarczanie danych jako jednego dużego tensora. - Używanie
model.fitDataset()
i dostarczanie danych za pośrednictwem obiektuDataset
.
model.fit()
Jeśli Twój zbiór danych mieści się w pamięci głównej i jest dostępny jako pojedynczy tensor, możesz wytrenować model, wywołując metodę fit()
:
// Generate dummy data.
const data = tf.randomNormal([100, 784]);
const labels = tf.randomUniform([100, 10]);
function onBatchEnd(batch, logs) {
console.log('Accuracy', logs.acc);
}
// Train for 5 epochs with batch size of 32.
model.fit(data, labels, {
epochs: 5,
batchSize: 32,
callbacks: {onBatchEnd}
}).then(info => {
console.log('Final accuracy', info.history.acc);
});
Pod maską model.fit()
może wiele dla nas zrobić:
- Dzieli dane na zestaw do trenowania i walidacji oraz używa zestawu walidacyjnego do mierzenia postępów podczas uczenia.
- Tasuje dane, ale dopiero po podziale. Aby być bezpiecznym, powinieneś wstępnie przetasować dane przed przekazaniem ich do funkcji
fit()
. - Dzieli tensor dużych danych na mniejsze tensory rozmiaru
batchSize.
- Wywołuje
optimizer.minimize()
podczas obliczania utraty modelu w odniesieniu do partii danych. - Może powiadamiać Cię o początku i końcu każdej epoki lub partii. W naszym przypadku jesteśmy powiadamiani na koniec każdej partii za pomocą opcji
callbacks.onBatchEnd
. Inne opcje to:onTrainBegin
,onTrainEnd
,onEpochBegin
,onEpochEnd
ionBatchBegin
. - Przechodzi do głównego wątku, aby zapewnić terminową obsługę zadań umieszczonych w kolejce w pętli zdarzeń JS.
Aby uzyskać więcej informacji, zapoznaj się z dokumentacją fit()
. Pamiętaj, że jeśli zdecydujesz się użyć interfejsu API Core, musisz samodzielnie zaimplementować tę logikę.
model.fitDataset()
Jeśli dane nie mieszczą się w całości w pamięci lub są przesyłane strumieniowo, możesz wytrenować model, wywołując fitDataset()
, który pobiera obiekt Dataset
. Oto ten sam kod treningowy, ale z zestawem danych, który otacza funkcję generatora:
function* data() {
for (let i = 0; i < 100; i++) {
// Generate one sample at a time.
yield tf.randomNormal([784]);
}
}
function* labels() {
for (let i = 0; i < 100; i++) {
// Generate one sample at a time.
yield tf.randomUniform([10]);
}
}
const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// We zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);
// Train the model for 5 epochs.
model.fitDataset(ds, {epochs: 5}).then(info => {
console.log('Accuracy', info.history.acc);
});
Aby uzyskać więcej informacji o zestawach danych, zapoznaj się z dokumentacją model.fitDataset()
.
Przewidywanie nowych danych
Gdy model zostanie wytrenowany, możesz wywołać model.predict()
, aby wykonać prognozy na niewidocznych danych:
// Predict 3 random samples.
const prediction = model.predict(tf.randomNormal([3, 784]));
prediction.print();
Podstawowe API
Wcześniej wspomnieliśmy, że istnieją dwa sposoby trenowania modelu uczenia maszynowego w TensorFlow.js.
Ogólną zasadą jest, aby najpierw spróbować użyć interfejsu API Layers, ponieważ jest on wzorowany na dobrze zaadaptowanym interfejsie API Keras. Interfejs Layers API oferuje również różne gotowe rozwiązania, takie jak inicjowanie wagi, serializacja modelu, szkolenie w zakresie monitorowania, przenośność i sprawdzanie bezpieczeństwa.
Możesz chcieć użyć Core API zawsze, gdy:
- Potrzebujesz maksymalnej elastyczności lub kontroli.
- I nie potrzebujesz serializacji ani nie możesz zaimplementować własnej logiki serializacji.
Aby uzyskać więcej informacji o tym interfejsie API, przeczytaj sekcję „Core API” w przewodniku dotyczącym modeli i warstw .
Ten sam model, co powyżej napisany przy użyciu Core API, wygląda tak:
// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));
function model(x) {
return x.matMul(w1).add(b1).relu().matMul(w2).add(b2);
}
Oprócz interfejsu Layers API interfejs Data API współpracuje również bezproblemowo z interfejsem Core API. Użyjmy ponownie zestawu danych, który zdefiniowaliśmy wcześniej w sekcji model.fitDataset() , która wykonuje dla nas tasowanie i grupowanie:
const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// Zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);
Wytrenujmy model:
const optimizer = tf.train.sgd(0.1 /* learningRate */);
// Train for 5 epochs.
for (let epoch = 0; epoch < 5; epoch++) {
await ds.forEachAsync(({xs, ys}) => {
optimizer.minimize(() => {
const predYs = model(xs);
const loss = tf.losses.softmaxCrossEntropy(ys, predYs);
loss.data().then(l => console.log('Loss', l));
return loss;
});
});
console.log('Epoch', epoch);
}
Powyższy kod to standardowa recepta podczas trenowania modelu za pomocą Core API:
- Zapętl liczbę epok.
- W każdej epoce zapętlaj swoje partie danych. W przypadku korzystania z
Dataset
dataset.forEachAsync()
to wygodny sposób na pętlę w partiach. - W przypadku każdej partii
optimizer.minimize(f)
, która wykonujef
i minimalizuje dane wyjściowe przez obliczenie gradientów w odniesieniu do czterech zmiennych, które zdefiniowaliśmy wcześniej. -
f
oblicza stratę. Wywołuje jedną z predefiniowanych funkcji straty przy użyciu przewidywania modelu i prawdziwej wartości.