Тестирование Систем Компьютерного Зрения
Компьютерное зрение управляет автономными транспортными средствами, медицинской диагностикой, системами безопасности и QA в производстве. В отличие от традиционного программного обеспечения, CV модели имеют дело с неоднозначностью, визуальной вариативностью и сложностью реального мира.
Тестирование CV систем требует оценки точности при разнообразных условиях, состязательной робастности, справедливости между демографиями и ограничений производительности реального времени.
Основные Стратегии Тестирования
1. Метрики Точности
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
import numpy as np
class ОценщикМоделиCV:
def __init__(self, модель):
self.модель = модель
def оценить_классификацию(self, тестовые_изображения, истинные_метки):
"""Оценить модель классификации"""
предсказания = self.модель.predict(тестовые_изображения)
предсказанные_метки = np.argmax(предсказания, axis=1)
# Общая точность
точность = accuracy_score(истинные_метки, предсказанные_метки)
# Метрики по классам
точность_класс, полнота, f1, поддержка = precision_recall_fscore_support(
истинные_метки,
предсказанные_метки,
average=None
)
return {
'точность': точность,
'метрики_по_классам': {
self.модель.имена_классов[i]: {
'точность': точность_класс[i],
'полнота': полнота[i],
'f1_score': f1[i],
'поддержка': поддержка[i]
}
for i in range(len(self.модель.имена_классов))
}
}
2. Валидация Датасета
import cv2
from collections import Counter
class ВалидаторДатасета:
def проверить_баланс_классов(self):
"""Обнаружить дисбаланс классов"""
подсчеты_меток = Counter(self.dataset.метки)
всего = len(self.dataset.метки)
отчет_дисбаланса = {}
for имя_класса, подсчет in подсчеты_меток.items():
процент = (подсчет / всего) * 100
отчет_дисбаланса[имя_класса] = {
'подсчет': подсчет,
'процент': процент,
'дисбалансирован': процент < 5 or процент > 50
}
return отчет_дисбаланса
def анализировать_качество_изображения(self):
"""Проверить низкокачественные изображения"""
проблемы_качества = []
for путь_изобр in self.dataset.пути_изображений:
изобр = cv2.imread(путь_изобр)
# Проверить разрешение
высота, ширина = изобр.shape[:2]
if высота < 224 or ширина < 224:
проблемы_качества.append({
'изображение': путь_изобр,
'проблема': 'низкое_разрешение',
'разрешение': f"{ширина}x{высота}"
})
# Проверить яркость
серое = cv2.cvtColor(изобр, cv2.COLOR_BGR2GRAY)
яркость = np.mean(серое)
if яркость < 30 or яркость > 225:
проблемы_качества.append({
'изображение': путь_изобр,
'проблема': 'плохая_яркость',
'яркость': яркость
})
return проблемы_качества
3. Состязательное Тестирование
import tensorflow as tf
class СостязательныйТестер:
def __init__(self, модель):
self.модель = модель
def атака_fgsm(self, изображение, истинная_метка, epsilon=0.01):
"""Атака Fast Gradient Sign Method"""
тензор_изображения = tf.convert_to_tensor(изображение[np.newaxis, ...])
with tf.GradientTape() as tape:
tape.watch(тензор_изображения)
предсказание = self.модель(тензор_изображения)
потеря = tf.keras.losses.sparse_categorical_crossentropy(
[истинная_метка], предсказание
)
градиент = tape.gradient(потеря, тензор_изображения)
знаковый_град = tf.sign(градиент)
# Создать состязательное изображение
состязательное_изображение = изображение + epsilon * знаковый_град.numpy()[0]
состязательное_изображение = np.clip(состязательное_изображение, 0, 1)
# Тестировать успешность атаки
сост_предск = self.модель.predict(состязательное_изображение[np.newaxis, ...])
сост_метка = np.argmax(сост_предск)
return {
'оригинальная_метка': истинная_метка,
'состязательная_метка': сост_метка,
'атака_успешна': сост_метка != истинная_метка,
'состязательное_изображение': состязательное_изображение
}
def тестировать_робастность(self, тестовый_набор, значения_epsilon=[0.01, 0.05, 0.1]):
"""Тестировать робастность между силами атаки"""
результаты = {eps: {'успехи': 0, 'всего': 0} for eps in значения_epsilon}
for изображение, метка in тестовый_набор:
for epsilon in значения_epsilon:
результат = self.атака_fgsm(изображение, метка, epsilon)
результаты[epsilon]['всего'] += 1
if результат['атака_успешна']:
результаты[epsilon]['успехи'] += 1
# Рассчитать оценки робастности
оценки_робастности = {
eps: 1 - (данные['успехи'] / данные['всего'])
for eps, данные in результаты.items()
}
return оценки_робастности
4. Тестирование Аугментации
import albumentations as A
class ТестерАугментации:
def тестировать_с_аугментациями(self, изображение, истинная_метка):
"""Тестировать консистентность модели под аугментациями"""
аугментации = [
('поворот', A.Rotate(limit=15, p=1)),
('яркость', A.RandomBrightness(limit=0.2, p=1)),
('размытие', A.Blur(blur_limit=3, p=1)),
('шум', A.GaussNoise(var_limit=(10, 50), p=1)),
('флип', A.HorizontalFlip(p=1))
]
оригинальное_предсказание = self.модель.predict(изображение[np.newaxis, ...])[0]
оригинальный_класс = np.argmax(оригинальное_предсказание)
результаты = {}
for имя_aug, аугментация in аугментации:
аугментированное = аугментация(image=изображение)['image']
aug_предск = self.модель.predict(аугментированное[np.newaxis, ...])[0]
aug_класс = np.argmax(aug_предск)
результаты[имя_aug] = {
'предсказание_изменилось': aug_класс != оригинальный_класс,
'всё_ещё_правильно': aug_класс == истинная_метка
}
# Рассчитать оценку инвариантности
оценка_инвариантности = sum(
1 for р in результаты.values() if not р['предсказание_изменилось']
) / len(результаты)
return {
'результаты_аугментации': результаты,
'оценка_инвариантности': оценка_инвариантности
}
Тестирование Производительности
import time
class ТестерПроизводительности:
def бенчмарк_инференса(self, тестовые_изображения, размеры_батчей=[1, 8, 32]):
"""Бенчмарк скорости инференса"""
результаты = {}
for размер_батча in размеры_батчей:
латентности = []
for i in range(0, len(тестовые_изображения), размер_батча):
батч = тестовые_изображения[i:i+размер_батча]
начало = time.time()
_ = self.модель.predict(батч)
конец = time.time()
латентность_мс = (конец - начало) * 1000 / len(батч)
латентности.append(латентность_мс)
результаты[f'batch_{размер_батча}'] = {
'средняя_латентность_мс': np.mean(латентности),
'латентность_p95_мс': np.percentile(латентности, 95),
'пропускная_способность_fps': 1000 / np.mean(латентности)
}
return результаты
Лучшие Практики
Практика | Описание |
---|---|
Разнообразный Тестовый Набор | Включать разное освещение, углы, фоны |
Сбор Крайних Случаев | Окклюзии, экстремальные углы, плохое освещение |
Кросс-Датасет Валидация | Тестировать на данных из разных источников |
Состязательное Укрепление | Включать состязательные примеры в обучение |
Непрерывная Оценка | Мониторить производственный дрейф производительности |
Тестирование Справедливости | Тестировать между демографиями (тона кожи, возрасты) |
Заключение
Тестирование компьютерного зрения выходит за пределы метрик точности—требуя тестирования робастности, валидации датасетов, состязательных защит и оценки справедливости. По мере развертывания CV систем в критически важных для безопасности приложениях, строгое тестирование становится критичным.