🧠 Keras
Полный справочник Keras 3: бэкенды, Sequential и Functional API, слои, компиляция и обучение, колбэки, регуляризация, CNN и RNN и трансформеры, transfer learning, сохранение, KerasTuner и частые ошибки.
Шпаргалки · ИИ · #keras #deep-learning #python #tensorflow #neural-networks
Что это
Keras высокоуровневый API нейросетей. Keras 3 мультибэкенд: тот же код работает на TensorFlow, PyTorch или JAX.
pip install keras tensorflow # или keras torch / keras jax
export KERAS_BACKEND=torch # tensorflow | torch | jax (до импорта keras)
import keras
from keras import layers, ops
keras.utils.set_random_seed(42) # воспроизводимость
Операции над тензорами пишите через keras.ops (ops.matmul, ops.sum), чтобы код не зависел от бэкенда. Старый tf.keras остаётся как алиас в TensorFlow, но новый код лучше писать на keras.
Три способа построить модель
# 1. Sequential — цепочка слоёв
model = keras.Sequential([
layers.Input(shape=(28, 28, 1)),
layers.Conv2D(32, 3, activation="relu"),
layers.MaxPooling2D(),
layers.Flatten(),
layers.Dense(10, activation="softmax"),
])
# 2. Functional API — ветвления, несколько входов и выходов, общие слои
inp = keras.Input(shape=(64,), name="features")
x = layers.Dense(128, activation="relu")(inp)
skip = layers.Dense(128)(inp)
x = layers.Add()([x, skip]); x = layers.LayerNormalization()(x)
out = layers.Dense(1, activation="sigmoid", name="p")(x)
model = keras.Model(inp, out)
# 3. Подклассы — полная свобода
class MLP(keras.Model):
def __init__(self, n=10):
super().__init__(); self.d1 = layers.Dense(64, activation="relu"); self.d2 = layers.Dense(n)
def call(self, x, training=False): return self.d2(self.d1(x))
model.summary() показывает слои, формы и число параметров; keras.utils.plot_model(model, show_shapes=True) рисует схему.
Основные слои
| Группа | Слои |
|---|---|
| Полносвязные | Dense, EinsumDense |
| Свёртки | Conv1D, Conv2D, Conv3D, SeparableConv2D, DepthwiseConv2D, Conv2DTranspose |
| Пулинг | MaxPooling2D, AveragePooling2D, GlobalAveragePooling2D, GlobalMaxPooling1D |
| Рекуррентные | LSTM, GRU, SimpleRNN, Bidirectional(LSTM(64)), RNN |
| Внимание, трансформер | MultiHeadAttention, LayerNormalization, Embedding, PositionEmbedding (KerasHub) |
| Нормализация | BatchNormalization, LayerNormalization, GroupNormalization, UnitNormalization, Normalization |
| Регуляризация | Dropout, SpatialDropout2D, GaussianNoise, ActivityRegularization |
| Форма | Flatten, Reshape, Permute, RepeatVector, Concatenate, Add, Multiply, Lambda |
| Предобработка | Rescaling, Resizing, Normalization, TextVectorization, StringLookup, IntegerLookup, Discretization, CategoryEncoding, Hashing |
| Аугментация | RandomFlip, RandomRotation, RandomZoom, RandomContrast, RandomTranslation, RandomCrop |
Активации: relu, gelu, swish (silu), leaky_relu, tanh, sigmoid, softmax, linear. Инициализаторы: glorot_uniform (по умолчанию), he_normal (для ReLU).
Компиляция
model.compile(
optimizer=keras.optimizers.AdamW(learning_rate=1e-3, weight_decay=1e-4),
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=["accuracy", keras.metrics.AUC(name="auc")],
)
| Задача | Последний слой | Потеря |
|---|---|---|
| Бинарная | Dense(1, "sigmoid") |
binary_crossentropy |
| Многоклассовая (целые метки) | Dense(N, "softmax") |
sparse_categorical_crossentropy |
| Многоклассовая (one-hot) | Dense(N, "softmax") |
categorical_crossentropy |
| Мультилейбл | Dense(N, "sigmoid") |
binary_crossentropy |
| Регрессия | Dense(1) (без активации) |
mse, mae, huber |
Если последний слой без softmax (логиты), задайте from_logits=True в потере. Скорость обучения можно менять расписанием: keras.optimizers.schedules.CosineDecay(1e-3, decay_steps); оптимизаторы: Adam, AdamW, SGD(momentum=0.9, nesterov=True), RMSprop, Lion; clipnorm=1.0 против взрыва градиентов.
Обучение и оценка
history = model.fit(
X_train, y_train, # массивы NumPy, tf.data.Dataset, torch DataLoader, генераторы
epochs=50, batch_size=64,
validation_split=0.2, # или validation_data=(X_val, y_val)
class_weight={0: 1.0, 1: 5.0}, # для несбалансированных классов
callbacks=[...], verbose=2, shuffle=True,
)
model.evaluate(X_test, y_test); model.predict(X_new, batch_size=256); model.predict_on_batch(x)
history.history["val_loss"] # кривые для графика
model.train_on_batch(x, y); model.test_on_batch(x, y)
predict возвращает вероятности: для классов np.argmax(p, axis=1).
Колбэки
callbacks = [
keras.callbacks.EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True),
keras.callbacks.ModelCheckpoint("best.keras", monitor="val_loss", save_best_only=True),
keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.5, patience=2, min_lr=1e-6),
keras.callbacks.TensorBoard(log_dir="logs"),
keras.callbacks.CSVLogger("train.csv"),
keras.callbacks.LearningRateScheduler(lambda epoch, lr: lr * 0.95),
keras.callbacks.TerminateOnNaN(),
]
class MyCb(keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs=None): print(epoch, logs["val_accuracy"])
Регуляризация против переобучения
Dropout(0.2–0.5)между слоями,BatchNormalization.kernel_regularizer=keras.regularizers.l2(1e-4)илиl1.- Аугментация данных (особенно изображения), больше данных.
- Меньше модель, ранняя остановка,
weight_decayвAdamW. - Нормализуйте входы (
Rescaling(1/255),Normalization()сadapt(X_train)).
Готовые архитектуры: примеры
# CNN для изображений
model = keras.Sequential([
layers.Input((32, 32, 3)), layers.RandomFlip("horizontal"), layers.Rescaling(1/255),
layers.Conv2D(32, 3, padding="same", activation="relu"), layers.BatchNormalization(), layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding="same", activation="relu"), layers.BatchNormalization(), layers.MaxPooling2D(),
layers.GlobalAveragePooling2D(), layers.Dropout(0.3), layers.Dense(10, activation="softmax"),
])
# Текст: LSTM
vec = layers.TextVectorization(max_tokens=20000, output_sequence_length=200); vec.adapt(train_texts)
model = keras.Sequential([layers.Input((1,), dtype="string"), vec, layers.Embedding(20000, 128, mask_zero=True),
layers.Bidirectional(layers.LSTM(64)), layers.Dropout(0.3), layers.Dense(1, activation="sigmoid")])
# Временной ряд
model = keras.Sequential([layers.Input((60, 5)), layers.LSTM(64, return_sequences=True), layers.LSTM(32), layers.Dense(1)])
# Блок трансформера
def block(x, heads=4, dim=128):
a = layers.MultiHeadAttention(num_heads=heads, key_dim=dim // heads)(x, x)
x = layers.LayerNormalization()(x + a)
f = layers.Dense(dim * 4, activation="gelu")(x); f = layers.Dense(dim)(f)
return layers.LayerNormalization()(x + f)
# Автоэнкодер
enc = keras.Sequential([layers.Input((784,)), layers.Dense(64, activation="relu"), layers.Dense(16)])
dec = keras.Sequential([layers.Input((16,)), layers.Dense(64, activation="relu"), layers.Dense(784, activation="sigmoid")])
Transfer learning
base = keras.applications.EfficientNetB0(weights="imagenet", include_top=False, input_shape=(224, 224, 3))
base.trainable = False # шаг 1: обучаем только голову
inp = keras.Input((224, 224, 3))
x = base(inp, training=False) # BatchNorm в режиме инференса
x = layers.GlobalAveragePooling2D()(x); x = layers.Dropout(0.3)(x)
out = layers.Dense(5, activation="softmax")(x)
model = keras.Model(inp, out)
model.compile(optimizer=keras.optimizers.Adam(1e-3), loss="sparse_categorical_crossentropy", metrics=["accuracy"])
model.fit(train_ds, validation_data=val_ds, epochs=5)
base.trainable = True # шаг 2: дообучение (fine-tuning) верхних слоёв с малым lr
for layer in base.layers[:-30]: layer.trainable = False
model.compile(optimizer=keras.optimizers.Adam(1e-5), loss="sparse_categorical_crossentropy", metrics=["accuracy"])
model.fit(train_ds, validation_data=val_ds, epochs=10)
Каталог keras.applications: ResNet50, MobileNetV3, EfficientNetV2, ConvNeXt, VGG16. Предобученные текстовые и мультимодальные модели: KerasHub (keras_hub), BERT, Gemma, Llama.
Свои слои, потери, метрики и шаг обучения
@keras.saving.register_keras_serializable()
class Scale(layers.Layer):
def __init__(self, factor=2.0, **kw): super().__init__(**kw); self.factor = factor
def build(self, shape): self.w = self.add_weight(shape=(shape[-1],), initializer="ones", trainable=True)
def call(self, x): return x * self.w * self.factor
def get_config(self): return {**super().get_config(), "factor": self.factor}
def focal_loss(y_true, y_pred, gamma=2.0):
p = ops.where(y_true == 1, y_pred, 1 - y_pred); return -ops.mean((1 - p) ** gamma * ops.log(p + 1e-7))
Для нестандартного обучения переопределите train_step в подклассе keras.Model (код зависит от бэкенда: GradientTape в TF, loss.backward() в PyTorch, jax.value_and_grad в JAX).
Данные и предобработка
train_ds = keras.utils.image_dataset_from_directory("data", validation_split=0.2, subset="training", seed=1, image_size=(224, 224), batch_size=32)
class_names = train_ds.class_names
norm = layers.Normalization(); norm.adapt(X_train) # статистики по обучающей выборке
keras.utils.to_categorical(y, num_classes=10) # one-hot
Предобработку включайте в модель: на инференсе вход тот же, что и на обучении.
Сохранение и загрузка
model.save("model.keras") # архитектура + веса + состояние оптимизатора
model = keras.saving.load_model("model.keras", custom_objects={"Scale": Scale})
model.save_weights("m.weights.h5"); model.load_weights("m.weights.h5")
model.export("serving_dir") # SavedModel (бэкенд TensorFlow): для TF Serving, TFLite
Потенциально опасно загружать чужие модели с Lambda-слоями: используйте safe_mode=True (по умолчанию).
Подбор гиперпараметров
import keras_tuner as kt
def build(hp):
m = keras.Sequential([layers.Input((20,)), layers.Dense(hp.Int("units", 32, 256, step=32), activation="relu"), layers.Dense(1, activation="sigmoid")])
m.compile(optimizer=keras.optimizers.Adam(hp.Choice("lr", [1e-2, 1e-3, 1e-4])), loss="binary_crossentropy", metrics=["accuracy"]); return m
tuner = kt.Hyperband(build, objective="val_accuracy", max_epochs=30); tuner.search(X, y, validation_split=0.2); tuner.get_best_hyperparameters(1)[0].values
Альтернативы: Optuna, Ray Tune.
Диагностика
| Симптом | Причина и действия |
|---|---|
val_loss растёт, loss падает |
переобучение: Dropout, регуляризация, аугментация, ранняя остановка, меньше модель |
| Обе метрики плохие | недообучение: больше слоёв и нейронов, дольше, выше lr, лучше признаки |
Потеря nan |
lr слишком велик, нет нормализации, log(0), clipnorm, TerminateOnNaN |
| Точность на уровне случайной | неверные метки или формат метки и потери, нет перемешивания, нет обучения (trainable=False у всего) |
| Ошибка формы | сверьте model.summary() и X.shape; для CNN (H, W, C); метки (N,) или (N, C) |
| Нестабильные результаты | keras.utils.set_random_seed, больше данных, ансамбли |
| Очень медленно | батч больше, tf.data с prefetch, mixed_float16 (keras.mixed_precision.set_global_policy), GPU |
Быстрая проверка кода: обучите на 10–100 примерах, потеря должна упасть почти до нуля.
Практика
- Начинайте с простой модели и бейзлайна (линейная или дерево) и сравнивайте.
- Делите данные заранее на train / val / test; тест трогайте один раз.
- Нормализуйте входы, балансируйте классы, следите за утечками.
- Для табличных данных нейросети часто уступают градиентному бустингу.
- Фиксируйте версии
keras, бэкенда и сохраняйте конфигурацию эксперимента (MLflow, Weights & Biases). - Экосистема: KerasHub (готовые модели), KerasCV / KerasNLP (теперь в KerasHub), KerasTuner, TensorBoard, TF Serving, TFLite, ONNX.