Обучение нейросети: как настроить гиперпараметры и избежать переобучения
От замысла к реальности — как «оживить» вашу нейросеть
Вы уже проделали огромный путь: определили цель нейросети, подобрали инструменты, собрали данные и спроектировали архитектуру. Это как построить космический корабль: у вас есть чертежи, материалы и команда инженеров. Но чтобы он полетел, нужно запустить двигатели — и здесь начинается самое интересное.
Напомним, что мы уже сделали:
Поняли цель — зачем нейросеть нужна: предсказывать, классифицировать, генерировать?
Выбрали инструменты — TensorFlow, PyTorch или, может, Keras? Как подобрать «рабочий стол» для вашего ИИ-творца.
Подготовили данные — очистили, разметили, превратили сырую информацию в «топливо» для обучения.
Построили архитектуру — словно спроектировали мозг: слои, нейроны, функции активации.
Но пока это лишь «мертвая» структура. Чтобы она задышала, нужны обучение и проверка. Представьте, что вы дали ребенку учебник, но ни разу не проверили, как он усвоил материал. С нейросетью то же самое: без тренировки на данных и тестов она останется слепым котенком в мире алгоритмов.
Зачем это нужно
Обучение — это «натаскивание» модели: она ищет закономерности, подстраивает параметры и учится отвечать на ваши вопросы.
Проверка — экзамен на зрелость: убедиться, что нейросеть не просто запомнила примеры, а поняла правила игры.
Если пропустить этот этап, можно получить модель, которая блестяще отвечает на тренировочные задачи… и проваливается в реальном мире. Как избежать этого? Давайте разбираться!
Почему это важно
«Любая нейросеть — это как ученик-отличник, который может завалить экзамен из-за стресса. Ваша задача — подготовить её ко всем неожиданностям».
Готовы превратить «теоретика» в «практика»? Переходим к первому шагу — разделению данных.
Содержание
ToggleРазделение данных: как не превратить нейросеть в «зубрилку»
Представьте, что вы учите студента решать задачи. Если дать ему все ответы заранее, на экзамене он блеснет… но только если вопросы совпадут с шаблоном. А если нет? Нейросеть — тот же студент. Чтобы она научилась мыслить, а не запоминать, данные нужно разделить на «учебник» и «экзаменационный билет».
Зачем делить данные
Спасти модель от «зазубривания» (переобучения)
Нейросеть-отличник, которая идеально решает тренировочные задачи, но пасует на новых данных — классическая проблема.
Пример: Модель для распознавания котиков, обученная только на фото белых персов, не узнает сфинкса в темноте.
Проверить, понимает ли модель суть
Тестовый набор — это «взрослая жизнь» для ИИ. Если он справляется здесь, значит уловил закономерности, а не случайные шумы.
Как разделить данные без ошибок
Шаг 1. Выбрать пропорции
80/20 или 70/30 — золотая середина. 80% данных модель использует для обучения, 20% — как «экзамен».
Важно! Для маленьких датасетов (например, 1000 строк) лучше 90/10, иначе модели не хватит примеров для обучения.
Шаг 2. Использовать правильные инструменты
В Python это делается в одну строку:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
random_state фиксирует случайность — чтобы результаты были воспроизводимы.
Шаг 3. Проверить баланс
Если в данных 95% спама и 5% нормальных писем, после разделения пропорции должны сохраниться. Иначе модель не научится видеть редкие классы.
Совет для профи: Для несбалансированных данных используйте стратификацию. Код превращается в:
train_test_split(..., stratify=y)
Это как заставить нейросеть учиться на равных примерах «сложных» и «простых» случаев.
Ошибки, которые взорвут вашу модель
«Утечка данных»: Случайно добавили признаки из теста в тренировочный набор? Модель подсмотрит ответы и сжульничает на экзамене.
Нормализация до разделения: Если сначала масштабировать все данные, а потом делить, информация из теста «просочится» в обучение. Сначала разделяйте — потом обрабатывайте!
Почему это важно
«Хорошее разделение данных — как честные правила игры. Без них вы получите модель-жулика, а не модель-гения».
Теперь, когда данные готовы, переходим к главному — настройке параметров обучения. Узнаете, как выбрать скорость обучения, чтобы нейросеть не «перегрелась» и не уснула.
Настройка параметров обучения: как дирижировать оркестром из гиперпараметров
Представьте, что нейросеть — это музыкальный инструмент. Даже самый дорогой рояль будет фальшивить, если его не настроить. Гиперпараметры — это те «винты» и «струны», от которых зависит, зазвучит ли ваша модель симфонией или какофонией. Давайте настраивать!
Ключевые гиперпараметры: что крутить и за что отвечает
Эпохи (epochs): когда остановиться, чтобы не «переиграть»
Эпоха — это один полный прогон всех данных через нейросеть. Слишком много эпох — модель запомнит шумы (переобучится), слишком мало — не успеет понять закономерности (недообучится).
Как не сойти с ума
Используйте раннюю остановку (Early Stopping). Это как умный будильник, который прерывает обучение, когда модель перестает улучшаться:
from tensorflow.keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(
monitor='val_loss', # Следим за ошибкой на валидации
patience=5, # Ждём 5 эпох без улучшений
restore_best_weights=True # Возвращаем лучшие веса
)
model.fit(..., callbacks=[early_stopping])
Совет: Начните с 50-100 эпох. Если видите, что валидационная ошибка растет, а тренировочная падает — это красный флаг переобучения.
Скорость обучения (learning rate): шаги гения или спринт в никуда
Скорость обучения — это размер шага, с которым модель корректирует свои веса.
Слишком высокая (например, 0.1): Модель «прыгает» мимо оптимальных значений, как мячик по ступенькам. Результат: расходимость, NaN-ы в лоссе. NaN (Not a Number) — это специальное значение, которое возникает в числовых вычислениях, когда операция не может вернуть корректный результат. В контексте обучения нейросетей NaN в лоссе означает, что в процессе вычисления функции потерь произошла ошибка, из-за которой значение потерь стало неопределённым или бесконечным. Это критическая проблема, которая прерывает обучение модели.
Слишком низкая (например, 0.00001): Обучение длится вечность, модель «застревает» в локальных минимумах.
Золотая середина:
Начните с 0.001 (стандарт для оптимизаторов вроде Adam).
Используйте планировщики скорости обучения, чтобы автоматически менять шаг:
from tensorflow.keras.optimizers.schedules import ExponentialDecay
lr_schedule = ExponentialDecay(
initial_learning_rate=0.001,
decay_steps=10000,
decay_rate=0.9
)
optimizer = Adam(learning_rate=lr_schedule)
Размер батча (batch size): команда или одиночный забег
Большой батч (512+): Обучение быстрее, но модель делает грубые шаги. Риск «проскочить» минимум.
Маленький батч (8-32): Точнее настраивает веса, но требует больше времени и памяти.
Правило: Выбирайте максимальный размер, который влезает в память GPU. Популярные значения — 32, 64, 128.
Инструменты для автоматизации: пусть роботы работают за вас
Grid Search vs Random Search: метод тыка по науке
Grid Search — перебор всех комбинаций параметров по сетке. Точный, но медленный.
Random Search — случайный поиск в заданных диапазонах. Быстрее, часто эффективнее.
Пример для Scikit-learn:
from sklearn.model_selection import RandomizedSearchCV
param_dist = {
'learning_rate': [0.001, 0.01, 0.1],
'batch_size': [32, 64, 128],
'epochs': [50, 100]
}
search = RandomizedSearchCV(estimator=model, param_distributions=param_dist, n_iter=10)
search.fit(X_train, y_train)
Оптимизаторы: «Мозги» обучения
Adam — универсал, подходит для 90% задач. Сам адаптирует скорость обучения.
SGD — требует тонкой настройки, но может дать лучшие результаты на глубоких сетях.
Код для Keras:
from tensorflow.keras.optimizers import Adam, SGD
# Для Adam
model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy')
# Для SGD с моментом
model.compile(optimizer=SGD(learning_rate=0.01, momentum=0.9), loss='mse')
Лайфхаки от профи
Не фиксируйте random_state при финальных экспериментах — убедитесь, что модель устойчива к разным разбиениям данных.
Визуализируйте обучение: Графики лосса покажут, где модель переучивается или «застряла».
Начните с малого: Постройте прототип на маленькой сети и части данных, чтобы найти базовые параметры.
Почему это важно
«Настройка гиперпараметров — это не магия, а наука. Даже простая модель с правильными настройками побьёт сложную, которую не отладили».
Теперь, когда ваша нейросеть настроена как скрипка, переходим к самому волнующему — запуску обучения. Узнаете, как следить за процессом и не пропустить момент, когда модель начнёт творить чудеса.
Запуск обучения: как превратить код в «мыслящую» машину (и не сжечь видеокарту)
Вы настроили гиперпараметры, разделили данные, и теперь ваша нейросеть готова к главному — обучению. Это как запуск ракеты: вы проверили системы, осталось нажать кнопку «Старт» и следить, чтобы всё шло по плану. Поехали!
Процесс обучения: от кода к результату
Как запустить обучение одной строкой
В современных фреймворках обучение модели выглядит почти как магия. Вот пример для Keras/TensorFlow:
history = model.fit(
X_train, y_train,
epochs=50,
batch_size=32,
validation_data=(X_val, y_val), # Валидационный набор для контроля
callbacks=[early_stopping, tensorboard_callback] # Мониторинг и ранняя остановка
)
Что здесь происходит
X_train, y_train — данные, на которых модель учится.
epochs=50 — 50 «кругов» по данным. Как марафон: чем больше кругов, тем лучше выносливость (но есть риск переутомиться).
batch_size=32 — модель обрабатывает данные порциями по 32 примера. Представьте, что она читает книгу не слово за словом, а абзацами.
validation_data — контрольные вопросы после каждой эпохи: «Ты всё ещё понимаешь, что делаешь?».
Ускорение на стероидах: GPU и TPU
Если обучение длится дни, а не часы — время подключать тяжёлую артиллерию.
GPU (NVIDIA) — видеокарты, которые считают матрицы в 100 раз быстрее CPU.
TPU (Google) — специализированные чипы для тензорных операций.
Как проверить, что TensorFlow видит вашу GPU?
import tensorflow as tf
print("Доступные устройства:", tf.config.list_physical_devices())
# Принудительно запустить обучение на GPU
with tf.device('/GPU:0'):
model.fit(...)
Совет: Если GPU не используется, убедитесь, что установлены CUDA и cuDNN. Это как установить драйверы для гоночного болида.
Мониторинг в реальном времени: как не пропустить катастрофу
Обучение без мониторинга — как полёт с завязанными глазами. Вот инструменты, которые спасут вашу модель:
TensorBoard: «Чёрный ящик» нейросети
Визуализируйте метрики в реальном времени:
from tensorflow.keras.callbacks import TensorBoard
import datetime
# Создаём лог-папку с timestamp
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = TensorBoard(log_dir=log_dir, histogram_freq=1)
# Добавляем колбэк в model.fit()
model.fit(..., callbacks=[tensorboard_callback])
Запустите в терминале:
tensorboard --logdir logs/fit
…и откройте http://localhost:6006. Увидите графики лосса, точности и даже распределения весов!
Weights & Biases (W&B): Google Analytics для ML
Сервис для командной работы и сравнения экспериментов:
import wandb
from wandb.keras import WandbCallback
wandb.init(project="my-awesome-model")
model.fit(..., callbacks=[WandbCallback()])
Фишки:
- Автоматические графики и логирование.
- Сравнение сотен экспериментов в одной таблице.
- Интеграция с PyTorch, JAX и даже sklearn.
Как читать графики обучения
Идеальный сценарий: Тренировочный и валидационный лосс плавно снижаются вместе.
Переобучение: Валидационный лосс растёт, а тренировочный падает (модель «зубрит»).
Недообучение: Оба лосса высокие (модель не понимает данные).
Советы от гуру
Не доверяйте слепо метрикам. Смотрите на реальные примеры — иногда модель «обманывает» метрики.
Сохраняйте чекпойнты:
from tensorflow.keras.callbacks import ModelCheckpoint
checkpoint = ModelCheckpoint('best_model.h5', save_best_only=True)
Если loss = NaN: Уменьшите скорость обучения или нормализуйте данные.
Почему это важно
«Обучение нейросети — это не «настроил и забыл». Это диалог: вы задаёте вопросы, модель отвечает метриками, а вы корректируете параметры».
Теперь, когда модель обучена, остался последний шаг — тестирование. Узнаете, как провести финальный экзамен и не дать модели сжульничать.
Валидация и тестирование: как понять, что ваша нейросеть готова к бою
Вы провели часы за обучением модели, и теперь она показывает 99% точности. Но что, если это лишь иллюзия? Чтобы не стать жертвой «статистических галлюцинаций», нужны валидация и тестирование — два ключевых этапа, которые отделяют надежную модель от «гадалки на кофейной гуще».
Валидация vs тестирование: кто есть кто
Валидационный набор — это «полигон» для экспериментов:
- На нём вы настраиваете гиперпараметры (learning rate, размер батча).
- Он помогает выбрать лучшую архитектуру модели.
Пример: Подбор оптимального числа эпох с помощью ранней остановки.
Тестовый набор — финальный экзамен без права на ошибку:
- Его используют один раз после всех настроек.
- Он имитирует реальные данные, которые модель никогда не видела.
Пример: Если вы запускаете модель в продакшн, тестовый набор — её последний рубеж.
Главное правило
«Тестовый набор — как запечатанный конверт с ответами. Открыли его слишком рано — всё, вы жулик».
Метрики: как отличить удачную модель от провальной
Для классификации (котики vs собачки)
Точность (Accuracy)
(Правильные ответы) / (Все примеры).
- Хорошо для сбалансированных данных.
- Проблема: Если 95% данных — котики, модель, предсказывающая «котик» всегда, получит 95% точности. Обман!
F1-score
Среднее гармоническое между точностью (precision) и полнотой (recall).
- Лучше для несбалансированных данных.
- Пример: Если важно не пропустить ни одного больного пациента (даже ценой ложных срабатываний), смотрите на F1.
ROC-AUC
Оценивает, насколько модель уверенно отличает классы.
- 1.0 — идеал, 0.5 — случайные догадки.
- Совет: Используйте, когда классов много или важна уверенность модели.
Пример кода:
from sklearn.metrics import classification_report
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))
Для регрессии (предсказание цен, температуры)
- MSE (Mean Squared Error):
Среднее квадратов ошибок.
→ Чувствителен к выбросам (большие ошибки сильно влияют на результат). - MAE (Mean Absolute Error):
Среднее абсолютных ошибок.
→ Легче интерпретировать: «Модель ошибается в среднем на ±10$». - R² (R-квадрат):
Доля дисперсии, которую объясняет модель.
→ 1.0 — идеальное предсказание, 0 — модель не лучше, чем предсказание средним значением.
Пример интерпретации:
Если R² = 0.85 → модель объясняет 85% изменчивости данных.
Анализ ошибок: как найти слабые места модели
Confusion Matrix: карта провалов и побед
Матрица показывает, сколько раз модель перепутала классы. Например, для задачи распознавания цифр:
from sklearn.metrics import confusion_matrix
import seaborn as sns
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True)
Визуализация ошибок: увидеть, чтобы поверить
Для задач с изображениями или текстами:
Соберите примеры, где модель ошиблась.
Ищите паттерны: шум на фото, опечатки, неочевидные ракурсы.
Пример: Модель для детекции опухолей на МРТ ошибается на снимках с артефактами движения.
Советы, которые спасут вашу репутацию
Никогда не подглядывайте в тестовые данные до финальной оценки.
Проверяйте метрики на разных подвыборках (например, по полу, возрасту, регионам), чтобы избежать предвзятости.
Сравнивайте с бейзлайном: Какова точность случайного угадывания? А простой линейной модели?
Почему это важно
«Хорошая модель — не та, которая идеально прошла тесты, а та, которая не сломается в реальном мире. Тестирование — это репетиция апокалипсиса для вашего ИИ».
Типичные ошибки и как их избежать: как не угробить свою нейросеть за 5 минут
Обучение нейросети напоминает прогулку по минному полю: один неверный шаг — и модель взрывается переобучением, недообучением или молчаливым крашем. Давайте разберём, как обойти ловушки, о которых не пишут в учебниках.
Переобучение (Overfitting): когда модель «зубрит» вместо понимания
Проблема: Нейросеть идеально предсказывает тренировочные данные, но проваливается на новых примерах. Это как студент, который заучил билеты, но не понимает предмета.
Пример катастрофы
Модель для распознавания лиц даёт 99% точности на фото из датасета… и 50% на снимках с плохим освещением.
Решение
Регуляризация — «диета» для нейросети:
- Dropout: Случайно «выключайте» часть нейронов во время обучения. Код для Keras:
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5)) # Отключаем 50% нейронов
- L2-регуляризация: Штрафуйте модель за слишком большие веса.
from tensorflow.keras.regularizers import l2
model.add(Dense(128, activation='relu', kernel_regularizer=l2(0.01)))
Аугментация данных: Искусственно расширяйте датасет. Для изображений: повороты, зеркала, шумы.
Недообучение (Underfitting): когда модель «ленится»
Проблема: Нейросеть слишком проста или мало тренировалась. Результаты плохие даже на тренировочных данных. Это как ученик, который прочитал только оглавление учебника.
Пример
Модель предсказывает цену дома только на основе площади, игнорируя район, этаж и год постройки.
Решение
Усложните архитектуру: Добавьте слоёв, нейронов или используйте предобученные модели (например, ResNet).
Увеличьте эпохи: Дайте модели время «вникнуть» в данные. Но следите за валидационным лоссом!
Проверьте данные: Может, в них нет нужных признаков? Добавьте фичи, которые влияют на целевую переменную.
Проблемы с данными: тихие убийцы моделей
Утечка данных (Data Leakage)
Что случилось: Информация из тестового набора «просочилась» в тренировочный.
Пример: Нормализовали весь датасет до разделения на train/test. Теперь модель знает «границы» тестовых данных.
Как избежать
Всегда сначала делите данные на train/test, потом применяйте нормализацию/аугментацию.
Убедитесь, что в фичах нет «подсказок» из будущего (например, цена акции завтрашнего дня в тренировочных данных).
Некорректная предобработка
Ошибка: Вы обработали тренировочные данные, но забыли повторить те же шаги для тестовых.
Фикс
Сохраняйте параметры предобработки (например, среднее и std для нормализации):
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # Используем параметры из X_train!
Советы, которые сэкономят вам месяцы жизни
- Сохраняйте чекпойнты:
from tensorflow.keras.callbacks import ModelCheckpoint
checkpoint = ModelCheckpoint(
'best_model.h5',
monitor='val_loss',
save_best_only=True
)
model.fit(..., callbacks=[checkpoint])
После краша обучения можно продолжить с последней сохранённой версии.
- Экспериментируйте с гиперпараметрами:
Попробуйте learning rate в диапазоне 0.1 → 0.0001.
Тестируйте разные размеры батча (16, 32, 64).
Запускайте 3-5 экспериментов для каждого подхода и сравнивайте метрики.
- Проверяйте данные визуально:
Для изображений: выведите 10-20 примеров из датасета.
Для текста: посмотрите частоту слов или длину предложений.
Почему это важно
«Лучшие модели строят не гении, а те, кто не повторяет чужих ошибок. Ваш код может быть идеальным, но один пропущенный шаг в предобработке — и всё полетит в тартарары».
Заключение
Резюме: обучение — это марафон, а не спринт
Вы прошли огонь, воду и медные трубы: разделили данные, настроили гиперпараметры, запустили обучение и проверили модель на прочность. Теперь вы знаете, что:
Нейросеть — не волшебная палочка. Ей нужны чёткие правила (баланс данных, регуляризация) и жёсткий контроль (метрики, валидация).
Ошибки — лучшие учителя. Переобучение, утечка данных и прочие «монстры» делают вашу модель сильнее, если вы их вовремя ловите.
Идеальных моделей не бывает. Главное — чтобы она решала задачу достаточно хорошо в реальных условиях.
Но это только половина пути. Представьте, что вы вырастили чемпиона-спортсмена, но так и не выпустили его на стадион. Без деплоя все ваши усилия — просто красивые графики в блокноте.
Что дальше: деплой и мониторинг в production
Теперь ваша модель готова к бою. Но «боевые условия» — это не тестовая песочница. Вас ждут:
Деплой на сервер или в облако — как упаковать модель в Docker-контейнер или запустить через AWS SageMaker.
Мониторинг — как поймать дрифт данных или падение точности, когда пользователи начнут заливать в модель мемы вместо фоток котиков.
Обновления — как переучивать модель на лету, не останавливая сервис.
«Продакшн — это зеркало, которое покажет все ваши ошибки. Но именно оно сделает вашу модель по-настоящему взрослой».
Проверьте модель в реальности!
Не ждите идеального момента — его не существует. Сделайте следующее прямо сейчас:
Загрузите модель на хостинг (например, Hugging Face Spaces или Heroku).
Дайдите ей реальных данных — даже 10 пользователей найдут баги, которые вы не заметили.
Настройте алерт: если точность упала ниже порога — вы первые, кто об этом узнает.
Помните: Даже GPT-4 когда-то был сырым прототипом. Ваша модель заслуживает шанса изменить мир.
Бонус: пример кода — готовый рецепт для обучения вашей нейросети
Ниже — полный пример кода, который объединяет всё, о чём мы говорили: от разделения данных до ранней остановки.
Комментарии помогут разобраться даже новичкам, а фрагменты можно адаптировать под любую задачу.
# Импорт библиотек
from sklearn.model_selection import train_test_split
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
# Предположим, X — признаки, y — целевые переменные (заранее подготовлены)
# Например, X.shape = (1000, 20), y.shape = (1000,)
# 1. Разделяем данные на обучающие и тестовые
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2, # 20% данных уходит в тестовый набор
random_state=42 # Для воспроизводимости
)
# 2. Создаём модель (пример архитектуры)
model = Sequential([
Dense(64, activation='relu', input_shape=(X_train.shape[1],)),
Dense(32, activation='relu'),
Dense(1, activation='sigmoid') # Для бинарной классификации
])
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
# 3. Настраиваем раннюю остановку
early_stopping = EarlyStopping(
monitor='val_loss', # Следим за ошибкой на валидации
patience=5, # Ждём 5 эпох без улучшений
restore_best_weights=True # Возвращаем лучшие веса модели
)
# 4. Запускаем обучение
history = model.fit(
X_train,
y_train,
epochs=100, # Максимальное число эпох
batch_size=32, # Размер батча
validation_split=0.2, # 20% тренировочных данных → валидация
callbacks=[early_stopping], # Подключаем раннюю остановку
verbose=1 # Вывод логов обучения
)
# 5. Оцениваем на тестовых данных
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"\nРезультат:")
print(f"- Точность на тесте: {test_acc:.2f}")
print(f"- Ошибка на тесте: {test_loss:.2f}")
# Совет: Используйте history для анализа обучения
# history.history['loss'] — лосс на тренировке
# history.history['val_loss'] — лосс на валидации
Как это работает
- Разделение данных: 80% уходит в обучение, 20% — в тест.
- Ранняя остановка: Если валидационный лосс не улучшается 5 эпох подряд, обучение останавливается.
- Валидация: 20% от тренировочных данных автоматически выделяются для проверки в процессе обучения.
- Метрики: Для бинарной классификации используются binary_crossentropy и точность.
Советы для экспериментов
- Для регрессии замените activation=’sigmoid’ на activation=’linear’, а loss на ‘mse’.
- Если данных мало, увеличьте patience до 10-15.
- Хотите визуализировать обучение? Добавьте:
import matplotlib.pyplot as plt
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.show()
Теперь у вас есть готовый шаблон. Осталось подставить свои данные и запустить!


