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 AD benchmark AUROC 99.1%). Ось його реалізація, яку ми адаптуємо під ваше виробництво:
Код детектора PatchCore
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 кращий за supervised у 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 / рік (типовий завод) |
Наш підхід: що входить в роботу
Наша компанія має 10+ років досвіду та реалізувала 50+ проєктів у промисловому комп'ютерному зорі. Ми пропонуємо:
- Аудит виробництва — оцінка умов зйомки, частоти дефектів, вимог до 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-контролю якості без ризику та з гарантією результату.







