Перейти к основному содержимому

Keras и TensorFlow — нейросети

Разработчику

TensorFlow — платформа глубокого обучения от Google — вычислительный граф, автоматическое дифференцирование, GPU/TPU, экспорт в TensorFlow Lite (мобильные устройства) и TensorFlow.js (браузер). Keras с TensorFlow 2.x встроен как высокоуровневый API (tf.keras) для быстрой сборки и обучения сетей.

Табличные задачи на старте проще закрыть scikit-learn — см. Scikit-learn. Keras уместен, когда нужны изображения, последовательности, эмбеддинги или глубокие архитектуры (CNN, LSTM, трансформеры). Теория нейрона и слоёв — Нейрон; массивы и матрицы — 337 — NumPy и Lab 1129; первый код без фреймворка — перцептрон на NumPy.

Связь с линейной алгеброй

Слой Dense — это умножение матрицы весов на batch признаков плюс смещение: те же операции, что в 343 — Матрицы и 337 — NumPy. Batch из 32 строк по 784 пикселя MNIST — матрица 32×784; веса первого слоя — 784×128.


ML и DL в одной картине

Scikit-learnKeras (TensorFlow)
ДанныеТаблицы, разреженные матрицыТензоры (изображения, последовательности)
ПризнакиЧасто готовят вручную (pandas)Извлекаются слоями сети
ОбучениеCPU, секунды–минутыGPU желателен для больших моделей
Типичные задачиЦена, отток, кластерыCV, NLP, аудио

Раздел глубокое обучение в Машинное обучение даёт расширенные примеры CNN и RNN; здесь — компактный практический маршрут.


Установка и проверка

pip install tensorflow

import tensorflow as tf

print(tf.__version__)
print("GPU:", tf.config.list_physical_devices("GPU"))

Мини-регрессия: y = k·x

Перед MNIST полезно обучить линейную модель на синтетике — один вход, один выход, активация linear, loss mse:


import os
os.environ.setdefault("TF_CPP_MIN_LOG_LEVEL", "2")

import numpy as np
import tensorflow as tf

x = np.array([[2.0], [5.0], [8.0], [10.0]], dtype=np.float32)
y = np.array([[6.0], [15.0], [24.0], [30.0]], dtype=np.float32) # y ≈ 3·x

model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(1,)),
tf.keras.layers.Dense(1, activation="linear"),
])
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.05), loss="mse")
history = model.fit(x, y, epochs=200, verbose=0)

print("веса:", model.get_weights())
print("предсказание для x=7:", model.predict(np.array([[7.0]]), verbose=0))

После обучения вес около 3, смещение около 0. Тот же приём — в перцептроне на NumPy, но там вы явно обновляете syn0.

Масштаб данных и nan

Если входы и ответы велики (например, x = 15…20, y = 45…60 при зависимости y = 3x), SGD с дефолтным шагом может «перепрыгнуть» минимум — веса уходят в бесконечность, loss становится nan. Решение: нормализовать данные (делить на 255 для пикселей, Min-Max для таблиц) или уменьшить масштаб синтетики (x = 1…10, y = 3…30), либо снизить learning_rate / взять Adam вместо sgd.

# Тот же y = 3·x, но «крупные» числа — часто nan при optimizer='sgd'
x_big = np.array([[15], [5], [12], [19], [20]], dtype=np.float32)
y_big = np.array([[45], [15], [36], [57], [60]], dtype=np.float32)

model_bad = tf.keras.Sequential([
tf.keras.layers.Input(shape=(1,)),
tf.keras.layers.Dense(1, activation="linear"),
])
model_bad.compile(optimizer="sgd", loss="mse")
# model_bad.fit(x_big, y_big, epochs=50, verbose=0) # может дать nan

x_ok = x_big / 10.0
y_ok = y_big / 10.0
model_bad.fit(x_ok, y_ok, epochs=100, verbose=0)
print(model_bad.predict(np.array([[2.0]]), verbose=0)) # ≈ [[6.]] — y = 3x

MNIST 6×6 — первый fit на картинках

Перед Fashion MNIST и CNN возьмите два класса MNIST (цифры 0 и 1), сожмите до 6×6 и нормализуйте пиксели — обучение займёт секунды на CPU:

import numpy as np
import tensorflow as tf

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
idx_tr = np.where((y_train == 0) | (y_train == 1))[0]
idx_te = np.where((y_test == 0) | (y_test == 1))[0]
x_tr, y_tr = x_train[idx_tr], y_train[idx_tr]
x_te, y_te = x_test[idx_te], y_test[idx_te]

