Home » Метрики глубокого обучения: точность, полнота, accuracy
Метрики глубокого обучения: точность, полнота, accuracy

Метрики глубокого обучения: точность, полнота, accuracy

Когда поднимаешь ML-проекты на своей железке, настраиваешь инференс или тренируешь модели, без понимания метрик никуда. Точность, полнота, accuracy — это не просто абстрактные циферки в логах, а твои лучшие друзья для оценки того, насколько хорошо работает модель. Сегодня разберём, как правильно измерять эффективность нейросетей, какие метрики когда использовать, и главное — как это всё быстро развернуть и настроить на сервере. Поверь, без этого знания твоя модель может показывать 99% accuracy, а на практике работать хуже рандома.

Как это работает: теория без воды

Метрики глубокого обучения строятся на матрице ошибок (confusion matrix) — таблице, которая показывает, насколько хорошо модель предсказывает каждый класс. Для бинарной классификации у нас есть четыре ключевых значения:

  • True Positive (TP) — модель правильно определила положительный класс
  • True Negative (TN) — модель правильно определила отрицательный класс
  • False Positive (FP) — модель ошибочно предсказала положительный класс (ложная тревога)
  • False Negative (FN) — модель пропустила положительный класс (пропуск цели)

Из этих четырёх значений выводятся основные метрики:

  • Accuracy = (TP + TN) / (TP + TN + FP + FN) — общая точность
  • Precision = TP / (TP + FP) — точность (из всех предсказанных положительных, сколько действительно положительных)
  • Recall = TP / (TP + FN) — полнота (из всех действительно положительных, сколько нашла модель)

Быстрая настройка: от нуля до результата

Для начала нужен сервер с GPU. Если у тебя нет подходящего железа, можешь взять VPS с GPU или выделенный сервер для серьёзных экспериментов.

Ставим окружение:

sudo apt update && sudo apt install -y python3-pip python3-venv nvidia-utils-470
python3 -m venv ml_env
source ml_env/bin/activate
pip install torch torchvision tensorflow scikit-learn matplotlib seaborn pandas numpy

Создаём базовый скрипт для расчёта метрик:

import numpy as np
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import confusion_matrix, classification_report
import matplotlib.pyplot as plt
import seaborn as sns

# Пример данных
y_true = np.array([0, 1, 1, 0, 1, 1, 0, 0, 1, 0])
y_pred = np.array([0, 1, 0, 0, 1, 1, 0, 1, 1, 0])

# Расчёт метрик
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)

print(f"Accuracy: {accuracy:.3f}")
print(f"Precision: {precision:.3f}")
print(f"Recall: {recall:.3f}")
print(f"F1-score: {f1:.3f}")

# Матрица ошибок
cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.savefig('confusion_matrix.png')
plt.show()

Практические примеры: когда что использовать

Рассмотрим реальные кейсы, где каждая метрика критична:

Задача Приоритетная метрика Почему Пример
Медицинская диагностика Recall (полнота) Важно не пропустить болезнь Лучше ложная тревога, чем пропущенный рак
Спам-фильтр Precision (точность) Важно не потерять важные письма Лучше пропустить спам, чем заблокировать важное письмо
Мониторинг серверов F1-score Баланс между ложными тревогами и пропусками Нужен компромисс между точностью и полнотой
Общая классификация Accuracy Классы сбалансированы Классификация изображений с равным количеством классов

Продвинутые метрики для серьёзных задач

Для многоклассовой классификации и более сложных сценариев понадобятся дополнительные метрики:

from sklearn.metrics import roc_auc_score, average_precision_score
from sklearn.metrics import cohen_kappa_score, matthews_corrcoef

# Для многоклассовой классификации
y_true_multi = np.array([0, 1, 2, 0, 1, 2, 0, 1, 2])
y_pred_multi = np.array([0, 1, 1, 0, 2, 2, 0, 1, 2])

