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-контролю якості без ризику та з гарантією результату.