x_tr = (x_tr / 255.0).astype(np.float32)
x_te = (x_te / 255.0).astype(np.float32)
x_tr = tf.image.resize(x_tr[..., np.newaxis], (6, 6)).numpy()[..., 0]
x_te = tf.image.resize(x_te[..., np.newaxis], (6, 6)).numpy()[..., 0]

y_tr_cat = tf.keras.utils.to_categorical(y_tr, num_classes=2)
y_te_cat = tf.keras.utils.to_categorical(y_te, num_classes=2)

model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(6, 6)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(2, activation="sigmoid"),
])
model.compile(optimizer="sgd", loss="binary_crossentropy", metrics=["accuracy"])
model.fit(x_tr, y_tr_cat, epochs=5, verbose=1)
print("test accuracy:", model.evaluate(x_te, y_te_cat, verbose=0)[1])
print("probabilities:", model.predict(x_te[:3], verbose=0))

Flatten превращает 6×6 в вектор длины 36; to_categorical — метки в one-hot; для классификации MSE не подходит — нужны binary_crossentropy и сигмоида (или один выход + sparse_categorical_crossentropy + softmax). Самопроверка: для первых 20 тестовых изображений сравните np.argmax(predict(...)) с y_te[:20] и сверьте долю совпадений с model.evaluate.


Fashion MNIST — сложнее MNIST

Fashion MNIST — 60 000 обучающих и 10 000 тестовых изображений 28×28 (один канал), 10 классов одежды (футболка, брюки, кроссовки…). Формат как у классического MNIST, но задача ближе к «реальному» CV.


(fashion_x, fashion_y), (test_x, test_y) = tf.keras.datasets.fashion_mnist.load_data()
fashion_x = fashion_x.astype("float32") / 255.0
test_x = test_x.astype("float32") / 255.0

model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(28, 28)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation="relu"),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation="softmax"),
])
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(fashion_x, fashion_y, epochs=5, batch_size=128, validation_split=0.1)

Тот же датасет на PyTorchпрактикум MNIST (замените загрузчик на torchvision.datasets.FashionMNIST). Сравнение фреймворков — таблица в разделе PyTorch — альтернатива ниже.


CIFAR-10 — цветные 32×32

CIFAR-10 — 60 000 RGB-изображений 32×32, 10 классов (самолёт, автомобиль, птица, кот, олень, собака, лягушка, лошадь, корабль, грузовик). Форма одного кадра: (32, 32, 3) — высота, ширина, три канала (R, G, B). В отличие от MNIST, канал один (grayscale).

import tensorflow as tf

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
print("shape одного изображения:", x_train[0].shape) # (32, 32, 3)

class_names = [
"airplane", "automobile", "bird", "cat", "deer",
"dog", "frog", "horse", "ship", "truck",
]

model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(32, 32, 3)),
tf.keras.layers.Conv2D(32, (3, 3), activation="relu", padding="same"),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation="relu", padding="same"),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation="relu"),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Dense(10, activation="softmax"),
])
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(x_train, y_train, epochs=10, batch_size=64, validation_split=0.1)

На CPU первые эпохи могут давать низкую accuracy (~1–5% на старте) — нормально для случайных весов; подбирайте число фильтров, Dropout, эпохи или переносите обучение в Colab с GPU. Загрузка своих JPG с диска — tf.keras.utils.image_dataset_from_directory(..., color_mode="rgb").

Табличные данные в Keras

Перед изображениями полезно сравнить sklearn и Keras на одной таблице — Lab 1157 — Titanic (логистическая регрессия, дерево, Dense-сеть).


Sequential — слои друг за другом

Модель для табличных или простых задач (бинарная классификация после нормализации):

Код ITЗагрузка примера кода…

Параметр compileКогда использовать
binary_crossentropyДва класса, выход sigmoid
sparse_categorical_crossentropyНесколько классов, метки — целые числа 0…K-1
categorical_crossentropyНесколько классов, метки — one-hot
mseРегрессия, выход linear

Оптимизатор по умолчанию — adam; скорость обучения можно задать явно: optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3).

Перед fit полезно посмотреть архитектуру:

model.summary() # число параметров по слоям

Для схемы слоёв (нужен pip install pydot graphviz):

tf.keras.utils.plot_model(model, to_file="model.png", show_shapes=True)

Цикл обучения: Keras и PyTorch

Идеи одни и те же; отличается синтаксис.

ШагKeras (tf.keras)PyTorch
СборкаSequential / Modelnn.Module
Функция потерьв compile(loss=...)nn.CrossEntropyLoss() и др.
Оптимизаторв compile(optimizer=...)torch.optim.Adam(...)
Одна эпохаmodel.fit(X, y, epochs=...)цикл: forwardlossbackwardoptimizer.step()
Валидацияvalidation_split или validation_dataотдельный цикл без backward на val
Метрикиmetrics=["accuracy"] в compileсчитаете вручную или через torchmetrics
Сохранениеmodel.save("model.keras")torch.save(model.state_dict(), ...)