# Macro-average (усреднение по классам)
macro_precision = precision_score(y_true_multi, y_pred_multi, average='macro')
macro_recall = recall_score(y_true_multi, y_pred_multi, average='macro')
macro_f1 = f1_score(y_true_multi, y_pred_multi, average='macro')

# Weighted-average (взвешенное по количеству примеров)
weighted_precision = precision_score(y_true_multi, y_pred_multi, average='weighted')
weighted_recall = recall_score(y_true_multi, y_pred_multi, average='weighted')
weighted_f1 = f1_score(y_true_multi, y_pred_multi, average='weighted')

print(f"Macro F1: {macro_f1:.3f}")
print(f"Weighted F1: {weighted_f1:.3f}")

# Cohen's Kappa для несбалансированных классов
kappa = cohen_kappa_score(y_true_multi, y_pred_multi)
print(f"Cohen's Kappa: {kappa:.3f}")

Автоматизация и мониторинг метрик

Создаём класс для автоматического расчёта и логирования метрик:

import json
import datetime
import os

class MetricsTracker:
    def __init__(self, log_file='metrics.json'):
        self.log_file = log_file
        self.metrics_history = []
        
    def calculate_metrics(self, y_true, y_pred, experiment_name="default"):
        metrics = {
            'timestamp': datetime.datetime.now().isoformat(),
            'experiment': experiment_name,
            'accuracy': float(accuracy_score(y_true, y_pred)),
            'precision': float(precision_score(y_true, y_pred, average='weighted')),
            'recall': float(recall_score(y_true, y_pred, average='weighted')),
            'f1': float(f1_score(y_true, y_pred, average='weighted'))
        }
        
        self.metrics_history.append(metrics)
        self.save_metrics()
        return metrics
    
    def save_metrics(self):
        with open(self.log_file, 'w') as f:
            json.dump(self.metrics_history, f, indent=2)
    
    def get_best_experiment(self, metric='f1'):
        if not self.metrics_history:
            return None
        return max(self.metrics_history, key=lambda x: x[metric])

# Использование
tracker = MetricsTracker()
results = tracker.calculate_metrics(y_true, y_pred, "experiment_v1")
print(f"Current metrics: {results}")

Интеграция с популярными ML-фреймворками

Для PyTorch создаём кастомный коллбэк:

import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from sklearn.metrics import classification_report

class MetricsCallback:
    def __init__(self):
        self.reset()
    
    def reset(self):
        self.predictions = []
        self.targets = []
    
    def update(self, preds, targets):
        self.predictions.extend(preds.cpu().numpy())
        self.targets.extend(targets.cpu().numpy())
    
    def compute(self):
        return classification_report(self.targets, self.predictions, output_dict=True)

# Интеграция в тренировочный цикл
def train_with_metrics(model, train_loader, val_loader, criterion, optimizer, epochs=10):
    metrics_callback = MetricsCallback()
    
    for epoch in range(epochs):
        model.train()
        for batch_idx, (data, target) in enumerate(train_loader):
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
        
        # Validation
        model.eval()
        metrics_callback.reset()
        with torch.no_grad():
            for data, target in val_loader:
                output = model(data)
                pred = output.argmax(dim=1)
                metrics_callback.update(pred, target)
        
        metrics = metrics_callback.compute()
        print(f"Epoch {epoch+1}: Accuracy: {metrics['accuracy']:.3f}, "
              f"F1: {metrics['weighted avg']['f1-score']:.3f}")

Оптимизация и тюнинг по метрикам

Скрипт для автоматического подбора порога классификации:

from sklearn.metrics import precision_recall_curve, roc_curve
import numpy as np

def find_optimal_threshold(y_true, y_proba, metric='f1'):
    """Находит оптимальный порог для максимизации выбранной метрики"""
    
    thresholds = np.arange(0.1, 1.0, 0.01)
    best_threshold = 0.5
    best_score = 0
    
    for threshold in thresholds:
        y_pred = (y_proba >= threshold).astype(int)
        
        if metric == 'f1':
            score = f1_score(y_true, y_pred)
        elif metric == 'precision':
            score = precision_score(y_true, y_pred, zero_division=0)
        elif metric == 'recall':
            score = recall_score(y_true, y_pred, zero_division=0)
        
        if score > best_score:
            best_score = score
            best_threshold = threshold
    
    return best_threshold, best_score

