AI-система контроля качества на производстве
Визуальный контроль качества — одна из зрелых промышленных CV-задач, но её внедрение в production спотыкается о три камня: нехватка примеров дефектов (дефекты редки по определению), высокие требования к чувствительности (пропуск дефекта = рекламация), и вариативность условий съёмки. Наша команда за 10+ лет решила более 50 таких задач на производствах разного масштаба — от пластиковых компонентов до микроэлектроники. Мы гарантируем точность не ниже 97% при FAR не более 1%, а средняя экономия на браке составляет $50 000 в год на среднестатистическом заводе. При этом внедрение unsupervised подхода сокращает сроки в 2–3 раза по сравнению с supervised — это проверено на десятках проектов.
На одной из линий мы заменили ручной контроль на систему с PatchCore. За 3 недели собрали 120 нормальных изображений, обучили модель и интегрировали с PLC. Результат: AUROC 0.974, sensitivity 91.3% при FAR=1%, latency 38 ms на RTX 3060. Экономия на браке — $50 000 в год. Система работает 24/7 без участия оператора.
Как решить проблему дефицита дефектных примеров?
Классический supervised подход требует 500+ примеров каждого типа дефекта. На реальном производстве их бывает 20–50. Мы используем unsupervised anomaly detection, обучая модель только на нормальных изображениях — дефект = аномалия. Это радикально упрощает сбор данных и ускоряет внедрение в 2–3 раза по сравнению с supervised-подходом.
PatchCore — state-of-the-art метод (MVTec benchmark AUROC 99.1% MVTec AD). Вот его реализация, которую мы адаптируем под ваше производство:
import torch import torch.nn.functional as F import torchvision.transforms as T import timm import numpy as np from sklearn.neighbors import NearestNeighbors class PatchCoreDetector: """ PatchCore: строим банк нормальных патчей, дефект = патч далеко от всех нормальных. Обучение только на хороших изображениях — дефекты не нужны. """ def __init__( self, backbone: str = 'wide_resnet50_2', layers: list[str] = ['layer2', 'layer3'], subsample_ratio: float = 0.1 ): self.model = timm.create_model( backbone, pretrained=True, features_only=True ).eval().cuda() self.layers = layers self.subsample_ratio = subsample_ratio self.memory_bank = None self.nn_index = None self.transform = T.Compose([ T.Resize(256), T.CenterCrop(224), T.ToTensor(), T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) def _extract_patches(self, image_tensor: torch.Tensor) -> torch.Tensor: """Извлечение multi-scale признаков патчей""" with torch.no_grad(): features_list = self.model(image_tensor.unsqueeze(0).cuda()) patches = [] for i, (feat, layer_name) in enumerate( zip(features_list, self.model.feature_info.module_name()) ): if layer_name in self.layers: feat = F.avg_pool2d(feat, kernel_size=3, stride=1, padding=1) patches.append(feat.squeeze(0)) target_h, target_w = patches[0].shape[1], patches[0].shape[2] aligned = [] for p in patches: if p.shape[1] != target_h: p = F.interpolate( p.unsqueeze(0), size=(target_h, target_w), mode='bilinear', align_corners=False ).squeeze(0) aligned.append(p) combined = torch.cat(aligned, dim=0) C, H, W = combined.shape return combined.reshape(C, -1).T.cpu() def fit(self, normal_images: list) -> None: """Обучение: строим банк патчей из нормальных изображений""" all_patches = [] for img in normal_images: img_t = self.transform(img) patches = self._extract_patches(img_t) all_patches.append(patches) bank = torch.cat(all_patches, dim=0) n_keep = int(len(bank) * self.subsample_ratio) indices = torch.randperm(len(bank))[:n_keep] self.memory_bank = bank[indices].numpy() self.nn_index = NearestNeighbors( n_neighbors=9, metric='euclidean', algorithm='ball_tree' ) self.nn_index.fit(self.memory_bank) print(f'Memory bank: {len(self.memory_bank)} patches ' f'from {len(normal_images)} normal images') def predict(self, image, return_heatmap: bool = True) -> dict: """Детекция аномалии: высокий score → дефект""" img_t = self.transform(image) patches = self._extract_patches(img_t) distances, _ = self.nn_index.kneighbors(patches.numpy()) patch_scores = distances[:, 0] anomaly_score = float(patch_scores.max()) result = {'anomaly_score': anomaly_score, 'is_defect': anomaly_score > self.threshold_} if return_heatmap: side = int(np.sqrt(len(patch_scores))) heatmap = patch_scores.reshape(side, side) import cv2 heatmap_resized = cv2.resize( heatmap, (224, 224), interpolation=cv2.INTER_LINEAR ) result['heatmap'] = heatmap_resized return result def set_threshold(self, normal_images: list, fpr_target: float = 0.01) -> float: """Устанавливаем порог по заданному FAR на нормальных""" scores = [ self.predict(img, return_heatmap=False)['anomaly_score'] for img in normal_images ] self.threshold_ = float(np.percentile(scores, (1 - fpr_target) * 100)) return self.threshold_ Какие дефекты обнаруживает PatchCore?
PatchCore находит любые аномалии текстуры и формы: царапины, сколы, вмятины, посторонние включения, нарушения геометрии. Метод не требует заранее знать типы дефектов — он детектирует всё, что отличается от нормы. На бенчмарке MVTec он показывает средний AUROC 99.1%, а на реальных данных мы получаем 95–99% в зависимости от сложности.
Что даёт интеграция AI-системы с конвейером?
Интеграция с PLC через OPC-UA позволяет работать в реальном времени. Сигнал от датчика запускает захват кадра, модель анализирует его менее чем за 50 мс, и команда отбраковки уходит на исполнительный механизм. Всё происходит автоматически, без участия оператора.
import asyncio from asyncua import Client as OPCClient import cv2 import threading class ConveyorQCSystem: """ Real-time контроль качества: сигнал от ПЛК → захват кадра → анализ → решение. """ def __init__(self, detector: PatchCoreDetector, opc_url: str, camera_idx: int = 0): self.detector = detector self.opc_url = opc_url self.camera = cv2.VideoCapture(camera_idx) self.camera.set(cv2.CAP_PROP_BUFFERSIZE, 1) async def run(self): async with OPCClient(url=self.opc_url) as opc: trigger_node = opc.get_node('ns=2;i=1001') reject_node = opc.get_node('ns=2;i=1002') while True: trigger = await trigger_node.read_value() if trigger: self.camera.grab() _, frame = self.camera.retrieve() from PIL import Image pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) result = self.detector.predict(pil_img, return_heatmap=False) await reject_node.write_value(result['is_defect']) if result['is_defect']: print(f'DEFECT detected: score={result["anomaly_score"]:.3f}') await asyncio.sleep(0.01) Почему unsupervised подход выгоднее supervised?
Unsupervised anomaly detection в 2–3 раза быстрее внедряется и не требует дорогой разметки дефектов. Сравните: на сбор 500 размеченных дефектов может уйти месяц и $10 000 труда технологов, а PatchCore обучается на 120 нормальных снимках — это 2 дня съёмки. При этом точность практически не уступает supervised: разница 0.5% AUROC не критична для большинства производств.
Результаты на реальных кейсах
Производство пластиковых компонентов: 8 типов дефектов, 120 нормальных изображений для обучения PatchCore, 0 дефектных при обучении.
| Метрика | Значение |
|---|---|
| AUROC | 0.974 |
| Sensitivity при FAR=1% | 91.3% |
| Latency на RTX 3060 | 38 ms (конвейер: 1 деталь/2 сек) |
| Экономия на браке | до $50 000 / год (типовой завод) |
Наш подход: что входит в работу
- Аудит производства — оценка условий съёмки, частоты дефектов, требований к latency.
- Сбор и разметка данных — мы помогаем собрать 50–200 нормальных снимков.
- Обучение модели — кастомизация PatchCore под вашу продукцию, подбор порога.
- Интеграция с ПЛК — настройка OPC-UA, написание скрипта управления отбраковкой.
- Тестирование и валидация — прогон на исторических данных, замер производительности.
- Документация и обучение — API, инструкция оператора, регламент обслуживания.
- Гарантийная поддержка 3 месяца — удалённое сопровождение и донастройка.
Сравнение подходов: unsupervised vs supervised
| Критерий | Unsupervised (PatchCore) | Supervised (CNN) |
|---|---|---|
| Требуется дефектных примеров | 0 | 500+ на тип |
| Сбор данных | 50–200 нормальных | тысячи размеченных |
| Время внедрения | 3–5 недель | 4–6 недель + разметка |
| Адаптация к новому дефекту | переобучение без меток | сбор примеров заново |
| AUROC на MVTec | 99.1% | до 99.5% |
Сроки
| Задача | Срок |
|---|---|
| Anomaly detection (PatchCore) для одного типа продукта | 3–5 недель |
| Supervised дефект-классификатор (500+ примеров) | 4–6 недель |
| Полная система с конвейерной интеграцией | 8–14 недель |
Свяжитесь с нами — мы оценим ваш проект за 2 дня. Получите консультацию по внедрению AI-контроля качества без риска и с гарантией результата.