Сквозной пример на PyTorch — PyTorch для разработчика и практикум MNIST.


Гиперпараметры и регуляризация

ГиперпараметрЧто делаетТипичный старт
learning_rateШаг обновления весов1e-3 для Adam
Число слоёв / нейроновЁмкость модели2–3 скрытых слоя по 64–128
batch_sizeПримеров за один шаг32–128
epochsПроходов по train10–50; с EarlyStopping — до 100
Функция активацииНелинейностьReLU в скрытых, sigmoid/softmax на выходе
Dropout(p)Случайно "выключает" долю нейронов на train0.2–0.5 между Dense-слоями

Признаки переобучения: loss на train падает, на validation растёт — см. смещение и дисперсия. Рычаги — упростить сеть, добавить Dropout, раньше остановить обучение, больше данных или аугментация (Data Science — подготовка для ML).

Модель с Dropout и L2-регуляризацией:

from tensorflow.keras import Sequential, regularizers
from tensorflow.keras.layers import Dense, Dropout

model = Sequential([
Dense(128, activation="relu", kernel_regularizer=regularizers.l2(0.01), input_shape=(100,)),
Dropout(0.5),
Dense(64, activation="relu", kernel_regularizer=regularizers.l2(0.01)),
Dropout(0.3),
Dense(1, activation="sigmoid"),
])
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])

MNIST — первая свёрточная сеть

Код ITЗагрузка примера кода…

Свёрточные слои (Conv2D) ищут локальные паттерны (штрихи, углы); пулинг уменьшает размер карты признаков. Такие сети — основа распознавания объектов и лиц.


Functional API — ветвления и несколько входов

Когда нужны общие слои, несколько входов или выходов:

inputs = tf.keras.Input(shape=(100,))
x = tf.keras.layers.Dense(128, activation="relu")(inputs)
x = tf.keras.layers.Dropout(0.5)(x)
outputs = tf.keras.layers.Dense(10, activation="softmax")(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)
model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])

Callbacks и ранняя остановка

log_dir = "logs/fit"
callbacks = [
tf.keras.callbacks.EarlyStopping(
monitor="val_loss", patience=5, restore_best_weights=True
),
tf.keras.callbacks.ModelCheckpoint(
"best.keras", monitor="val_accuracy", save_best_only=True
),
tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1),
]

history = model.fit(
X_train, y_train,
epochs=100,
batch_size=32,
validation_split=0.2,
callbacks=callbacks,
)

EarlyStopping останавливает обучение, когда validation перестаёт улучшаться — защита от переобучения. ModelCheckpoint сохраняет лучшие веса по выбранной метрике. Подробнее — смещение и дисперсия и разбиение train/validation/test.


Визуализация: matplotlib и TensorBoard

После fit Keras возвращает объект History — метрики по эпохам удобно строить в matplotlib:


import matplotlib.pyplot as plt

plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(history.history["loss"], label="train")
plt.plot(history.history["val_loss"], label="val")
plt.title("Loss")
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(history.history["accuracy"], label="train")
plt.plot(history.history["val_accuracy"], label="val")
plt.title("Accuracy")
plt.legend()
plt.tight_layout()
plt.show()

Если кривые train и val расходятся — модель переобучается; если обе плохие — недообучение или мало данных/признаков.

TensorBoard пишет те же метрики в каталог логов (см. callback выше). Локально:

tensorboard --logdir logs/fit

В Google Colab после обучения:

%load_ext tensorboard
%tensorboard --logdir logs/fit

В TensorBoard смотрят вкладки Scalars (loss, accuracy), Graphs (вычислительный граф) и Histograms (распределение весов). Общие приёмы matplotlib для аналитики — lab/1112.


Google Colab — обучение без локального GPU

Google Colab — Jupyter в браузере с бесплатным GPU (лимиты по времени). Удобен для учебных CNN/LSTM, когда на ноутбуке нет видеокарты.

  1. Runtime → Change runtime type → T4 GPU (или аналог).
  2. Установка зависимостей в первой ячейке: !pip install -q tensorflow.
  3. Проверка: import tensorflow as tf; print(tf.config.list_physical_devices("GPU")).
  4. Датасеты — tf.keras.datasets (MNIST, CIFAR-10) или загрузка с Google Drive (from google.colab import drive; drive.mount("/content/drive")).
  5. Длинные ноутбуки сохраняйте на Drive; веса — model.save("/content/drive/MyDrive/model.keras").

