Зміст
На бланку ультразвукового контролю товщини (УЗТ) товщина стінки — це не «текст взагалі», а коротке рукописне число в уже вирізаній клітинці: 12,3, 8,0, інколи порожньо. Помилка в десятих іде в облікову систему підприємства (ERP). У пілоті ми перевіряємо, як далеко можна заїхати маленькою згортково-рекурентною мережею на таких кропах — без хмари, без універсального трансформера і без обіцянки «готово до цеху».
Це продовження польових нотаток, не заміна сусідніх статей. Контур усього аркуша — геометрія, модель зору, оцінка надійності, звіт оператора — розібрано в «чому однієї моделі мало». Загальна механіка «цифра проти послідовності» і коли виправданий TrOCR — у розборі від згортки до трансформера. Тут — конкретна голова MeasurementCrnn з пілоту: вхід 1 × 48 × 160, абетка 0123456789,, близько 640 тисяч навчальних параметрів і урок, який мережа отримала на порожніх клітинках.
Репозиторій закритий; публічний контур — на сторінці портфоліо. Нижче немає сирих бланків замовника. Цифри прогонів — вимірювання пілоту, не норматив приймання.
Ключові висновки
Це не універсальне розпізнавання. Шаблон відомий, клітинка вже вирізана, абетка вузька. Універсальна модель на весь аркуш тут зайва як перший крок.
CRNN — не конкурент згортці, а згортка плюс послідовність. CNN дістає штрихи, двонапрямлена LSTM тримає порядок цифр, CTC знімає розмітку меж кожного символу.
Близько 640 тисяч параметрів вистачає на робочий базовий рівень. Велика частка ваг сидить у рекурентній частині, а не в «величезному кодувальнику».
Повне збігання рядка жорсткіше за точність за символами. Чотири вірні цифри з п'яти дають високу посимвольну оцінку і невірну товщину.
Порожня клітинка — окрема задача. Одна голова, яка одночасно вирішує «чи є число» і «яке саме», знижує хибні спрацьовування ціною якості заповнених полів.
Не потрібна модель на кожне поле. Ділити слід за типом візуальної задачі: замір, друкована дата, друкований текст, рукописний коментар, порожньо/заповнено.
Трансформер підключаємо як запасний контур, якщо компактна межа виміряна і не закриває вимоги — не як стартовий стек.
Відома геометрія — не універсальне розпізнавання
У пілоті бланк уже розбирається локальним комп'ютерним зором (CV, Computer Vision): перспектива, таблиця, карта клітинок, кропи. На момент розпізнавання заміру ми частіше дивимося не на фотографію аркуша, а на маленький прямокутник «тут має бути число або порожньо».
Це змінює постановку. Універсальне оптичне розпізнавання символів (OCR) мусить знайти текст де завгодно. У нас координати поля відомі заздалегідь. Отже, можна зібрати вузьку систему: кроп → порожньо або заповнено → розпізнати вміст → перевірити діапазон товщини → структуроване поле. Одну мережу не змушуємо одночасно шукати таблицю, читати прізвище і вгадувати десяті.
flowchart TB
form[UT_form]
form --> layout[Layout_and_crop]
layout --> empty[Empty_or_value]
empty -->|empty| skip[No_OCR]
empty -->|value| crnn[Measurement_CRNN]
crnn --> rules[Range_and_format]
rules --> json[Structured_field]
Друковані колонки (зона, діаметр, тип елемента) і шапка — інші візуальні задачі. Їх закривають друкований OCR і окремі правила, а не розширення абетки замірної голови. Той самий принцип «спочатку геометрія, потім модель» уже стоїть у системній статті про бланк; тут він звужується до однієї клітинки заміру.
Чому спочатку компактна модель, а не трансформер
У пілоті вже є хмарні моделі зору на вирізаних фрагментах. Вони корисні як сильний, але платний контур. Компактна CRNN відповідає на інше питання: чи можна читати замір усередині підприємства, на звичайному процесорі, без надсилання бланка в зовнішній API, з передбачуваним розміром артефакту і своєю версією ваг.
Ми не стверджуємо, що згортково-рекурентна мережа «краща за трансформер взагалі». Твердження вже: спочатку вимірюється простий спеціалізований варіант. Архітектуру ускладнюють, коли базовий рівень уперся в стелю, а не тому що «у 2026 так прийнято». Для вузької абетки і короткого рядка це чесніше, ніж одразу орендувати GPU під донавчання TrOCR.
Локальний контур дає супровід: знімок ваг лежить поряд із кодом, абетка зафіксована, вхідний розмір відомий. Платити за кожен запит не потрібно. Ціна — самі дані і дисципліна експериментів. Це ближче до інженерії наборів, ніж до вибору «найсучаснішої» мережі.
Згортка, двонапрямлена пам'ять і вирівнювання в одній голові
Згорткова мережа (CNN, Convolutional Neural Network) шукає візуальні ознаки: спочатку лінії й штрихи, потім вигини, потім форми, схожі на цифри. Це не «компактна нейромережа в маркетинговому сенсі»: компактність у нашому тексті — про розмір моделі, CNN — про згортку.
Однієї класифікації картинки мало. Замір — послідовність: 5 → 8 → 3 → 2 → 1, часто із комою. Мережа має пам'ятати, що вже прочитала зліва, і не переплутати порядок. Тут з'являється LSTM (Long Short-Term Memory): рекурентний шар, який пропускає вже побачені кроки в поточний. У коді bidirectional=True, тому пам'ять дивиться в обидва боки: майбутня цифра допомагає розібрати попередню, якщо почерк сумнівний.
CRNN (Convolutional Recurrent Neural Network) у пілоті — це саме зв'язка:
кроп
→ CNN (ознаки)
→ BiLSTM (порядок)
→ Linear (12 класів)
→ CTC
→ "12,3"
CTC (Connectionist Temporal Classification) дозволяє не розмічати межі кожної цифри. Достатньо пари «картинка клітинки → рядок». На кожному кроці часу мережа видає розподіл за символами плюс службовий blank. Декодер згортає повтори й викидає порожні кроки: 5 5 blank 8 8 blank 3 стає 583. У коді BLANK_INDEX = 0, функція помилки — CTCLoss. На маленькій вибірці мережа інакше швидко вчиться передбачати одні пропуски: тому зміщення класу blank заздалегідь зсунуте в від'ємний бік (-2.0), щоб цифри взагалі мали шанс у перших епохах.
Докладний навчальний розбір CTC і порівняння з TrOCR уже є в сусідній статті про цифри — тут важлива не теорія, а те, що ця зв'язка вписана в замірну клітинку, а не в абстрактний порівняльний тест.
MeasurementCrnn: 48×160 і шістсот тисяч параметрів
Конкретна мережа в пілоті приймає одноканальний тензор 1 × 48 × 160. Чотири блоки згортка → нормалізація → ReLU → пулінг. Останній пулінг згортає висоту в один піксель і лишає 20 кроків уздовж ширини — саме вісь часу для LSTM. Далі два шари двонапрямленої пам'яті, hidden_size = 96, dropout = 0.2. Голова лінійна: 12 класів — 11 символів абетки 0123456789, плюс blank.
Крапка у вихіднику зводиться до коми: normalize_label(" 7.3 ") дає 7,3. Це доменне правило товщини, не «ще один клас».
Орієнтир за навчальними параметрами — близько 640 тисяч. Грубо: згортка ≈ 241 тис., двонапрямлена LSTM ≈ 396 тис., лінійний шар ≈ 2 тис. Більша частина ваг — у послідовності, і при цьому модель лишається крихітною поряд із трансформером зору.
Параметри — не збережені картинки і не база готових відповідей. Це числові коефіцієнти, які підбираються на парах «кроп → рядок». Після навчання у файл measurement-crnn.pt кладуться ваги, абетка, hidden_size і розміри входу. Архітектуру можна завантажити на процесорі й ганяти нові клітинки без повторного навчання. Навчання періодичне; вивід — на кожному новому бланку.
Як готуємо кроп і навіщо аугментація
Сирий виріз клітинки не годують мережі як є. Ланцюжок із коду: відтінки сірого, автоконтраст, масштаб із полями, полотно 48 × 160 із центруванням, інверсія яскравості (штрих стає світлим на темному), тензор. На навчанні додається слабка аугментація: поворот ±3°, зсув на кілька пікселів, контраст і яскравість у вузькому діапазоні.
Навіщо це. Почерк, товщина ручки, тінь від телефона і лінія сітки змінюються від аркуша до аркуша. Якщо мережа запам'ятає конкретні 200 кропів без варіацій, вона здивується третьому почерку. Аугментація не замінює різноманіття бланків — вона не дає моделі вивчити один сканер як «єдино правильний світ».
Розділення вибірки в завантажувачі йде з прив'язкою до вихідного аркуша і поля, а не до випадкового набору файлів. Схожі клітинки одного бланка не повинні спокійно опинитися і в навчанні, і в перевірці — та сама дисципліна, що в статті про витоки в наборах даних.
Перший прогін: повне збігання і точність за символами
Перший компактний прогін у пілоті: близько тисячі числових значень, навчання близько 19 хвилин, 70,9% повного збігання рядка і 89% точності за символами. Це не «модель на 89% готова до цеху». Це два різні контракти.
Еталон 58321, прогноз 58327: за символами чотири з п'яти вірні, замір цілком невірний. Товщина в міліметрах живе як ціле значення. Оператору й ERP потрібен рядок, а не середня частка вгаданих знаків.
Груба ілюстрація, не прогноз нашої мережі: якщо кожен символ незалежний з імовірністю 0,89, то п'ять символів поспіль дають близько 0,89⁵ ≈ 56% повного збігання. На практиці символи залежні, довжини різні, кома критична — але напрям вірний: повне збігання завжди жорсткіше посимвольної метрики. Для промислового OCR її треба дивитися окремо, разом із помилками за довжиною і за окремими цифрами.
Пізніше, на ширшій вибірці заповнених клітинок, повне збігання піднімалося вище (в одному з прогонів на цифрах — 85,4%). Це все ще пілотні заміри на наших кропах, не обіцянка чужому архіву.
Порожня клітинка ламає розпізнавач
Стара голова, навчена майже лише на заповнених замірах, на порожніх клітинках давала 100% хибних спрацьовувань. Фантоми впізнавані: 8,0, 8,9, 5,0, 11,1. Лінія сітки, пил, слід ручки в сусідній клітинці для розпізнавача виглядають як «майже цифра».
У конвеєрі вже є евристика вмісту клітинки (чорнило, повтор, закреслення, текст). Вона знижує число порожніх кропів, які взагалі потрапляють у розпізнавач. Але якщо розпізнавач усе ж дивиться на порожнє поле, він зобов'язаний щось сказати — і каже правдоподібну товщину.
Експеримент із негативними прикладами: 75 перевірених аркушів; навчання 10 960 кропів, перевірка 1 977; серед навчання 1 912 чисел і 191 порожня клітинка (частка порожніх у завантажувачі за замовчуванням 0,10). Порівняння пілотних прогонів:
| Прогін | Цифри, повне збігання | Хибні спрацьовування на порожніх |
|---|---|---|
| Базовий, майже без порожніх | 85,4% | 100% |
| З нуля, з порожніми | 78,6% | 0,1% |
| Донавчання на порожніх | 83,2% | 0,5% |
Додавання негативних прикладів різко б'є по фантомах і забирає якість на заповнених. Одна CRNN починає вирішувати дві конфліктні задачі: «чи є тут значення?» і «яке саме?». Ваги, які вчаться ігнорувати сітку, гірше читають тонкий хвіст дев'ятки.
Наступний крок, який ще не закрито: крихітний класифікатор «порожньо / є значення» перед замірною головою. Порожнє — не годуємо розпізнавач. Заповнене — можна повернути більш «цифровий» знімок ваг (measurement-crnn.prev.pt) без компромісу в одній голові. Як ми вже класифікуємо порожнє, повтор і закреслення в комп'ютерному зорі — у наступній нотатці.
Зберігаємо експериментальні ваги окремо: попередній найкращий, прогін з нуля, донавчання. Інакше за два тижні не можна чесно сказати, що саме зламав новий набір.
Одна модель на тип задачі, не на кожне поле
Спокуса промислового бланка — окрема мережа на дату, на прізвище, на кожну колонку заміру. Це чотири розгортання і та сама плутанина в чотирьох копіях. Краще різати за візуальним контрактом.
| Тип задачі | Що в пілоті |
|---|---|
| Рукописний замір | MeasurementCrnn + перевірка діапазону товщини |
| Порожньо / заповнено | евристика чорнила зараз; окремий маленький класифікатор — наступний крок |
| Друкована дата | друкований OCR + день 1–31, місяць 1–12, розумний рік |
| Друкований текст шапки і службових полів | спільний друкований OCR |
| Рукописний коментар / прізвище | інша задача, інша абетка; не розширювати замірну голову |
| Галочка, повтор, закреслення | окремі правила / маленький класифікатор |
Нейромережа розпізнає те, що не можна надійно порахувати. Звичайний код перевіряє те, що перевіряється детерміновано. Дата 12.09.2026 не потребує другої CRNN: достатньо цифр і правил. Рукописне прізвище — навпаки, не повинно їхати в абетку з десяти цифр і коми.
Трансформер має сенс, коли компактна межа виміряна і не вистачає: різні типи документів, слабка передбачуваність верстки, широка абетка, достатньо даних. Практична схема — не «одразу важке розпізнавання», а спеціалізована голова → оцінка надійності → за низької впевненості важкий контур або людина.
Знімок ваг, навчання і метрики цеху
Навчання в пілоті: AdamW, швидкість 1e-3, загасання ваг 1e-4, пакет 16 прикладів, обрізання градієнта, планувальник ReduceLROnPlateau, рання зупинка. Це нудний і достатній контур. Епоха — повний прохід навчальною вибіркою; найкращий знімок пишеться, коли росте повне збігання на перевірці.
Вивід (ocr_crnn.py) читає знімок ваг на процесорі, декодує жадібно, нормалізує товщину, за низької впевненості може повернути порожньо. Рушій рукопису перемикається змінною оточення: PaddleOCR / EasyOCR за замовчуванням, CRNN — окремий режим. Це важливо чесно сказати: компактна мережа ще не єдиний шлях у проді пілоту. Основний контур аркуша як і раніше тримає локальний зір, хмарні проходи і звіт оператора.
Метрики, які мають сенс на заводі, ширші за одну «точність»: повне збігання, точність за символами, хибні спрацьовування на порожніх, пропуски заповнених, частка ручної перевірки, впевненість, якість за довжиною значення, час на процесорі. Ціна помилки тут та сама, що в економіці збою: пропущена товщина дорожча зайвого «подивитися очима».
Набір важливіший за розмір голови. Різні почерки, скани і телефони, реальні каверзні кропи, порожні клітинки, жорсткі негативні приклади, розділення за аркушем, а не за файлом. Збільшення моделі не лікує дірявий набір — це вже було вірно для еталонних записів загалом.
Що зробити сьогодні
Якщо у вас схожі бланки з фіксованою сіткою, не починайте з вибору «CRNN чи TrOCR».
Виріжте 200–500 клітинок заміру з еталоном з обліку, включно з порожніми. Розділіть за аркушем, не за випадковими файлами.
Зберіть найвужчу голову, яку можете пояснити: полотно фіксованого розміру, абетка з цифр і роздільника, CTC. Збережіть знімок ваг разом з абеткою і розміром входу.
Порахуйте окремо повне збігання, посимвольну точність і хибні спрацьовування на порожніх. Якщо порожні «малюють» товщину — не донавчайте ту саму голову до нескінченності: поставте відсічку порожньо/значення перед розпізнавачем.
Часті питання
Навіщо CRNN, якщо вже є модель зору на фрагментах?
Хмарна модель закриває шапку, рідкісний текст і сумнівні клітинки ціною запиту і периметра даних. Компактна голова закриває масовий замір локально. У пілоті це різні контури, не взаємовиключні релігії.
Чому не навчити одразу TrOCR?
Бо спочатку потрібна вимірювана межа вузької задачі. TrOCR виправданий, коли абетка і верстка перестають бути вузькими. Сусідня стаття якраз про цей поріг; тут поріг ще не закритий порожніми клітинками і обсягом почерків.
70,9% повного збігання — це мало чи нормально?
Для приймання цеху — мало. Для першого компактного прогону на тисячі значень — чесний базовий рівень, від якого видно, куди йдуть помилки: остання цифра, кома, порожні поля.
Чи можна однією мережею читати і замір, і прізвище?
Технічно так, практично це інша абетка і інша довжина. Замірна голова з комою не повинна «трохи» стати універсальним розпізнавачем. Окремий контур рукописного тексту — коли з'явиться окремий набір.
Чому хибні спрацьовування на порожніх важливіші, ніж ще 2% на цифрах?
Порожня клітинка, перетворена на 8,0, виглядає як упевнений замір. Оператор може не помітити. Недочитана заповнена клітинка частіше потрапляє в «перевірити». Мовчазна галюцинація небезпечніша за явний пропуск.
Чи потрібен GPU, щоб цим користуватися?
Для виводу в пілоті — ні, знімок ваг вантажиться на процесор. Навчання тисячею кропів у нас вкладалося в десятки хвилин. Оренда великого GPU має сенс пізніше, для універсальної моделі, якщо компактна межа вичерпана.
Що почитати далі
Системний контур бланка, людина в петлі і чому не можна згодовувати весь аркуш одній моделі — польові нотатки щодо УЗТ. Навчальна механіка CNN, CTC і коли брати TrOCR — від згортки до трансформера. Що робити з порожньою клітинкою, повтором і закресленням до розпізнавання — класифікатор вмісту клітинки. Як не змішувати навчання й оцінку — інженерія наборів даних. Навіщо рахувати ціну пропуску — економіка вартості збою. Цикл експериментів після базового прогону — якість не росте від запуску навчання. Сусідня промислова постановка «маленька мережа, велика ціна помилки» — ШІ на рентгенограмах зварки.
Висновок
Фіксована сітка бланка УЗТ дозволяє не будувати універсальний розпізнавач. Компактна CRNN з CTC, входом 48 × 160 і приблизно 640 тисячами параметрів дає чесний локальний базовий рівень на рукописних замірах. Далі якість упирається не в «додати шарів», а в порожні клітинки, різноманіття почерку і розділення задач: класифікатор порожньо/значення, правила на дату, окремий друкований контур, людина на хвіст.
Практичний крок: узяти кропи однієї колонки заміру, заборонити собі універсальну модель на цій підмножині і виміряти повне збігання і фантоми на порожніх. Список упевнених помилок скаже про ваш архів більше, ніж таблиця архітектур. У пілоті це все ще відкритий контур: замірна голова жива як режим рушія, класифікатор порожніх попереду, вивантаження в облік — друга фаза.


