Õppematerjal · TensorFlow ja Keras
TensorFlow nullist MLP-ni
Selle materjali lõpuks oskad Kerasega ehitada ja treenida mitmekihilise pertseptroni (MLP), mis eristab andmetes klasse. Närvivõrgu teooriat siin ei korrata, selleks on nn-explainer. Siin läheme otse TensorFlow poole: kõigepealt tensor, siis üks neuron, siis kihid ja lõpuks täielik MLP.
Teooria kordamiseks: nn-explainer ↗Mis on süvaõpe, TensorFlow ja Keras?
Enne koodi lühidalt kolm sõna, mida selles materjalis kogu aeg kuuled.
Süvaõpe
Masinõppes ei kirjuta inimene reegleid ette, vaid arvuti leiab need andmetest. Närvivõrk on üks masinõppe mudel: see koosneb neuronitest, mis on seatud kihtidesse. Süvaõpe (deep learning) on närvivõrgud, kus on mitu peidetud kihti. Sõna „sügav“ tulebki kihtide arvust: mida rohkem kihte, seda keerukamaid mustreid võrk õppida suudab. Pildi puhul õpib esimene kiht näiteks servi, järgmine kujundeid ja viimane terveid objekte.
Meie MLP kahe peidetud kihiga on süvaõppe kõige lihtsam vorm. Süvaõpet kasutatakse eriti siis, kui andmed on keerulised (pildid, tekst, heli, aegread) ja neid on palju. Väikese tabeli puhul annavad sageli sama head tulemust ka sklearni tavalised mudelid.
TensorFlow
TensorFlow on Google'i loodud teek, mis arvutab tensoritega (arvude tabelitega) väga kiiresti, vajadusel graafikakaardil. Ta oskab ka ise leida tuletisi, mida närvivõrgu õppimiseks vaja läheb (nn-explainer'is nägid seda backward-sammuna). Seda vajab iga süvaõppe võrk, seepärast on TensorFlow kõige aluseks.
Keras
Keras on TensorFlow kasutajasõbralik pool. Kerases on valmis ehitusklotsid (kihid, kaofunktsioonid, parandajad) ja lihtne töövoog: mudel, compile, fit, predict. Sa kirjutad koodi Kerasega ja TensorFlow töötab selle all: ta teeb raske arvutuse ära. Võrdle autoga: Keras on rool ja pedaalid, TensorFlow on mootor. Sõitmiseks ei pea mootori ehitust teadma.
Koodis näed seda nii:
| Rida | Mis see on |
|---|---|
import tensorflow as tf | TensorFlow: tensorid ja tehted (osad 1 ja 2) |
from tensorflow import keras | Keras: mudel ja treenimine (osad 3 kuni 7) |
from tensorflow.keras import layers | Kerase kihid, näiteks layers.Dense(...) |
Selles materjalis on peategelane Keras. Tensoreid õpime tundma selleks, et näha, mida mudel sisse võtab ja välja annab.
Miks TensorFlow, kui sklearnis on MLP olemas?
Kui oled kasutanud MLPClassifierit või MLPRegressorit, oled MLP-d juba treeninud. Sklearn teeb kõik ühe fit()-iga. Keras näeb välja sarnane, ka seal on fit(). Vahe on selles, et võrgu ehitad sa ise kihtidest ja kihte on palju rohkem kui sklearnis. Vaata sama mudelit kõrvuti.
from sklearn.neural_network import MLPClassifier
clf = MLPClassifier(
hidden_layer_sizes=(16, 16),
activation="relu",
solver="adam",
learning_rate_init=0.01,
batch_size=32,
max_iter=50,
)
clf.fit(X_train, y_train)
clf.predict(X_test)model = keras.Sequential([
keras.Input(shape=(2,)),
layers.Dense(16, activation="relu"),
layers.Dense(16, activation="relu"),
layers.Dense(1, activation="sigmoid"),
])
model.compile(
optimizer=keras.optimizers.Adam(
learning_rate=0.01),
loss="binary_crossentropy",
)
model.fit(X_train, y_train,
epochs=50, batch_size=32)
model.predict(X_test)See on sama võrk: 2 sisendit, kaks peidetud kihti 16 neuroniga, ReLU, Adam, partii 32 ja 50 epohhi. Täisnäite andmetel (osa 7) said mõlemad testi täpsuseks umbes 97–98%. Tulemus on peaaegu sama, aga Kerases näed ja valid ise iga kihi. Samamoodi saab Kerasega ehitada ka pildi-, teksti- ja aegridade võrke.
| Mida tahad teha | sklearn MLP | TensorFlow / Keras |
|---|---|---|
| Väike tabel, kiire esimene mudel | Väga hea, vähe koodi | Saab, aga koodi on veidi rohkem |
| Pildid, tekst, heli, aegread | Ainult täisühendatud kihid | Konvolutsioon (CNN), RNN ja LSTM, Transformer jt kihid on valmis |
| Graafikakaart (GPU) | Ainult protsessor | Kasutab GPU-d, kui see on olemas (Linux, WSL2, Colab) |
| Treeningu jälgimine | loss_curve_, early_stopping | history ja callback'id (EarlyStopping, ModelCheckpoint, TensorBoard) |
| Oma kiht, oma kaofunktsioon | Pole | Saab teha |
| Mudeli viimine mujale | joblib, ainult Pythonis | .keras fail; TensorFlow Lite (telefon), TensorFlow.js (brauser) |
| Eeltreenitud mudelid | Pole | keras.applications (pildimudelid) |
| Andmed, mis ei mahu mällu | Kõik peab korraga mälus olema | tf.data loeb osade kaupa |
Sklearn, kui andmed on väike tabel ja tahad MLP-d kiiresti võrrelda teiste mudelitega (otsustuspuu, random forest, logistiline regressioon) ühes Pipelineis. TensorFlow/Keras, kui võrk on suurem või keerulisem (pildid, tekst, aegread), kui tahad kasutada GPU-d või kui mudel peab jõudma telefoni, veebi või serverisse.
Selles materjalis ei seleta me närvivõrgu teooriat uuesti. Kui neuron, kiht, aktivatsioon, kaofunktsioon või gradient descent vajavad kordamist, vaata enne nn-explainer'it. Siin näitame, kuidas need mõisted Kerases välja näevad.
| nn-explainer'is | Kerases |
|---|---|
| Neuron | layers.Dense(1) |
| Kiht mitme neuroniga | layers.Dense(16) |
| Sisend | keras.Input(shape=(2,)) |
| Aktivatsioon (ReLU, sigmoid, softmax) | activation="relu" |
| Kaofunktsioon (viga) | loss="binary_crossentropy" |
| Gradient descent, õppesamm | optimizer=keras.optimizers.Adam(learning_rate=0.01) |
| Forward, backward ja kaalude uuendamine | model.fit(...) teeb need ise |
| Epohh ja partii | epochs=50, batch_size=32 |
| Ennustamine | model.predict(...) |
0Alustus
Paigalda TensorFlow. Kõik siinsed näited töötavad tavalise protsessoriga, graafikakaarti pole vaja. Google Colabis on TensorFlow juba olemas.
pip install tensorflowKontrollime, et kõik töötab:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
print(tf.__version__)
print(keras.__version__)
print(tf.config.list_physical_devices("GPU"))2.21.0
3.15.1
[]- Esimene rida toob sisse TensorFlow, teine Kerase (osa, millega võrke ehitame) ja kolmas kihtide klassid.
- Tühi loend
[]tähendab, et graafikakaarti ei leitud. See on täiesti korras. - Kõik näited on katsetatud TensorFlow 2.21.0 ja Keras 3.15.1 peal. Sinu versioon võib olla teine, aga kood töötab Keras 3-ga (TensorFlow 2.16 ja uuem).
TensorFlow prindib esimesel käivitusel sageli pikki teateid, näiteks oneDNN custom operations are on või hoiatuse, et GPU-d ei leitud. Need on teated, mitte vead. Võid need rahulikult ignoreerida.
Soovitus: ära kopeeri plokke korraga. Käivita iga plokk eraldi, vaata väljundit ja muuda mõnda arvu. Nii jääb rohkem meelde.
1Tensor
Tensor on TensorFlow põhiline andmetüüp. See on nagu NumPy massiiv: arvude tabel, millel on kuju (shape) ja tüüp (dtype). Kerase mudelid võtavad sisse ja annavad välja tensoreid. Lisaks oskab TensorFlow arvutada graafikakaardil ja leida tuletisi ise. Viimase teeb fit() sinu eest, seda me ise ei kirjuta.
a = tf.constant([1.0, 2.0, 3.0])
print(a)
print(a.shape)
print(a.dtype)
M = tf.constant([[1, 2, 3],
[4, 5, 6]])
print(M.shape)
print(M.dtype)tf.Tensor([1. 2. 3.], shape=(3,), dtype=float32)
(3,)
<dtype: 'float32'>
(2, 3)
<dtype: 'int32'>tf.constant(...)teeb tensori.print(a)näitab kolme asja korraga: arve, kuju ja tüüpi.- Täisarvud on
int32, komaga arvudfloat32. Kui tahad komaga arvu, kirjuta1.0, mitte1.
| Mõõtmeid | Näide | Kuju | Masinõppes |
|---|---|---|---|
| 0 | tf.constant(3.5) | () | üks arv, nt kaofunktsiooni väärtus |
| 1 | tf.constant([1., 2., 3.]) | (3,) | ühe näite tunnused või kõik sildid |
| 2 | tf.constant([[1, 2, 3], [4, 5, 6]]) | (2, 3) | tabel: read on näited, veerud on tunnused |
| 2 | andmetabel X | (150, 4) | iirise andmed: 150 lille, 4 tunnust |
Keras tahab sisendit alati kujuga (näidete arv, tunnuste arv). Esimene arv on, mitu rida (näidet) on, teine, mitu veergu (tunnust). Enamik vigu tuleb sellest, et kuju on vale.
Tensori loomine
print(tf.zeros((2, 3)))
print(tf.ones((2, 2)))
print(tf.range(5))
tf.random.set_seed(0) # et juhuslikud arvud korduksid
print(tf.random.normal((2, 2)))tf.Tensor(
[[0. 0. 0.]
[0. 0. 0.]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[1. 1.]
[1. 1.]], shape=(2, 2), dtype=float32)
tf.Tensor([0 1 2 3 4], shape=(5,), dtype=int32)
tf.Tensor(
[[ 1.5110626 0.42292204]
[-0.41969493 -1.0360372 ]], shape=(2, 2), dtype=float32)tf.zeros ja tf.ones teevad nullidest ja ühtedest tabeli. tf.range loeb nullist peale. tf.random.normal annab juhuslikke arve, seega on sinu arvud teised.
NumPy ja tensor
import numpy as np
arr = np.array([[1.0, 2.0], [3.0, 4.0]])
t = tf.constant(arr)
print(t.dtype) # float64, sest NumPy kasutab vaikimisi seda
t32 = tf.cast(t, tf.float32) # muudame tüübi
print(t32.dtype)
print(t32.numpy()) # tagasi NumPy massiiviks<dtype: 'float64'>
<dtype: 'float32'>
[[1. 2.]
[3. 4.]]NumPy kasutab vaikimisi float64, Keras eelistab float32. Kui andmed on NumPy massiivis, pole häda: model.fit(X, y) muudab tüübi ise. Aga TensorFlow oma tehetes ei luba float32 ja float64 segada. Siis aitab tf.cast.
2Kujud ja tehted
Siin on tensorite kõige tavalisemad võtted. Enamik neist on sul NumPy-st juba tuttavad.
Kuju muutmine
Tabeli saab teisiti kokku panna: samad arvud, uus kuju. Arv -1 tähendab „arvuta see ise“.
x = tf.range(6)
print(x)
print(tf.reshape(x, (2, 3)))
print(tf.reshape(x, (3, -1)).shape) # -1: TensorFlow arvutab selle arvu isetf.Tensor([0 1 2 3 4 5], shape=(6,), dtype=int32)
tf.Tensor(
[[0 1 2]
[3 4 5]], shape=(2, 3), dtype=int32)
(3, 2)Valimine
Indekseerimine töötab nagu NumPy-s. M[0] on esimene rida, M[:, 1] on teine veerg.
M = tf.constant([[1, 2, 3],
[4, 5, 6]])
print(M[0]) # esimene rida
print(M[:, 1]) # teine veerg
print(M[1, 2]) # üks arvtf.Tensor([1 2 3], shape=(3,), dtype=int32)
tf.Tensor([2 5], shape=(2,), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)Tehted
Tehted käivad elemendiviisi: a + b liidab esimese arvu esimesega, teise teisega ja nii edasi. Kokkuvõtted algavad sõnaga reduce_ (suruvad palju arve üheks).
a = tf.constant([1.0, 2.0, 3.0])
b = tf.constant([10.0, 20.0, 30.0])
print(a + b)
print(a * 2)
print(tf.square(a))
print(tf.reduce_sum(a))
print(tf.reduce_mean(a))tf.Tensor([11. 22. 33.], shape=(3,), dtype=float32)
tf.Tensor([2. 4. 6.], shape=(3,), dtype=float32)
tf.Tensor([1. 4. 9.], shape=(3,), dtype=float32)
tf.Tensor(6.0, shape=(), dtype=float32)
tf.Tensor(2.0, shape=(), dtype=float32)Telg (axis): mida mööda kokku võtta
Tabelis saab arve kokku liita kahte moodi: ridade kaupa või veergude kaupa. Seda ütleb axis.
x = tf.constant([[1.0, 2.0],
[3.0, 4.0]])
print(tf.reduce_sum(x, axis=0)) # read liidetakse kokku
print(tf.reduce_sum(x, axis=1)) # veerud liidetakse kokkutf.Tensor([4. 6.], shape=(2,), dtype=float32)
tf.Tensor([3. 7.], shape=(2,), dtype=float32)axis=0 liidab read kokku (alles jääb üks rida), axis=1 liidab veerud kokku (alles jääb üks veerg).
Maatrikskorrutis
Pisinäide. Kolm õpilast, igaühel kaks tunnust. Neuron korrutab tunnused kaaludega, liidab kokku ja lisab nihke. Kõigi õpilaste jaoks korraga teeb seda üks tehe, @:
X = tf.constant([[1.0, 4.0],
[2.0, 3.0],
[0.0, 5.0]]) # 3 õpilast, 2 tunnust
W = tf.constant([[2.0],
[3.0]]) # kaalud, kuju (2, 1)
b = tf.constant([1.0]) # nihe
print(X @ W + b) # kuju (3, 1)tf.Tensor(
[[15.]
[14.]
[16.]], shape=(3, 1), dtype=float32)X @ W + b arvutab kõigi õpilaste ennustused korraga. Oranž raam on esimene õpilane.Esimese õpilase vastus on 1·2 + 4·3 + 1 = 15. Tähtis on, et sisemised kujud klapiksid: (3, 2) @ (2, 1) annab (3, 1). Just seda teeb Kerase Dense kiht (osa 4).
Broadcasting: standardiseerimine ühe reaga
Mudelile sobivad paremini ühesuurused arvud. Siin on üks tunnus väike (1, 2, 3) ja teine suur (100, 200, 300). Standardiseerimine võtab iga veeru keskmise maha ja jagab standardhälbega.
X = tf.constant([[1.0, 100.0],
[2.0, 200.0],
[3.0, 300.0]]) # 3 rida, 2 tunnust
mu = tf.reduce_mean(X, axis=0) # iga veeru keskmine, kuju (2,)
sigma = tf.math.reduce_std(X, axis=0)
print(mu)
print((X - mu) / sigma) # mu ja sigma "venivad" igale realetf.Tensor([ 2. 200.], shape=(2,), dtype=float32)
tf.Tensor(
[[-1.2247448 -1.2247449]
[ 0. 0. ]
[ 1.2247448 1.2247449]], shape=(3, 2), dtype=float32)mu mõtteline koopia, mille TensorFlow iga rea jaoks teeb.X on kujuga (3, 2), mu on kujuga (2,). Kujud ei klapi, aga TensorFlow „venitab“ mu rea kõigile ridadele ja lahutab elemendiviisi. Jagamine sigma-ga käib samamoodi. Sellepärast ei pea sa ise tsüklit kirjutama.
Muudetavad tensorid ja suurima arvu koht
Tavalist tensorit ei saa muuta. Mudeli kaalud on aga muutuvad, seepärast on need tf.Variable'id. Neid sa ise tavaliselt ei loo, Keras teeb seda sinu eest.
try:
M[0, 0] = 99 # tavalist tensorit muuta ei saa
except TypeError as e:
print(e)
v = tf.Variable([1.0, 2.0, 3.0]) # Variable on muudetav
v.assign_add([10.0, 10.0, 10.0])
print(v.numpy())'tensorflow.python.framework.ops.EagerTensor' object does not support item assignment
[11. 12. 13.]Klassifitseerimisel tuleb tihti välja valida suurima tõenäosusega klass. Seda teeb tf.argmax:
probs = tf.constant([[0.1, 0.7, 0.2],
[0.8, 0.1, 0.1]])
print(tf.argmax(probs, axis=1)) # kus on iga rea suurim arv?tf.Tensor([1 0], shape=(2,), dtype=int64)Esimese rea suurim arv (0.7) on kohal 1, teise rea suurim arv (0.8) kohal 0.
- Kuju kirjutatakse
(read, veerud). Keras tahab andmeid kujuga(näidete arv, tunnuste arv). tf.constanton muutumatu,tf.Variableon muudetav.tf.reduce_sum(x, axis=0): nimetatud telg kaob ära.X @ W + bon neuronite arvutus kõigile näidetele korraga.- Tehetes ei tohi segada
int32,float32jafloat64. Muudatf.castiga.
3Esimene mudel: üks neuron
Alustame kõige väiksema võrguga, mis üldse õpib: ühe neuroniga. See on sama sirge ŷ = w · x + b, mille nn-explainer'is neuronina nägid. Seekord ei arvuta me midagi ise: Keras teeb kogu treenimise ära. Meie ülesanne on öelda kolm asja: milline mudel, kuidas viga mõõta ja kuidas seda parandada.
3.1 Ülesanne: andmed X ja y
Neli õpilast kirjutasid testi. Teame, mitu tundi igaüks õppis ja mitu punkti ta sai:
| Õpilane | Õppetunnid (X) | Punktid (y) |
|---|---|---|
| A | 1 | 3 |
| B | 2 | 5 |
| C | 3 | 7 |
| D | 4 | 9 |
- X on see, mida me teame: sisend ehk tunnus.
- y on see, mida tahame ennustada: sihtmuutuja.
Küsimus: mitu punkti saab õpilane, kes õppis 5 tundi? Vaata tabelit: iga lisatund annab 2 punkti juurde ja 0 tunniga oleks 1 punkt. Reegel on y = 2·X + 1.
Meie nägime seda silmaga. Mudel peab selle ise leidma, ja seda me nimetamegi õppimiseks. Õige reegli teame ette ainult selleks, et lõpus kontrollida, kas mudel leidis selle.
X = tf.constant([[1.0], [2.0], [3.0], [4.0]]) # õppetunnid, kuju (4, 1)
y = tf.constant([[3.0], [5.0], [7.0], [9.0]]) # punktid, kuju (4, 1)
print(X.shape, y.shape)(4, 1) (4, 1)Kuju (4, 1) tähendab 4 rida (õpilast) ja 1 veergu (tunnust). Keras tahab sisendi alati kujuga (näidete arv, tunnuste arv), ka siis, kui tunnus on ainult üks.
3.2 Mudel: üks neuron
Mudel on lihtne valem, mis teeb X-ist ennustuse:
Märk ŷ (loe „y-katus“, koodis ennustus) tähendab ennustust. Nii ei aeta seda segi tegeliku y-ga.
- w (weight, kaal) ütleb, mitu punkti annab üks lisatund. See on sirge tõus.
- b (bias, nihe) ütleb, mitu punkti saab õpilane, kes üldse ei õppinud (X = 0).
Neid kahte arvu me ei tea. Mudel peab need andmetest ise leidma. Neid arve nimetatakse mudeli parameetriteks.
Kerases ehitatakse mudel kihtidest. Meil on üks kiht ja selles üks neuron:
keras.utils.set_random_seed(1) # et algväärtused oleksid samad mis siin
model = keras.Sequential([
keras.Input(shape=(1,)), # sisend: 1 tunnus (õppetunnid)
layers.Dense(1), # 1 neuron: ŷ = w · x + b
])
model.summary()Model: "sequential"
┌─────────────────────────────────┬────────────────────────┬───────────────┐
│ Layer (type) │ Output Shape │ Param # │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense) │ (None, 1) │ 2 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 2 (8.00 B)
Trainable params: 2 (8.00 B)
Non-trainable params: 0 (0.00 B)keras.Sequential([...]): mudel, kus kihid on üksteise järel, sisendist väljundini.keras.Input(shape=(1,)): ütleb, et üks näide on 1 arv (õppetunnid). See ei ole kiht, ainult kuju kirjeldus.layers.Dense(1): üks neuron, mis arvutabw · x + b.Densetähendab, et iga sisend on ühendatud iga neuroniga.model.summary(): mudeli kokkuvõte.
Kokkuvõttes tähendab (None, 1), et väljundis on 1 arv iga näite kohta. None asemel võib olla ükskõik mitu näidet: mudel sobib nii ühe õpilase kui tuhande õpilase jaoks. Param # on 2, sest parameetreid on kaks: w ja b.
w = 2 ja b = 1, siis õpilane, kes õppis 3 tundi, saab 2·3 + 1 = 7 punkti. Kerases on see Dense(1).Mudel ei ole veel midagi õppinud. Keras valib w alguses juhuslikult ja paneb b = 0. Vaatame neid ja mudeli esimesi ennustusi:
w, b = model.layers[0].get_weights()
print("w =", w)
print("b =", b)
print(model.predict(X, verbose=0)) # mudel ei ole veel midagi õppinudw = [[-0.83484906]]
b = [0.]
[[-0.83484906]
[-1.6696981 ]
[-2.504547 ]
[-3.3393962 ]]Ennustused on kaugel õigetest vastustest (3, 5, 7, 9). Sinu w on teine, sest see on juhuslik.
3.3 Viga ja parandaja: compile
Enne treenimist tuleb Kerasele öelda kaks asja:
| Argument | Mida see tähendab |
|---|---|
loss="mse" | Viga: iga õpilase ennustuse ja õige vastuse vahe võetakse ruutu ja neist võetakse keskmine (mean squared error). Mida väiksem, seda parem mudel. |
optimizer=SGD(learning_rate=0.02) | Parandaja: muudab w-d ja b-d nii, et viga väheneks. learning_rate on õppesamm: kui suure sammu see iga kord teeb. |
model.compile(
optimizer=keras.optimizers.SGD(learning_rate=0.02), # kuidas w ja b-d parandatakse
loss="mse", # kuidas viga mõõdetakse
)
print(round(model.evaluate(X, y, verbose=0), 2)) # viga enne treenimist75.45Praegu on viga umbes 75. Õppimine tähendab: muuda w-d ja b-d nii, et see arv väheneks. Kui kaofunktsioon või gradient descent on veel udused, vaata nn-explainer'it.
3.4 Õppimine: fit
Nüüd treenime. Epohh tähendab, et mudel on kõik andmed korra läbi vaadanud ja kaale natuke parandanud. Teeme neid 500.
history = model.fit(X, y, epochs=500, verbose=0)
loss = history.history["loss"]
for e in (1, 2, 3, 5, 10, 20, 500):
print(f"epohh {e:3d} viga = {loss[e - 1]:.4f}")epohh 1 viga = 75.4470
epohh 2 viga = 33.4638
epohh 3 viga = 14.8426
epohh 5 viga = 2.9201
epohh 10 viga = 0.0503
epohh 20 viga = 0.0002
epohh 500 viga = 0.0000model.fit(X, y, epochs=500): treeni 500 epohhi.verbose=0tähendab, et Keras ei prindi iga epohhi.history.history["loss"]on loend: viga igal epohhil. Prindime sellest mõne.
Viga langeb 75-lt peaaegu nullini juba paarikümne epohhiga. Vaatame, mis w ja b-st sai, ja kasutame mudelit:
w, b = model.layers[0].get_weights()
print(f"w = {w[0, 0]:.3f} b = {b[0]:.3f}")
print(model.predict(tf.constant([[5.0]]), verbose=0)) # õpilane, kes õppis 5 tundiw = 2.001 b = 0.998
[[11.001116]]w ja b on peaaegu täpselt 2 ja 1. Mudel leidis ise üles reegli y = 2·X + 1, mida me talle ei öelnud. Õpilane, kes õppis 5 tundi, saab umbes 11 punkti.
3.5 Mida fit() sees teeb
Ühe epohhi jooksul teeb Keras neli sammu ja kordab neid:
- Ennustus (forward): mudel arvutab
ŷ = w · x + bkõigile õpilastele. - Viga: võrdleb ennustusi õigete vastustega.
- Tuletised (backward): arvutab, kummale poole w-d ja b-d keerata, et viga väheneks.
- Samm: parandaja liigutab w-d ja b-d natuke selles suunas. Sammu suurus on
learning_rate.
fit() sinu eest kordab.Need on samad sammud, mida nn-explainer'is samm-sammult nägid. Kerases ei kirjuta sa neid ise: fit() teeb need sinu eest.
3.6 Mida Keras treenimise ajal prindib
Seni panime verbose=0. Vaatame, mida Keras tavaliselt näitab. Paneme mudeli ehituse ühte funktsiooni, et saaksime sama mudelit mitu korda uuesti teha, ja treenime 3 epohhi (verbose=2 prindib ühe rea epohhi kohta):
def make_model(lr):
m = keras.Sequential([keras.Input(shape=(1,)), layers.Dense(1)])
m.compile(optimizer=keras.optimizers.SGD(learning_rate=lr), loss="mse")
return m
make_model(0.02).fit(X, y, epochs=3, verbose=2)Epoch 1/3
1/1 - 0s - 262ms/step - loss: 30.6848
Epoch 2/3
1/1 - 0s - 67ms/step - loss: 13.6233
Epoch 3/3
1/1 - 0s - 74ms/step - loss: 6.0556Epoch 1/3: epohh 1 kolmest.1/1: üks partii. Kõik neli õpilast mahtusid korraga, seega on epohhis üks samm. Suuremate andmetega on partiisid palju (osa 7).loss: viga selle epohhi jooksul. See langeb iga epohhiga.- Ajad (
ms/step) on sinu arvutis teised.
3.7 Õppesamm (learning_rate)
Õppesamm ütleb, kui suure sammu parandaja iga kord teeb. Proovime kolme väärtust, igaühe jaoks uus mudel ja 100 epohhi:
for lr in (0.001, 0.02, 0.3):
m = make_model(lr)
h = m.fit(X, y, epochs=100, verbose=0)
print(f"lr = {lr:<6} viga pärast 100 epohhi = {h.history['loss'][-1]:.4f}")lr = 0.001 viga pärast 100 epohhi = 1.4628
lr = 0.02 viga pärast 100 epohhi = 0.0038
lr = 0.3 viga pärast 100 epohhi = nan0.001on liiga väike: mudel õpib, aga nii aeglaselt, et 100 epohhi pärast on viga alles umbes 1.5.0.02on sobiv: viga on peaaegu null.0.3on liiga suur: iga samm hüppab miinimumist üle ja viga kasvab üha suuremaks, kuni tulebnan(not a number). Kui näednani, vähendalearning_rate.
3.8 Keras'e töövoog
Iga Kerase projekt käib samade nelja sammuga:
compile, fit, predict. Hindamiseks on lisaks evaluate.- Mudel:
keras.Sequential([keras.Input(...), layers.Dense(...)]). Parameetridwjabloob Keras ise. - compile:
lossütleb, kuidas viga mõõta,optimizerütleb, kuidas seda vähendada. - fit:
model.fit(X, y, epochs=...)kordab neid nelja sammu (ennustus, viga, tuletised, samm). - predict:
model.predict(X_uus)annab ennustused. X peab olema kujuga(näidete arv, tunnuste arv). - Kui
lossonnan, on õppesamm liiga suur.
Ühe neuroniga saab joonistada ainult sirge. Järgmises osas paneme neuroneid kõrvuti ja kihte üksteise taha.
4Dense kiht ja aktivatsioon
Üks neuron joonistab sirge. Päris ülesannetes on vaja mitut neuronit kõrvuti ja mitut kihti üksteise taga. Esimese jaoks on Kerases Dense kiht.
4.1 Dense: mitu neuronit kõrvuti
layers.Dense(3) on 3 neuronit kõrvuti. Iga neuron vaatab kõiki sisendeid. Kui sisendeid on 4, on igal neuronil 4 kaalu ja 1 nihe. Parameetreid on seega 3·4 + 3 = 15.
layer = layers.Dense(3) # 3 neuronit kõrvuti
X10 = tf.random.normal((10, 4)) # 10 näidet, 4 tunnust
out = layer(X10) # esimesel kutsel loob Keras kaalud
print(out.shape)
print(layer.kernel.shape) # W: (sisse, välja)
print(layer.bias.shape)(10, 3)
(4, 3)
(3,)(10, 3): 10 näidet, igaühe kohta 3 väljundit (üks iga neuroni kohta).layer.kernelon kaalude tabelW, kuju(4, 3): 4 sisendit, 3 neuronit. Keras hoiab kaalusid kujuga(sisse, välja).layer.biason nihkedb, üks iga neuroni kohta.
Dense(3) neljal sisendil: iga väljund on kõigi nelja sisendi kaalutud summa pluss nihe. Iga joon on üks kaal. Lillad jooned on väljundi h₁ kaalud, kollases kastis on sama valemina.Dense kiht ei ole midagi salapärast. See on lihtsalt see X @ W + b, mille osas 2 tensoritega ise kirjutasime. Kontrollime:
import numpy as np
W, b = layer.get_weights()
print(np.allclose(X10.numpy() @ W + b, out.numpy()))TrueTrue tähendab, et käsitsi arvutatud X @ W + b ja kihi väljund on samad.
4.2 Aktivatsioon: murdja kihtide vahel
Pärast neuronite arvutust võib panna väikese „murdja“, mida nimetatakse aktivatsioonifunktsiooniks. Kerases antakse see kihile argumendiga activation=. Kolm tavalisemat:
| Aktivatsioon | Mida teeb | Kus kasutatakse |
|---|---|---|
"relu" | Negatiivne arv muutub nulliks, positiivne jääb samaks | Peidetud kihtides |
"sigmoid" | Surub arvu vahemikku 0 kuni 1, nagu tõenäosus | Kahe klassi väljundis |
"softmax" | Teeb arvude rea tõenäosusteks, mis annavad kokku 1 | Mitme klassi väljundis |
None (vaikimisi) | Ei tee midagi, arv jääb samaks | Regressiooni väljundis |
Vaatame neid väikeste arvudega:
z = tf.constant([-2.0, -0.5, 0.0, 1.5])
print(tf.nn.relu(z).numpy()) # negatiivsed saavad nulliks
print(tf.nn.sigmoid(z).numpy()) # kõik arvud 0 ja 1 vahele
logits = tf.constant([[2.0, 0.5]])
print(tf.nn.softmax(logits).numpy()) # tõenäosused, summa on 1[0. 0. 0. 1.5]
[0.11920294 0.37754068 0.5 0.81757444]
[[0.81757444 0.18242551]]- ReLU:
-2,-0.5ja0said nulliks,1.5jäi samaks. - Sigmoid: kõik arvud on nüüd 0 ja 1 vahel. Suur arv saab 1-le lähedase, väga negatiivne 0-le lähedase.
- Softmax: kaks arvu (
2.0ja0.5) said tõenäosusteks 0.82 ja 0.18. Nende summa on 1. Suurem arv sai suurema tõenäosuse.
Dense kihti kokku ikka sirge. ReLU-ga tekivad murdekohad ja paljudest murdekohtadest saab kõvera piiri.Miks aktivatsiooni üldse vaja on? nn-explainer näitab seda pildil: ilma selleta on mitu kihti kokku ikka üks sirge. Järgmises osas näed seda ka Kerases oma silmaga.
5Mitu kihti: MLP
MLP (multilayer perceptron) on võrk, kus Dense kihid on üksteise taga ja nende vahel on aktivatsioon. Vaatame päris ülesandel, miks seda vaja on.
5.1 Ülesanne: kaks poolkuud
Andmed on kaks poolkuud (make_moons). Igal punktil on kaks tunnust ja klass 0 või 1. Jagame andmed treeninguks ja testiks ning skaleerime need.
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = make_moons(n_samples=1000, noise=0.2, random_state=42)
print(X.shape, y.shape)
print(X[:3].round(2))
print(y[:3])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # skaleerimise õpime ainult treeningandmetelt
X_test = scaler.transform(X_test)
print(X_train.shape, X_test.shape)(1000, 2) (1000,)
[[-0.11 0.52]
[ 1.14 -0.34]
[ 0.8 -0.01]]
[1 1 1]
(800, 2) (200, 2)(1000, 2)tähendab 1000 punkti, igaühel 2 tunnust. Sildidyon 0 või 1.train_test_splitpaneb 200 punkti testiks kõrvale. Nendega mudelit ei treenita. Nendega kontrollime lõpus, kui hästi mudel uute andmetega töötab.StandardScalertoob tunnused samasse suurusjärku (keskmine 0, standardhälve 1). Närvivõrk õpib skaleeritud andmetega palju kiiremini. Skaleerimise õpime ainult treeningandmetelt (fit_transform) ja testile rakendame sama (transform).
5.2 Katse: üks neuron, kaks kihti, kaks kihti ReLU-ga
Treenime kolm mudelit samadel andmetel ja vaatame testi täpsust. Et ei peaks sama koodi kolm korda kirjutama, paneme mudeli ehituse funktsiooni build sisse:
def build(hidden, activation):
model = keras.Sequential([keras.Input(shape=(2,))])
for units in hidden:
model.add(layers.Dense(units, activation=activation))
model.add(layers.Dense(1, activation="sigmoid"))
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.01),
loss="binary_crossentropy", metrics=["accuracy"])
return model
variants = [
("üks neuron", [], None),
("kaks kihti, aktivatsioonita", [16, 16], None),
("kaks kihti ja ReLU", [16, 16], "relu"),
]
models = {}
for name, hidden, act in variants:
keras.utils.set_random_seed(0)
m = build(hidden, act)
m.fit(X_train, y_train, epochs=50, batch_size=32, verbose=0)
acc = m.evaluate(X_test, y_test, verbose=0)[1]
models[name] = m
print(f"{name:30s} testi täpsus {acc:.1%}")üks neuron testi täpsus 86.0%
kaks kihti, aktivatsioonita testi täpsus 85.5%
kaks kihti ja ReLU testi täpsus 96.5%model.add(...)lisab mudelile kihi juurde.- Viimane kiht on alati
Dense(1, activation="sigmoid"): üks neuron, mis annab tõenäosuse, et punkt on klassi 1. activation=Nonetähendab, et peidetud kihtidel pole aktivatsiooni.
Tulemused:
- Üks neuron (86.0%): tõmbab ühe sirge. Poolkuude vahele sirget ei saa.
- Kaks kihti ilma aktivatsioonita (85.5%): peaaegu sama. Mitu
Densekihti järjest ilma aktivatsioonita on kokku ikka üks sirge, nagu nn-explainer näitas. Sellest pole kasu. - Kaks kihti ja ReLU (96.5%): ReLU murrab sirge ja paljudest murdekohtadest saab kõver piir.
5.3 MLP kokku
Sama võrk, kirjutatud nii, nagu sa seda tavaliselt teed:
keras.utils.set_random_seed(0)
model = keras.Sequential([
keras.Input(shape=(2,)), # 2 tunnust
layers.Dense(16, activation="relu"), # 1. peidetud kiht
layers.Dense(16, activation="relu"), # 2. peidetud kiht
layers.Dense(1, activation="sigmoid"), # väljund: tõenäosus 0...1
])
model.summary()Model: "sequential"
┌─────────────────────────────────┬────────────────────────┬───────────────┐
│ Layer (type) │ Output Shape │ Param # │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense) │ (None, 16) │ 48 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense) │ (None, 16) │ 272 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_2 (Dense) │ (None, 1) │ 17 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 337 (1.32 KB)
Trainable params: 337 (1.32 KB)
Non-trainable params: 0 (0.00 B)- Kaks peidetud kihti (
Dense(16, activation="relu")), igaühes 16 neuronit. - Viimane kiht on väljund: üks neuron, mis annab tõenäosuse (
sigmoid). Output Shapenäitab kuju pärast iga kihti.Param #näitab parameetrite arvu:2·16 + 16 = 48,16·16 + 16 = 272ja16·1 + 1 = 17. Kokku 337.
2 → 16 → 16 → 1. Joonisel on kummastki peidetud kihist näha viis neuronit 16-st. Kriipsjoonega kast näitab aktivatsiooni, all on kuju pärast iga kihti (None on näidete arv).Esimese kihi sisendi kuju ütled ise: keras.Input(shape=(tunnuste arv,)). Iga järgmise kihi sisendi arvutab Keras ise eelmise kihi neuronite arvust. Viimase kihi neuronite arv sõltub ülesandest.
5.4 Viimane kiht ja kaofunktsioon sõltuvad ülesandest
| Ülesanne | Viimane kiht | Kaofunktsioon (loss) | Sildid y |
|---|---|---|---|
| Regressioon (arv) | Dense(1) | "mse" | arvud, kuju (N,) |
| Kaks klassi | Dense(1, activation="sigmoid") | "binary_crossentropy" | 0 või 1, kuju (N,) |
| K klassi | Dense(K, activation="softmax") | "sparse_categorical_crossentropy" | täisarvud 0…K−1, kuju (N,) |
Pisinäide. Kolme klassi puhul annab viimane kiht kolm tõenäosust, näiteks [0.1, 0.7, 0.2]. Ennustatud klass on suurima tõenäosusega koht, siin klass 1 (seda leiab argmax, osa 2). Õige silt oleks sel juhul täisarv 1.
Kui sildid on one-hot kujul või tahad logiteid
Kui sildid on kirjutatud kujul [0, 1, 0] (one-hot), kasuta loss="categorical_crossentropy". Sellisel juhul on sildid kujuga (N, K).
Viimase kihi aktivatsiooni võib ka ära jätta (Dense(K)) ja anda kaofunktsioonile teada: keras.losses.SparseCategoricalCrossentropy(from_logits=True). Siis ei anna mudel tõenäosusi, vaid „toorarve“ (logiteid). Algajale on lihtsam esimene variant.
6Mänguväljak
Siin treenib brauseris päris väike MLP samade sammudega, mida fit() teeb. Taustavärv näitab, millise klassi võrk igas punktis ennustaks. Muuda seadeid ja vaata, kuidas piir muutub. Paremal on sama mudel Kerase koodina: seadistus ja kood käivad kokku.
- Vali aktivatsiooniks Puudub. Piir jääb sirgeks, ükskõik kui palju kihte või neuroneid lisad. See ongi põhjus, miks ReLU on vajalik.
- Vali Ring ringi sees, üks peidetud kiht ja 2 neuronit. Võrk ei suuda ringi ümbritseda (täpsus jääb umbes 87% peale). Lisa neuroneid ükshaaval ja leia, millal hakkab välja tulema.
- Vali Neli nurka (XOR) ja pane õppesammuks 0.3. Loss kõigub ega lange ühtlaselt. Pane tagasi 0.01: loss langeb rahulikult. Pane 0.001: õpib, aga aeglaselt.
- Võrdle partii suurusi 8 ja 200. Väikese partiiga tehakse ühes epohhis palju samme (kaalusid uuendatakse tihti), suure partiiga ainult üks. Sama epohhide arvu juures õpib väike partii tavaliselt kiiremini.
Mänguväljaku võrk on kirjutatud puhtas JavaScriptis ja ei kasuta TensorFlow'd. Ta arvutab sama, mida Keras: Glorot-algväärtused kaaludele, Adam ja binaarne risti-entroopia. Sellepärast näed siin samu mõjusid, mida päris Kerases.
7Täisnäide: poolkuud algusest lõpuni
Nüüd paneme kõik kokku: andmed, mudel, treenimine, hindamine ja ennustamine. Selle ühe ploki võid kopeerida oma märkmikusse ja käivitada.
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1. Andmed
X, y = make_moons(n_samples=1000, noise=0.2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 2. Mudel
keras.utils.set_random_seed(42)
model = keras.Sequential([
keras.Input(shape=(2,)),
layers.Dense(16, activation="relu"),
layers.Dense(16, activation="relu"),
layers.Dense(1, activation="sigmoid"),
])
# 3. Compile: viga ja parandaja
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.01),
loss="binary_crossentropy",
metrics=["accuracy"],
)
# 4. Treenimine (20% treeningandmetest jääb kõrvale kontrolliks)
history = model.fit(
X_train, y_train,
epochs=50,
batch_size=32,
validation_split=0.2,
verbose=0,
)
for e in (1, 10, 20, 30, 40, 50):
print(f"epohh {e:2d} viga {history.history['loss'][e - 1]:.3f}"
f" kontrolli viga {history.history['val_loss'][e - 1]:.3f}"
f" kontrolli täpsus {history.history['val_accuracy'][e - 1]:.1%}")
# 5. Hindamine testandmetel
loss, acc = model.evaluate(X_test, y_test, verbose=0)
print(f"testi täpsus: {acc:.1%}")epohh 1 viga 0.555 kontrolli viga 0.354 kontrolli täpsus 83.7%
epohh 10 viga 0.143 kontrolli viga 0.118 kontrolli täpsus 95.6%
epohh 20 viga 0.090 kontrolli viga 0.067 kontrolli täpsus 97.5%
epohh 30 viga 0.081 kontrolli viga 0.064 kontrolli täpsus 97.5%
epohh 40 viga 0.072 kontrolli viga 0.063 kontrolli täpsus 97.5%
epohh 50 viga 0.069 kontrolli viga 0.061 kontrolli täpsus 97.5%
testi täpsus: 97.0%Mida uued sõnad tähendavad
- validation_split=0.2: Keras paneb 20% treeningandmetest kõrvale ja kontrollib nende peal iga epohhi järel, kuidas mudelil läheb (
val_loss,val_accuracy). Nende andmete peal mudel ei õpi. - batch_size=32: partii on väike tükk andmeid. Keras uuendab kaalusid pärast iga partiid, mitte alles epohhi lõpus. See on kiirem ja õpib sageli paremini.
- Adam: SGD targem sugulane, mis kohandab sammu iga parameetri jaoks ise. Hea vaikevalik.
- metrics=["accuracy"]: lisaks veale näita ka täpsust (õigete ennustuste osa). Täpsus on inimesele arusaadav, viga on mudelile õppimiseks.
- history:
fit()tagastab sõnastiku, kus on iga epohhiloss,val_loss,accuracyjaval_accuracy.
batch_size=32 lõikab need 32-realisteks partiideks ja iga partii järel uuendatakse kaalusid. Keras näitab seda treenimisel kui 20/20.Treeningu viga ja kontrolli viga langevad koos ning täpsus on umbes 97%. Testi täpsus (97.0%) on peaaegu sama mis kontrolli täpsus: mudel töötab ka andmetega, mida ta pole näinud.
Ennusta uut punkti
Uue punkti peab skaleerima sama skaleerijaga, mida treeningandmetega kasutasime. Ja punkt peab olema kujuga (1, 2), seega kaks nurksulgu:
new = scaler.transform([[0.5, -0.3]]) # sama skaleerimine!
p = model.predict(new, verbose=0)
print(p) # tõenäosus, et klass on 1
print(int(p[0, 0] > 0.5)) # ennustatud klass[[0.9918686]]
1predict annab tõenäosuse, et klass on 1. Siin on see 0.99, seega ennustame klassi 1. Kahe klassi puhul on lävi 0.5: üle selle on klass 1, alla selle klass 0.
Kauem ei ole parem: EarlyStopping
Kui treenida liiga kaua, hakkab mudel treeningandmeid pähe õppima. Treeningu viga langeb edasi, aga kontrolli viga hakkab tõusma. Seda nimetatakse ülesobitamiseks.
history), paremal sama mudel 300 epohhi. Oranž punkt on kontrolli vea miinimum (epohh 70), kriipsjoon on koht, kus EarlyStopping treeningu peatas.Keras oskab treeningu õigel ajal ise peatada. Selleks on callback EarlyStopping: ta jälgib kontrolli viga ja peatab, kui see ei parane mitu epohhi järjest.
keras.utils.set_random_seed(42)
model = build([16, 16], "relu") # sama mudel nagu varem
stop = keras.callbacks.EarlyStopping(
monitor="val_loss", # jälgi kontrolli viga
patience=5, # oota 5 epohhi paranemist
restore_best_weights=True, # võta tagasi parimad kaalud
)
history = model.fit(X_train, y_train, epochs=200, batch_size=32,
validation_split=0.2, callbacks=[stop], verbose=0)
print("tehtud epohhe:", len(history.history["loss"]))
print(f"testi täpsus: {model.evaluate(X_test, y_test, verbose=0)[1]:.1%}")tehtud epohhe: 33
testi täpsus: 96.5%monitor="val_loss": jälgi kontrolli viga.patience=5: oota 5 epohhi, kas viga paraneb. Kui ei parane, peata.restore_best_weights=True: pärast peatamist võta tagasi parima epohhi kaalud.- Nüüd sai mudel hakkama 33 epohhiga ja testi täpsus on peaaegu sama (96.5%). Me ei pidanud epohhide arvu ise ära arvama.
Mudeli salvestamine
Treenitud mudeli saab ühte faili salvestada ja hiljem tagasi laadida:
model.save("moons.keras") # kogu mudel ühes failis
loaded = keras.models.load_model("moons.keras")
print(model.predict(new, verbose=0)) # algne mudel
print(loaded.predict(new, verbose=0)) # laetud mudel annab sama vastuse[[0.9881414]]
[[0.9881414]].keras fail sisaldab mudelit ja kaale, aga mitte StandardScalerit. Uute andmete skaleerimiseks salvesta skaleerija eraldi (joblib.dump(scaler, "scaler.joblib")) või pane skaleerimine mudeli sisse kihiga layers.Normalization.
Vaheta andmed välja: from sklearn.datasets import load_iris, X, y = load_iris(return_X_y=True). Mida pead mudelis muutma? Vihje: vaata tunnuste ja klasside arvu (need on 4 ja 3) ning osa 5.4 tabelit.
Lahendus
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0, stratify=y)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
keras.utils.set_random_seed(0)
model = keras.Sequential([
keras.Input(shape=(4,)), # 4 tunnust
layers.Dense(16, activation="relu"),
layers.Dense(3, activation="softmax"), # 3 klassi, tõenäosused
])
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.01),
loss="sparse_categorical_crossentropy", # sildid on täisarvud 0, 1, 2
metrics=["accuracy"])
model.fit(X_train, y_train, epochs=100, batch_size=16, verbose=0)
print(f"iirise testi täpsus: {model.evaluate(X_test, y_test, verbose=0)[1]:.1%}")iirise testi täpsus: 100.0%Muutus kolm asja: sisend on shape=(4,), viimane kiht on Dense(3, activation="softmax") ja kaofunktsioon on sparse_categorical_crossentropy. Sildid on juba täisarvud 0, 1 ja 2, seega neid muutma ei pea.
8Levinud vead
Siin on veateated, mida algajad kõige sagedamini näevad. Teated on päris, kopeeritud TensorFlow'st ja Kerasest.
| Mida näed | Põhjus | Paranda |
|---|---|---|
expected axis -1 of input shape to have value 2, but received input with shape (None, 4) | Andmetes on teine arv tunnuseid kui mudeli Input(shape=…). | Kontrolli X.shape. Esimene kiht: keras.Input(shape=(X.shape[1],)). |
Expected shape (None, 2), but input has incompatible shape (2,) või Unrecognized data type: x=[0.5, -0.3] | Ühe näite ennustamisel puudub näidete mõõde. | Kasuta kahte nurksulgu: [[0.5, -0.3]], kuju (1, 2). |
Received a label value of 3 which is outside the valid range of [0, 3) | sparse_categorical_crossentropy tahab silte 0…K−1, sul on 1…K. | Lahuta siltidest 1 või kodeeri sildid uuesti (LabelEncoder). |
Argument output must have rank (ndim) target.ndim - 1. Received: target.shape=(None, 3), output.shape=(None, 3) | Sildid on one-hot kujul, aga loss on sparse_…. | Kasuta "categorical_crossentropy" või muuda sildid täisarvudeks (y.argmax(axis=1)). |
Arguments target and output must have the same rank (ndim). Received: target.shape=(None,), output.shape=(None, 3) | Sildid on täisarvud, aga loss="categorical_crossentropy". | Kasuta "sparse_categorical_crossentropy". |
cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a double tensor | float32 ja float64 segamini (NumPy annab float64). | tf.cast(x, tf.float32) |
Cannot convert 0.5 to EagerTensor of dtype int32 | Täisarvuline tensor (tf.constant([1, 2])) ja komaga arv. | Kirjuta tensor komaga ([1., 2.]) või kasuta tf.cast. |
Argument(s) not recognized: {'lr': 0.01} | Vana õpetus. Keras 3-s on argumendi nimi learning_rate. | Adam(learning_rate=0.01) |
'Sequential' object has no attribute 'predict_classes' | Vana meetod on eemaldatud. | Kaks klassi: (model.predict(X) > 0.5).astype(int). Mitu klassi: model.predict(X).argmax(axis=1). |
UserWarning: Do not pass an input_shape/input_dim argument to a layer | Vana stiil: sisendi kuju on antud kihile. | Pane esimeseks keras.Input(shape=(…)). |
model.summary() näitab ? ja 0 (unbuilt) | Mudel ei tea veel sisendi kuju. | Lisa keras.Input(shape=…) või treeni mudelit korra. |
loss: nan | Liiga suur õppesamm, skaleerimata andmed või vale kaofunktsioon. | Vähenda learning_rate, skaleeri andmed, kontrolli osa 5.4 tabelit. |
| Täpsus jääb kinni klasside osakaalu juures | Aktivatsioon puudub kihtide vahel või viimases kihis on vale aktivatsioon. | Peidetud kihtidesse "relu", väljundisse sigmoid või softmax. |
Teine fit() ei alusta nullist | fit() jätkab sealt, kus mudel pooleli jäi. | Uue katse jaoks ehita mudel uuesti (keras.Sequential(...)). |
'EagerTensor' object does not support item assignment | Tavalist tensorit ei saa muuta. | Kasuta tf.Variable või tee uus tensor. |
Kui midagi ei tööta, prindi kujud: print(X.shape, y.shape) ja vaata model.summary(). Pooled vead selguvad nendest kahest reast.
Kontrolli ennast
Üheksa küsimust. Vali vastus, kohe näed, kas see oli õige ja miks.
Spikker
tf.constant([[1., 2.], [3., 4.]])
t.shape, t.dtype
tf.reshape(t, (4, 1))
tf.reduce_sum(t, axis=0)
a @ b # maatrikskorrutis
tf.cast(t, tf.float32)
t.numpy() # tagasi NumPy-ssemodel = keras.Sequential([
keras.Input(shape=(F,)),
layers.Dense(16, activation="relu"),
layers.Dense(16, activation="relu"),
layers.Dense(1, activation="sigmoid"),
])
model.summary()model.compile(
optimizer=keras.optimizers.Adam(
learning_rate=0.01),
loss="binary_crossentropy",
metrics=["accuracy"],
)
history = model.fit(
X_train, y_train,
epochs=50, batch_size=32,
validation_split=0.2,
)loss, acc = model.evaluate(X_test, y_test)
p = model.predict(X_uus) # tõenäosused
klass = (p > 0.5).astype(int) # 2 klassi
klass = p.argmax(axis=1) # mitu klassistop = keras.callbacks.EarlyStopping(
monitor="val_loss", patience=5,
restore_best_weights=True)
model.fit(..., callbacks=[stop])
model.save("mudel.keras")
model = keras.models.load_model("mudel.keras")# regressioon
Dense(1)
loss="mse"
# kaks klassi
Dense(1, activation="sigmoid")
loss="binary_crossentropy"
# K klassi (sildid 0..K-1)
Dense(K, activation="softmax")
loss="sparse_categorical_crossentropy"Mis edasi? Kui MLP on selge, on järgmised sammud ülesobitamise vastu Dropout ja BatchNormalization, suurte andmete jaoks tf.data, piltide jaoks konvolutsioonkihid (layers.Conv2D) ja eeltreenitud mudelid (keras.applications). Kõik need järgivad sama nelja sammu: mudel, compile, fit, predict.