Карта Colab-проектов (классификация изображений, генерация текста, эмоции) — в Практикуме — проекты по ИИ. Облачный контекст — GCP и Colab.


Сохранение и инференс

model.save("model.keras")
restored = tf.keras.models.load_model("model.keras")
restored.predict(X_test[:5])

Для мобильных устройств — экспорт в TFLite; для сервера — SavedModel или ONNX. Обзор продакшен-развёртывания — Применение ИИ в продакшене.


Текст — TextVectorization и Embedding

После TF-IDF в sklearn нейросеть учит эмбеддинги — таблицу векторов для каждого токена (слова или subword).

ЭтапСлой / инструментРоль
ТокенизацияTextVectorizationТекст → последовательность целых индексов
Смысл словаEmbedding(vocab_size, dim)Индекс → обучаемый вектор длины dim
АгрегацияGlobalAveragePooling1D или LSTMПоследовательность → один вектор / контекст
КлассDense + sigmoid/softmaxВероятности классов
import os
os.environ.setdefault("TF_CPP_MIN_LOG_LEVEL", "2")
import tensorflow as tf

texts = [
"great product love it",
"terrible waste of money",
"good quality fast delivery",
"broken item very disappointed",
"excellent service",
"worst purchase ever",
]
labels = [1, 0, 1, 0, 1, 0] # 1 — positive

max_tokens = 500
vectorizer = tf.keras.layers.TextVectorization(
max_tokens=max_tokens,
output_sequence_length=12,
)
vectorizer.adapt(texts)

model = tf.keras.Sequential([
vectorizer,
tf.keras.layers.Embedding(max_tokens, 16),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(1, activation="sigmoid"),
])
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
model.fit(texts, labels, epochs=80, verbose=0)

print(model.predict(["amazing deal"], verbose=0))

vectorizer.adapt(texts) строит словарь только на train — на production те же тексты через vectorizer без повторного adapt. Для нескольких классов эмоций — Dense(K, activation="softmax") и sparse_categorical_crossentropy; метки сначала в числа 0…K−1.

PyTorch-аналог — практикум тональности. Дальше по NLP — трансформеры.

Самопроверка: обучите на датасете эмоций (6 классов): LabelEncoder для y, увеличьте max_tokens и output_sequence_length.


RNN и LSTM — последовательности

RNN и LSTM обрабатывают данные по шагам, передавая скрытое состояние во времени. Подходят для временных рядов, текста (до трансформеров), сенсоров.

СлойИдея
SimpleRNNБазовая рекуррентная ячейка; на длинных цепочках — затухание градиента
LSTMВентили «запомнить / забыть»; стабильнее на длинных зависимостях

Мини-пример: предсказать следующее значение ряда по окну из 10 прошлых точек:

import numpy as np
import tensorflow as tf

np.random.seed(42)
t = np.arange(300, dtype=float)
series = np.sin(0.08 * t) + 0.05 * np.random.randn(300)

window = 10
X, y = [], []
for i in range(len(series) - window):
X.append(series[i : i + window])
y.append(series[i + window])
X = np.array(X)[..., np.newaxis] # (samples, window, 1)
y = np.array(y)

split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]

model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(window, 1)),
tf.keras.layers.LSTM(32),
tf.keras.layers.Dense(1),
])
model.compile(optimizer="adam", loss="mse")
model.fit(X_train, y_train, epochs=40, batch_size=32, verbose=0)
print("test MSE:", model.evaluate(X_test, y_test, verbose=0))

Для текста вместо одного числа на шаг — вектор из Embedding; часто добавляют второй LSTM (return_sequences=False) или BiLSTM — обзор в 6-03/113. Готовые LLM локально — разработка ИИ / HuggingFace.


PyTorch — альтернатива

PyTorch (Meta) популярен в исследованиях и среди LLM/CV-команд: динамический граф, torch.nn, экосистема Hugging Face. Идеи те же (слои, loss, optimizer); синтаксис другой.

Практический вход с установкой, autograd, градиентным спуском и сквозным пайплайном — в статье PyTorch для разработчика. После перцептрона на NumPy это естественный следующий шаг.

ВыборОриентир
Учебник, Kaggle, корпоративный Google-стекTensorFlow / Keras
Исследование, кастомные архитектуры, HF-моделиPyTorch

Дальше по маршруту

  1. Архитектуры — когда Dense, CNN, LSTM — матрица выбора по типу данных.
  2. Transfer learning — EfficientNet, заморозка слоёв.
  3. Практикум DL в Colab — классификация, char-RNN, эмоции.
  4. Распознавание лиц, объектов и текста — YOLO, OCR, NER.
  5. Облачные Cognitive API — если своё обучение не нужно.
  6. Большие языковые модели — трансформеры поверх тех же идей эмбеддингов.