# Пример использования
y_proba = np.random.rand(1000)  # Вероятности от модели
y_true = np.random.randint(0, 2, 1000)  # Истинные метки

optimal_threshold, best_f1 = find_optimal_threshold(y_true, y_proba, 'f1')
print(f"Optimal threshold: {optimal_threshold:.3f}, Best F1: {best_f1:.3f}")

Распространённые ошибки и как их избежать

Самые частые проблемы, с которыми сталкиваются при работе с метриками:

  • Использование accuracy для несбалансированных классов — если у тебя 95% примеров одного класса, модель может показать 95% accuracy, просто всегда предсказывая мажоритарный класс
  • Игнорирование macro/micro/weighted averaging — для многоклассовой классификации критично понимать разницу
  • Неправильная интерпретация precision/recall — помни: precision — “из найденного сколько правильно”, recall — “из правильного сколько найдено”
  • Забывание про валидацию — метрики на тренировочной выборке не говорят о реальной производительности

Альтернативные инструменты и библиотеки

Помимо scikit-learn, есть и другие полезные инструменты:

Интересные факты и нестандартные применения

Мало кто знает, но метрики можно использовать не только для оценки моделей:

  • Мониторинг серверов — можно настроить алерты как задачу бинарной классификации, где precision помогает избежать ложных тревог
  • A/B тестирование — конверсию можно рассматривать как задачу классификации и применять те же метрики
  • Кластеризация — adjusted rand index работает похоже на accuracy для кластеров

Крутой лайфхак: можно настроить автоматический деплой модели только если F1-score превышает определённый порог:

#!/bin/bash
# deploy_if_good.sh

THRESHOLD=0.85
CURRENT_F1=$(python calculate_metrics.py --output f1)

if (( $(echo "$CURRENT_F1 > $THRESHOLD" | bc -l) )); then
    echo "F1 score $CURRENT_F1 exceeds threshold $THRESHOLD. Deploying..."
    docker build -t ml_model:latest .
    docker stop ml_model || true
    docker run -d --name ml_model --restart unless-stopped ml_model:latest
else
    echo "F1 score $CURRENT_F1 below threshold $THRESHOLD. Deployment cancelled."
    exit 1
fi

Автоматизация и CI/CD интеграция

Создаём GitHub Actions workflow для автоматической проверки метрик:

name: ML Model Validation
on: [push, pull_request]

jobs:
  validate-metrics:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: 3.8
    - name: Install dependencies
      run: |
        pip install -r requirements.txt
    - name: Run tests and calculate metrics
      run: |
        python test_model.py
        python calculate_metrics.py > metrics_report.txt
    - name: Check metrics threshold
      run: |
        if ! python check_metrics_threshold.py; then
          echo "Metrics below threshold!"
          exit 1
        fi

Заключение и рекомендации

Метрики — это не просто числа в консоли, а реальный инструмент для понимания того, как работает твоя модель. Не гонись за единственной метрикой, всегда смотри на картину целиком. Для production-систем обязательно настрой мониторинг метрик в реальном времени.

Используй accuracy только для сбалансированных задач, precision — когда важно избежать ложных срабатываний, recall — когда нельзя пропустить положительные случаи. F1-score — твой друг для большинства задач, где нужен баланс.

Не забывай про правильную валидацию и не переобучайся на метриках. Лучше иметь немного хуже F1, но стабильную модель, чем идеальные числа на тесте и полный провал в продакшене.

И помни: лучшая метрика — это та, которая реально отражает успех твоей бизнес-задачи. Иногда даже кастомная метрика работает лучше стандартных.


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked