08 ноября 2020

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ПО (систСмы PDM/PLM) с 1993 Π³ΠΎΠ΄Π°, компания "Π˜ΠΠ’Π•Π ΠœΠ•Π₯" (www.intermech.ru). Π’ 2020-ΠΌ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ» курсы "ΠžΡΠ½ΠΎΠ²Ρ‹ Data Science" (минская IT Academy) Π Π΅Ρ„Π΅Ρ€Π΅Π½Ρ‚-ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄Ρ‡ΠΈΠΊ тСхничСской Π»ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹ с английского языка.
Π‘Ρ‚Π°Ρ‚ΡŒΡ описываСт распознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² изобраТСниях с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ популярной ΠΌΠΎΠ΄Π΅Π»ΠΈ YOLO. ΠŸΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ΡΡ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ описаниС Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΈ ΠΊΠΎΠ΄, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‰ΠΈΠΉ YOLO v3 Π½Π° Tensorflow 2.0
πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

Π”ΠΎ Yolo Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΎΠ² ΠΊ Ρ€Π°ΡΠΏΠΎΠ·Π½Π°Π²Π°Π½ΠΈΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π»ΠΎΡΡŒ Π² ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ°Ρ… Π°Π΄Π°ΠΏΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ классификаторы ΠΊ Ρ€Π°ΡΠΏΠΎΠ·Π½Π°Π²Π°Π½ΠΈΡŽ. Π’ YOLO, распознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π±Ρ‹Π»ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ ΠΊΠ°ΠΊ Π·Π°Π΄Π°Ρ‡Π° рСгрСссии ΠΊ Ρ€Π°Π·Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‰ΠΈΠΌ Ρ€Π°ΠΌΠΊΠ°ΠΌ, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ связаны вСроятности принадлСТности ΠΊ Ρ€Π°Π·Π½Ρ‹ΠΌ классам. НиТС ΠΌΡ‹ познакомимся с модСлью распознавания ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² YOLO ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ Π΅Π΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π² Tensorflow 2.0.

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0
О YOLO: Наша обобщСнная Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Ρ‡Ρ€Π΅Π·Π²Ρ‹Ρ‡Π°ΠΉΠ½ΠΎ быстра. Базовая модСль YOLO ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ изобраТСния Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ со ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒΡŽ 45 Ρ„Ρ€Π΅ΠΉΠΌΠΎΠ² Π² сСкунду. МСньшая вСрсия ΠΌΠΎΠ΄Π΅Π»ΠΈ, Fast YOLO, ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Ρ†Π΅Π»Ρ‹Ρ… 155 Ρ„Ρ€Π΅ΠΉΠΌΠΎΠ² Π² сСкунду…
β€” You Only Look Once: Unified, Real-Time Object Detection, 2015

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ YOLO?

YOLO – это пСрСдовая ΡΠ΅Ρ‚ΡŒ для распознавания ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² (object detection), разработанная Π”ΠΆΠΎΠ·Π΅Ρ„ΠΎΠΌ Π Π΅Π΄ΠΌΠΎΠ½ΠΎΠΌ (Joseph Redmon). Π“Π»Π°Π²Π½ΠΎΠ΅, Ρ‡Ρ‚ΠΎ ΠΎΡ‚Π»ΠΈΡ‡Π°Π΅Ρ‚ Π΅Π΅ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ… популярных Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ – это ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ. МодСли сСмСйства YOLO Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ быстрыС, Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ быстрСС R-CNN ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ…. Π­Ρ‚ΠΎ Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Ρ€Π°ΡΠΏΠΎΠ·Π½Π°Π²Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ.

Π’ΠΎ врСмя ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ (Π² 2016 Π³ΠΎΠ΄Ρƒ) YOLO ΠΈΠΌΠ΅Π»Π° ΠΏΠ΅Ρ€Π΅Π΄ΠΎΠ²ΡƒΡŽ mAP (mean Average Precision), ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с Ρ‚Π°ΠΊΠΈΠΌΠΈ систСмами, ΠΊΠ°ΠΊ R-CNN ΠΈ DPM. Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, YOLO с Ρ‚Ρ€ΡƒΠ΄ΠΎΠΌ Π»ΠΎΠΊΠ°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Ρ‚ΠΎΡ‡Π½ΠΎ. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, ΠΎΠ½Π° обучаСтся ΠΎΠ±Ρ‰Π΅ΠΌΡƒ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»Π΅Π½ΠΈΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². Π’ Π½ΠΎΠ²ΠΎΠΉ вСрсии ΠΊΠ°ΠΊ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ, Ρ‚Π°ΠΊ ΠΈ Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ систСмы Π±Ρ‹Π»ΠΈ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½Ρ‹.

ΠΠ»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρ‹ (Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ):
Π”Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ Π² основном использовали ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΏΠ»Π°Π²Π°ΡŽΡ‰Π΅Π³ΠΎ Π½Π°Π΄ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ ΠΎΠΊΠ½Π°, ΠΈ классификатора для этих Ρ€Π΅Π³ΠΈΠΎΠ½ΠΎΠ² (DPM – deformable part models). ΠšΡ€ΠΎΠΌΠ΅ этого, R-CNN использовал ΠΌΠ΅Ρ‚ΠΎΠ΄ прСдлоТСния Ρ€Π΅Π³ΠΈΠΎΠ½ΠΎΠ² (region proposal). Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ сначала Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π» ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ содСрТащиС Ρ€Π°ΠΌΠΊΠΈ, послС Ρ‡Π΅Π³ΠΎ для Π½ΠΈΡ… вызывался классификатор, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΠ»Π°ΡΡŒ пост-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° для удалСния Π΄Π²ΠΎΠΉΠ½Ρ‹Ρ… распознаваний ΠΈ ΡƒΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½ΡΡ‚Π²ΠΎΠ²Π°Π½ΠΈΡ содСрТащих Ρ€Π°ΠΌΠΎΠΊ.

YOLO ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π»Π° Π·Π°Π΄Π°Ρ‡Ρƒ распознавания ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΊ Π΅Π΄ΠΈΠ½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡Π΅ рСгрСссии. Она ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ прямо ΠΎΡ‚ пиксСлСй изобраТСния Π΄ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ содСрТащих Ρ€Π°ΠΌΠΎΠΊ ΠΈ вСроятностСй классов. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Сдиная CNN прСдсказываСт мноТСство содСрТащих Ρ€Π°ΠΌΠΎΠΊ ΠΈ вСроятности классов для этих Ρ€Π°ΠΌΠΎΠΊ.

ВСория

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ YOLO смотрит Π½Π° ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·, ΠΏΠ»Π°Π²Π°ΡŽΡ‰Π΅Π΅ ΠΎΠΊΠ½ΠΎ – это Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄. ВмСсто этого, всС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ разбиваСтся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ сСтки Π½Π° ячСйки Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ π‘†βˆ—π‘†. ПослС этого каТдая ячСйка ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° прСдсказаниС Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π²Π΅Ρ‰Π΅ΠΉ

Π’ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, каТдая ячСйка ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° прСдсказаниС Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… содСрТащих Ρ€Π°ΠΌΠΎΠΊ ΠΈ показатСля увСрСнности (confidence) для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΠ· Π½ΠΈΡ… – Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, это Π²Π΅Ρ€ΠΎΡΡ‚Π½ΠΎΡΡ‚ΡŒ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ данная Ρ€Π°ΠΌΠΊΠ° содСрТит ΠΎΠ±ΡŠΠ΅ΠΊΡ‚. Если Π² ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ячСйкС сСтки ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π½Π΅Ρ‚, Ρ‚ΠΎ ΠΎΡ‡Π΅Π½ΡŒ Π²Π°ΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ confidence для этой ячСйки Π±Ρ‹Π» ΠΎΡ‡Π΅Π½ΡŒ ΠΌΠ°Π»Ρ‹ΠΌ.

Когда ΠΌΡ‹ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ всС эти прСдсказания, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΊΠ°Ρ€Ρ‚Ρƒ всСх ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΈ Π½Π°Π±ΠΎΡ€ содСрТащих Ρ€Π°ΠΌΠΎΠΊ, Ρ€Π°Π½ΠΆΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… ΠΏΠΎ ΠΈΡ… confidence.

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

Π’ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, каТдая ячСйка ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° прСдсказаниС вСроятностСй классов. Π­Ρ‚ΠΎ Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ какая-Ρ‚ΠΎ ячСйка содСрТит ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, это всСго лишь Π²Π΅Ρ€ΠΎΡΡ‚Π½ΠΎΡΡ‚ΡŒ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ссли ячСйка сСти прСдсказываСт Π°Π²Ρ‚ΠΎΠΌΠΎΠ±ΠΈΠ»ΡŒ, это Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Ρ‚Π°ΠΌ Π΅ΡΡ‚ΡŒ, Π½ΠΎ это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Ссли Ρ‚Π°ΠΌ Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Ρ‚ΠΎ это Π°Π²Ρ‚ΠΎΠΌΠΎΠ±ΠΈΠ»ΡŒ.

Π”Π°Π²Π°ΠΉΡ‚Π΅ опишСм Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎ, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Π²Ρ‹Π΄Π°Π²Π°Π΅ΠΌΡ‹ΠΉ модСлью Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚.

Π’ YOLO для прСдсказания содСрТащих Ρ€Π°ΠΌΠΎΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ якорныС Ρ€Π°ΠΌΠΊΠΈ (anchor boxes). Π˜Ρ… основная идСя Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² ΠΏΡ€Π΅Π΄ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠΈ Π΄Π²ΡƒΡ… Ρ€Π°Π·Π½Ρ‹Ρ… Ρ€Π°ΠΌΠΎΠΊ, Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹Ρ… якорными Ρ€Π°ΠΌΠΊΠ°ΠΌΠΈ ΠΈΠ»ΠΈ Ρ„ΠΎΡ€ΠΌΠΎΠΉ якорных Ρ€Π°ΠΌΠΎΠΊ. Π­Ρ‚ΠΎ позволяСт Π½Π°ΠΌ Π°ΡΡΠΎΡ†ΠΈΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π²Π° прСдсказания с этими якорными Ρ€Π°ΠΌΠΊΠ°ΠΌΠΈ. Π’ ΠΎΠ±Ρ‰Π΅ΠΌ, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ большСС количСство якорных Ρ€Π°ΠΌΠΎΠΊ (ΠΏΡΡ‚ΡŒ ΠΈΠ»ΠΈ Π΄Π°ΠΆΠ΅ большС). Якоря Π±Ρ‹Π»ΠΈ рассчитаны Π½Π° датасСтС COCO с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ k-means кластСризации.

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

Π£ нас Π΅ΡΡ‚ΡŒ сСтка, каТдая ячСйка ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π΄ΠΎΠ»ΠΆΠ½Π° ΠΏΡ€Π΅Π΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ:

  • для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ содСрТащСй Ρ€Π°ΠΌΠΊΠΈ: 4 ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ (𝑑π‘₯,𝑑𝑦,𝑑𝑀,π‘‘β„Ž) ΠΈ ΠΎΠ΄Π½Ρƒ "ΠΎΡˆΠΈΠ±ΠΊΡƒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎΡΡ‚ΠΈ" – Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ, ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΡƒ confidence, ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‰ΡƒΡŽ, Π΅ΡΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ»ΠΈ Π½Π΅Ρ‚.
  • Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ количСство вСроятностСй классов.

Если Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ смСщСниС ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π²Π΅Ρ€Ρ…Π½Π΅Π³ΠΎ Π»Π΅Π²ΠΎΠ³ΠΎ ΡƒΠ³Π»Π° 𝑐π‘₯,𝑐𝑦, Ρ‚ΠΎ эти прСдсказания ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ Ρ„ΠΎΡ€ΠΌΡƒΠ»Π°ΠΌ:

bx=Οƒ(tx)+cxby=Οƒ(ty)+cybw=pwetwbh=pheth

Π³Π΄Π΅ 𝑝𝑀 ΠΈ π‘β„Ž ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΡˆΠΈΡ€ΠΈΠ½Π΅ ΠΈ высотС содСрТащСй Ρ€Π°ΠΌΠΊΠΈ. ВмСсто прСдсказания смСщСний, ΠΊΠ°ΠΊ Π±Ρ‹Π»ΠΎ Π²ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΉ вСрсии YOLO, Π°Π²Ρ‚ΠΎΡ€Ρ‹ ΠΏΡ€Π΅Π΄ΡΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Π»ΠΎΠΊΠ°Ρ†ΠΈΠΈ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ располоТСния ячСйки сСти.

Π­Ρ‚ΠΎΡ‚ Π²Ρ‹Π²ΠΎΠ΄ – это Π²Ρ‹Π²ΠΎΠ΄ нашСй Π½Π΅ΠΉΡ€ΠΎΠ½Π½ΠΎΠΉ сСти. ВсСго Ρ‚Π°ΠΌ π‘†βˆ—π‘†βˆ—[π΅βˆ—(4+1+𝐢)] Π²Ρ‹Π²ΠΎΠ΄ΠΎΠ², Π³Π΄Π΅ 𝐡 – количСство содСрТащих Ρ€Π°ΠΌΠΎΠΊ, прСдсказываСмых ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ячСйкой (зависит ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, Π² ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… ΠΌΠ°ΡΡˆΡ‚Π°Π±Π°Ρ… ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ наши прСдсказания), 𝐢 – количСство классов, 4 – количСство содСрТащих Ρ€Π°ΠΌΠΎΠΊ, Π° 1 – прСдсказаниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎΡΡ‚ΠΈ. Π—Π° ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€ΠΎΠΉΡ‚ΠΈ ΠΎΡ‚ исходного изобраТСния Π΄ΠΎ Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€Π°, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ распознанным ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ изобраТСния. Π‘Ρ‚ΠΎΠΈΡ‚ Ρ‚Π°ΠΊΠΆΠ΅ ΡƒΠΏΠΎΠΌΡΠ½ΡƒΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ YOLO v3 прСдсказываСт Ρ€Π°ΠΌΠΊΠΈ Π² Ρ‚Ρ€Π΅Ρ… Ρ€Π°Π·Π½Ρ‹Ρ… ΠΌΠ°ΡΡˆΡ‚Π°Π±Π°Ρ….

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, Ссли ΠΌΡ‹ возьмСм вСроятности ΠΈ ΡƒΠΌΠ½ΠΎΠΆΠΈΠΌ ΠΈΡ… Π½Π° значСния confidence, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ всС содСрТащиС Ρ€Π°ΠΌΠΊΠΈ, Π²Π·Π²Π΅ΡˆΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎ ΠΈΡ… вСроятности содСрТания этого ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.

ΠŸΡ€ΠΎΡΡ‚ΠΎΠ΅ сравнСниС с ΠΏΠΎΡ€ΠΎΠ³ΠΎΠΌ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ Π½Π°ΠΌ ΠΈΠ·Π±Π°Π²ΠΈΡ‚ΡŒΡΡ ΠΎΡ‚ прСдсказаний с Π½ΠΈΠ·ΠΊΠΎΠΉ confidence. Для ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ шага Π²Π°ΠΆΠ½ΠΎ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ пСрСсСчСниС ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ объСдинСния (intersection over union). Π­Ρ‚ΠΎ ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ ΠΏΠ»ΠΎΡ‰Π°Π΄ΠΈ пСрСсСчСния ΠΏΡ€ΡΠΌΠΎΡƒΠ³ΠΎΠ»ΡŒΠ½ΠΈΠΊΠΎΠ² ΠΊ ΠΏΠ»ΠΎΡ‰Π°Π΄ΠΈ ΠΈΡ… объСдинСния:

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

ПослС этого Ρƒ нас Π΅Ρ‰Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚Ρ‹, ΠΈ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ Π½ΠΈΡ… ΠΈΠ·Π±Π°Π²ΠΈΡ‚ΡŒΡΡ, ΠΌΡ‹ примСняСм ΠΏΠΎΠ΄Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π΅-максимумов. ПодавлСниС Π½Π΅-максимумов Π±Π΅Ρ€Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‰ΡƒΡŽ Ρ€Π°ΠΌΠΊΡƒ с максимальной Π²Π΅Ρ€ΠΎΡΡ‚Π½ΠΎΡΡ‚ΡŒΡŽ ΠΈ смотрит Π½Π° Π΄Ρ€ΡƒΠ³ΠΈΠ΅ содСрТащиС Ρ€Π°ΠΌΠΊΠΈ, располоТСнныС Π±Π»ΠΈΠ·ΠΊΠΎ ΠΊ ΠΏΠ΅Ρ€Π²ΠΎΠΉ. Π‘Π»ΠΈΠΆΠ°ΠΉΡˆΠΈΠ΅ Ρ€Π°ΠΌΠΊΠΈ с ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΌ пСрСсСчСниСм ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ объСдинСния с ΠΏΠ΅Ρ€Π²ΠΎΠΉ Ρ€Π°ΠΌΠΊΠΎΠΉ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠΎΠ΄Π°Π²Π»Π΅Π½Ρ‹.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ всС дСлаСтся Π·Π° ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΎΡ…ΠΎΠ΄, модСль Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΠΎΡ‡Ρ‚ΠΈ с Ρ‚Π°ΠΊΠΎΠΉ ΠΆΠ΅ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒΡŽ, ΠΊΠ°ΠΊ классификация. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, всС прСдсказания производятся ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ, Π° это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ модСль нСявно встраиваСт Π² сСбя Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹ΠΉ контСкст. ΠŸΡ€ΠΎΡ‰Π΅ говоря, модСль ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΡΠ²ΠΎΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π²ΡΡ‚Ρ€Π΅Ρ‡Π°ΡŽΡ‚ΡΡ вмСстС, ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π°Π·ΠΌΠ΅Ρ€Ρ‹ ΠΈ располоТСниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅.

ΠœΡ‹ Π½Π°ΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ всС Ρ‚Ρ€ΠΈ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° YOLO:

РСализация YOLO Π² Tensorflow

ΠœΡ‹ создадим ΠΏΠΎΠ»Π½ΡƒΡŽ ΡΠ²Π΅Ρ€Ρ‚ΠΎΡ‡Π½ΡƒΡŽ Π½Π΅ΠΉΡ€ΠΎΠ½Π½ΡƒΡŽ ΡΠ΅Ρ‚ΡŒ (Fully Convolutional Network, FCN) Π±Π΅Π· Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠΈ. Π§Ρ‚ΠΎΠ±Ρ‹ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΡ€Π΅Π΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ этой сСти, Π½ΡƒΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ вСса ΠΎΡ‚ Π·Π°Ρ€Π°Π½Π΅Π΅ Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ. Π­Ρ‚ΠΈ вСса ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Ρ‹ послС Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠΈ YOLOv3 Π½Π° датасСтС COCO (Common Objects in Context), ΠΈ ΠΈΡ… ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ с ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ сайта.

        !wget https://pjreddie.com/media/files/yolov3.weights
    

Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΏΠ°ΠΏΠΊΡƒ для хранСния вСсов

        #!rm -rf checkpoints
!mkdir checkpoints
    

Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ

        import cv2
import numpy as np
import tensorflow as tf

from absl import logging
from itertools import repeat

from tensorflow.keras import Model
from tensorflow.keras.layers import Add, Concatenate, Lambda
from tensorflow.keras.layers import Conv2D, Input, LeakyReLU
from tensorflow.keras.layers import MaxPool2D, UpSampling2D, ZeroPadding2D
from tensorflow.keras.regularizers import l2
from tensorflow.keras.losses import binary_crossentropy
from tensorflow.keras.losses import sparse_categorical_crossentropy
    

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ Π²Π΅Ρ€ΡΠΈΡŽ Tensorflow. Она Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π½Π΅ Π½ΠΈΠΆΠ΅ 2.0:

        print(tf.__version__)
# 2.1.0
    

ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ нСсколько Π²Π°ΠΆΠ½Ρ‹Ρ… ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½ΠΈΠΆΠ΅.

        yolo_iou_threshold   = 0.6 # ΠΏΠΎΡ€ΠΎΠ³ пСрСсСчСния ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ объСдинСния (iou)
yolo_score_threshold = 0.6 

weightsyolov3 = 'yolov3.weights' # ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ вСсов
weights= 'checkpoints/yolov3.tf' # ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ checkpoint'ΠΎΠ²
size= 416             # ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΠΌ изобраТСния ΠΊ этому Ρ€Π°Π·ΠΌΠ΅Ρ€Ρƒ 
checkpoints = 'checkpoints/yolov3.tf'
num_classes = 80      # количСство классов Π² ΠΌΠΎΠ΄Π΅Π»ΠΈ
    

Бписок слоСв Π² YOLOv3 FCN β€” Fully Convolutional Network

        YOLO_V3_LAYERS = [
  'yolo_darknet',
  'yolo_conv_0',
  'yolo_output_0',
  'yolo_conv_1',
  'yolo_output_1',
  'yolo_conv_2',
  'yolo_output_2',
]
    

ΠžΡ‡Π΅Π½ΡŒ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ вСса с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ чисто Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ API, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ порядок слоСв Π² Darknet ΠΈ tf.keras Ρ€Π°Π·Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ. Π—Π΄Π΅ΡΡŒ Π»ΡƒΡ‡ΡˆΠ΅Π΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ – созданиС ΠΏΠΎΠ΄ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π² keras. Для сохранСния ΠΏΠΎΠ΄ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ рСкомСндуСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Checkpoint'Ρ‹ Tensorflow, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ½ΠΈ ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ Tensorflow.

Π’ΠΎΡ‚ функция для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ вСсов ΠΈΠ· ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ YOLO Π² Darknet:

        def load_darknet_weights(model, weights_file):
  wf = open(weights_file, 'rb')
  major, minor, revision, seen, _ = np.fromfile(wf, dtype=np.int32, count=5)
  layers = YOLO_V3_LAYERS

  for layer_name in layers:
    sub_model = model.get_layer(layer_name)
    for i, layer in enumerate(sub_model.layers):
      if not layer.name.startswith('conv2d'):
        continue
      batch_norm = None
      if i + 1 < len(sub_model.layers) and \
            sub_model.layers[i + 1].name.startswith('batch_norm'):
        batch_norm = sub_model.layers[i + 1]

      logging.info("{}/{} {}".format(
        sub_model.name, layer.name, 'bn' if batch_norm else 'bias'))

      filters = layer.filters
      size = layer.kernel_size[0]
      in_dim = layer.input_shape[-1]

      if batch_norm is None:
        conv_bias = np.fromfile(wf, dtype=np.float32, count=filters)
      else:
        bn_weights = np.fromfile(
          wf, dtype=np.float32, count=4 * filters)

        bn_weights = bn_weights.reshape((4, filters))[[1, 0, 2, 3]]

      conv_shape = (filters, in_dim, size, size)
      conv_weights = np.fromfile(
        wf, dtype=np.float32, count=np.product(conv_shape))

      conv_weights = conv_weights.reshape(
        conv_shape).transpose([2, 3, 1, 0])

      if batch_norm is None:
        layer.set_weights([conv_weights, conv_bias])
      else:
        layer.set_weights([conv_weights])
        batch_norm.set_weights(bn_weights)

  assert len(wf.read()) == 0, 'Π½Π΅ ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ всС Π΄Π°Π½Π½Ρ‹Π΅'
  wf.close()
    

Ѐункция для расчСта пСрСсСчСния ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ объСдинСния

        def interval_overlap(interval_1, interval_2):
  x1, x2 = interval_1
  x3, x4 = interval_2
  if x3 < x1:
    return 0 if x4 < x1 else (min(x2,x4) - x1)
  else:
    return 0 if x2 < x3 else (min(x2,x4) - x3)

def intersectionOverUnion(box1, box2):
  intersect_w = interval_overlap([box1.xmin, box1.xmax], [box2.xmin, box2.xmax])
  intersect_h = interval_overlap([box1.ymin, box1.ymax], [box2.ymin, box2.ymax])
  intersect_area = intersect_w * intersect_h
  
  w1, h1 = box1.xmax-box1.xmin, box1.ymax-box1.ymin
  w2, h2 = box2.xmax-box2.xmin, box2.ymax-box2.ymin
  
  union_area = w1*h1 + w2*h2 - intersect_area
  return float(intersect_area) / union_area
    

Ѐункция для отрисовки содСрТащСй Ρ€Π°ΠΌΠΊΠΈ, ΠΈΠΌΠ΅Π½ΠΈ класса ΠΈ вСроятности:

        def draw_outputs(img, outputs, class_names):
  boxes, score, classes, nums = outputs
  boxes, score, classes, nums = boxes[0], score[0], classes[0], nums[0]
  wh = np.flip(img.shape[0:2])
  for i in range(nums):
    x1y1 = tuple((np.array(boxes[i][0:2]) * wh).astype(np.int32))
    x2y2 = tuple((np.array(boxes[i][2:4]) * wh).astype(np.int32))
    img = cv2.rectangle(img, x1y1, x2y2, (255, 0, 0), 2)
    img = cv2.putText(img, '{} {:.4f}'.format(
      class_names[int(classes[i])], score[i]),
      x1y1, cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 0, 255), 2)
  return img
    

ΠœΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΠΏΠ°ΠΊΠ΅Ρ‚Π½ΡƒΡŽ Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ (batch normalization), Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΎΡ€ΠΌΠ°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ для ускорСния Ρ‚Ρ€Π΅Π½ΠΈΡ€ΠΎΠ²ΠΊΠΈ. К соТалСнию, tf.keras.layers.BatchNormalization Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ Ρ…ΠΎΡ€ΠΎΡˆΠΎ для transfer learning, поэтому здСсь прСдлагаСтся Π΄Ρ€ΡƒΠ³ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ этой ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹.

        class BatchNormalization(tf.keras.layers.BatchNormalization):
  def call(self, x, training=False):
    if training is None: training = tf.constant(False)
    training = tf.logical_and(training, self.trainable)
    return super().call(x, training)
    

Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΌΠ°ΡΡˆΡ‚Π°Π±Π° ΠΌΡ‹ опрСдСляСм Ρ‚Ρ€ΠΈ якорныС Ρ€Π°ΠΌΠΊΠΈ для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ячСйки. Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ маска Ρ‚Π°ΠΊΠΎΠ²Π°:

  • 0,1,2 – ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Ρ€ΠΈ ΠΏΠ΅Ρ€Π²Ρ‹Π΅ якорныС Ρ€Π°ΠΌΠΊΠΈ
  • 3,4,5 – ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ‡Π΅Ρ‚Π²Π΅Ρ€Ρ‚ΡƒΡŽ, ΠΏΡΡ‚ΡƒΡŽ ΠΈ ΡˆΠ΅ΡΡ‚ΡƒΡŽ Ρ€Π°ΠΌΠΊΠΈ
  • 6,7,8 – ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡΠ΅Π΄ΡŒΠΌΡƒΡŽ, Π²ΠΎΡΡŒΠΌΡƒΡŽ ΠΈ Π΄Π΅Π²ΡΡ‚ΡƒΡŽ Ρ€Π°ΠΌΠΊΠΈ

РСализация YOLO v3

ΠŸΡ€ΠΈΡˆΠ»ΠΎ врСмя Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠ΅Ρ‚ΡŒ YOLOv3. Π’ΠΎΡ‚ ΠΊΠ°ΠΊ выглядит Π΅Π΅ структура:

Darknet 53 – YOLO v3
Darknet 53 – YOLO v3

Π—Π΄Π΅ΡΡŒ основная идСя – ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ свСрточныС слои. Π˜Ρ… Ρ‚Π°ΠΌ 53, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΡ‰Π΅ всСго ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Π²Π°ΠΆΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, ΠΈΠ·ΠΌΠ΅Π½ΡΡŽΡ‰ΠΈΠ΅ΡΡ ΠΎΡ‚ слоя ΠΊ слою.

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

ΠžΡΡ‚Π°Ρ‚ΠΎΡ‡Π½Ρ‹Π΅ Π±Π»ΠΎΠΊΠΈ (Residual blocks) Π½Π° Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠΌΠ΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ YOLOv3 ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ для обучСния ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠ°ΠΌ. ΠžΡΡ‚Π°Ρ‚ΠΎΡ‡Π½Ρ‹ΠΉ Π±Π»ΠΎΠΊ состоит ΠΈΠ· Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… свСрточных слоСв ΠΈ ΠΎΠ±Ρ…ΠΎΠ΄Π½Ρ‹Ρ… ΠΏΡƒΡ‚Π΅ΠΉ:

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

ΠœΡ‹ строим Π½Π°ΡˆΡƒ модСль с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π€ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ API, простого Π² использовании. Π‘ Π½ΠΈΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π»Π΅Π³ΠΊΠΎ Π·Π°Π΄Π°Π²Π°Ρ‚ΡŒ Π²Π΅Ρ‚Π²ΠΈ Π² нашСй Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ (Π±Π»ΠΎΠΊ ResNet) ΠΈ Π»Π΅Π³ΠΊΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΈ ΠΈ Ρ‚Π΅ ΠΆΠ΅ слои нСсколько Ρ€Π°Π· Π²Π½ΡƒΡ‚Ρ€ΠΈ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹.

        def DarknetConv(x, filters, size, strides=1, batch_norm=True):
  if strides == 1:
    padding = 'same'
  else:
    x = ZeroPadding2D(((1, 0), (1, 0)))(x)  # top left half-padding
    padding = 'valid'
  x = Conv2D(filters=filters, kernel_size=size,
          strides=strides, padding=padding,
          use_bias=not batch_norm, kernel_regularizer=l2(0.0005))(x)
  if batch_norm:
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.1)(x)
  return x

def DarknetResidual(x, filters):
  previous  = x
  x = DarknetConv(x, filters // 2, 1)
  x = DarknetConv(x, filters, 3)
  x = Add()([previous , x])
  return x


def DarknetBlock(x, filters, blocks):
  x = DarknetConv(x, filters, 3, strides=2)
  for _ in repeat(None, blocks):
    x = DarknetResidual(x, filters)       
  return x


def Darknet(name=None):
  x = inputs = Input([None, None, 3])
  x = DarknetConv(x, 32, 3)
  x = DarknetBlock(x, 64, 1)
  x = DarknetBlock(x, 128, 2)
  x = x_36 = DarknetBlock(x, 256, 8)
  x = x_61 = DarknetBlock(x, 512, 8)
  x = DarknetBlock(x, 1024, 4)
  return tf.keras.Model(inputs, (x_36, x_61, x), name=name)

def YoloConv(filters, name=None):
  def yolo_conv(x_in):
    if isinstance(x_in, tuple):
      inputs = Input(x_in[0].shape[1:]), Input(x_in[1].shape[1:])
      x, x_skip = inputs

      x = DarknetConv(x, filters, 1)
      x = UpSampling2D(2)(x)
      x = Concatenate()([x, x_skip])
    else:
      x = inputs = Input(x_in.shape[1:])

    x = DarknetConv(x, filters, 1)
    x = DarknetConv(x, filters * 2, 3)
    x = DarknetConv(x, filters, 1)
    x = DarknetConv(x, filters * 2, 3)
    x = DarknetConv(x, filters, 1)
    return Model(inputs, x, name=name)(x_in)
  return yolo_conv

def YoloOutput(filters, anchors, classes, name=None):
  def yolo_output(x_in):
    x = inputs = Input(x_in.shape[1:])
    x = DarknetConv(x, filters * 2, 3)
    x = DarknetConv(x, anchors * (classes + 5), 1, batch_norm=False)
    x = Lambda(lambda x: tf.reshape(x, (-1, tf.shape(x)[1], tf.shape(x)[2],
                                        anchors, classes + 5)))(x)
    return tf.keras.Model(inputs, x, name=name)(x_in)
  return yolo_output

def yolo_boxes(pred, anchors, classes):
  grid_size = tf.shape(pred)[1]
  box_xy, box_wh, score, class_probs = tf.split(pred, (2, 2, 1, classes), axis=-1)

  box_xy = tf.sigmoid(box_xy)
  score = tf.sigmoid(score)
  class_probs = tf.sigmoid(class_probs)
  pred_box = tf.concat((box_xy, box_wh), axis=-1)

  grid = tf.meshgrid(tf.range(grid_size), tf.range(grid_size))
  grid = tf.expand_dims(tf.stack(grid, axis=-1), axis=2)

  box_xy = (box_xy + tf.cast(grid, tf.float32)) /  tf.cast(grid_size, tf.float32)
  box_wh = tf.exp(box_wh) * anchors

  box_x1y1 = box_xy - box_wh / 2
  box_x2y2 = box_xy + box_wh / 2
  bbox = tf.concat([box_x1y1, box_x2y2], axis=-1)

  return bbox, score, class_probs, pred_box
    

ПодавлСниС Π½Π΅-максимумов

        def nonMaximumSuppression(outputs, anchors, masks, classes):
  boxes, conf, out_type = [], [], []

  for output in outputs:
    boxes.append(tf.reshape(output[0], (tf.shape(output[0])[0], -1, tf.shape(output[0])[-1])))
    conf.append(tf.reshape(output[1], (tf.shape(output[1])[0], -1, tf.shape(output[1])[-1])))
    out_type.append(tf.reshape(output[2], (tf.shape(output[2])[0], -1, tf.shape(output[2])[-1])))

  bbox = tf.concat(boxes, axis=1)
  confidence = tf.concat(conf, axis=1)
  class_probs = tf.concat(out_type, axis=1)

  scores = confidence * class_probs
  
  boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression(
    boxes=tf.reshape(bbox, (tf.shape(bbox)[0], -1, 1, 4)),
    scores=tf.reshape(
        scores, (tf.shape(scores)[0], -1, tf.shape(scores)[-1])),
    max_output_size_per_class=100,
    max_total_size=100,
    iou_threshold=yolo_iou_threshold,
    score_threshold=yolo_score_threshold
  )
  
  return boxes, scores, classes, valid_detections
    

Основная функция, ΡΠΎΠ·Π΄Π°ΡŽΡ‰Π°Ρ всю модСль:

        def YoloV3(size=None, channels=3, anchors=yolo_anchors,
          masks=yolo_anchor_masks, classes=80, training=False):
  x = inputs = Input([size, size, channels])

  x_36, x_61, x = Darknet(name='yolo_darknet')(x)

  x = YoloConv(512, name='yolo_conv_0')(x)
  output_0 = YoloOutput(512, len(masks[0]), classes, name='yolo_output_0')(x)

  x = YoloConv(256, name='yolo_conv_1')((x, x_61))
  output_1 = YoloOutput(256, len(masks[1]), classes, name='yolo_output_1')(x)

  x = YoloConv(128, name='yolo_conv_2')((x, x_36))
  output_2 = YoloOutput(128, len(masks[2]), classes, name='yolo_output_2')(x)

  if training:
    return Model(inputs, (output_0, output_1, output_2), name='yolov3')

  boxes_0 = Lambda(lambda x: yolo_boxes(x, anchors[masks[0]], classes),
                  name='yolo_boxes_0')(output_0)
  boxes_1 = Lambda(lambda x: yolo_boxes(x, anchors[masks[1]], classes),
                  name='yolo_boxes_1')(output_1)
  boxes_2 = Lambda(lambda x: yolo_boxes(x, anchors[masks[2]], classes),
                  name='yolo_boxes_2')(output_2)

  outputs = Lambda(lambda x: nonMaximumSuppression(x, anchors, masks, classes),
                  name='nonMaximumSuppression')((boxes_0[:3], boxes_1[:3], boxes_2[:3]))

  return Model(inputs, outputs, name='yolov3')
    

Ѐункция ΠΏΠΎΡ‚Π΅Ρ€ΡŒ с Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ:

        def YoloLoss(anchors, classes=80, ignore_thresh=0.5):
    def yolo_loss(y_true, y_pred):
        # 1. transform all pred outputs
        # y_pred: (batch_size, grid, grid, anchors, (x, y, w, h, obj, ...cls))
        pred_box, pred_obj, pred_class, pred_xywh = yolo_boxes(
            y_pred, anchors, classes)
        pred_xy = pred_xywh[..., 0:2]
        pred_wh = pred_xywh[..., 2:4]

        # 2. transform all true outputs
        # y_true: (batch_size, grid, grid, anchors, (x1, y1, x2, y2, obj, cls))
        true_box, true_obj, true_class_idx = tf.split(
            y_true, (4, 1, 1), axis=-1)
        true_xy = (true_box[..., 0:2] + true_box[..., 2:4]) / 2
        true_wh = true_box[..., 2:4] - true_box[..., 0:2]

        # give higher weights to small boxes
        box_loss_scale = 2 - true_wh[..., 0] * true_wh[..., 1]

        # 3. inverting the pred box equations
        grid_size = tf.shape(y_true)[1]
        grid = tf.meshgrid(tf.range(grid_size), tf.range(grid_size))
        grid = tf.expand_dims(tf.stack(grid, axis=-1), axis=2)
        true_xy = true_xy * tf.cast(grid_size, tf.float32) - \
            tf.cast(grid, tf.float32)
        true_wh = tf.math.log(true_wh / anchors)
        true_wh = tf.where(tf.math.is_inf(true_wh),
                           tf.zeros_like(true_wh), true_wh)

        # 4. calculate all masks
        obj_mask = tf.squeeze(true_obj, -1)
        # ignore false positive when iou is over threshold
        true_box_flat = tf.boolean_mask(true_box, tf.cast(obj_mask, tf.bool))
        best_iou = tf.reduce_max(broadcast_iou(
            pred_box, true_box_flat), axis=-1)
        ignore_mask = tf.cast(best_iou < ignore_thresh, tf.float32)

        # 5. calculate all losses
        xy_loss = obj_mask * box_loss_scale * \
            tf.reduce_sum(tf.square(true_xy - pred_xy), axis=-1)
        wh_loss = obj_mask * box_loss_scale * \
            tf.reduce_sum(tf.square(true_wh - pred_wh), axis=-1)
        obj_loss = binary_crossentropy(true_obj, pred_obj)
        obj_loss = obj_mask * obj_loss + \
            (1 - obj_mask) * ignore_mask * obj_loss
        # TODO: use binary_crossentropy instead
        class_loss = obj_mask * sparse_categorical_crossentropy(
            true_class_idx, pred_class)

        # 6. sum over (batch, gridx, gridy, anchors) => (batch, 1)
        xy_loss = tf.reduce_sum(xy_loss, axis=(1, 2, 3))
        wh_loss = tf.reduce_sum(wh_loss, axis=(1, 2, 3))
        obj_loss = tf.reduce_sum(obj_loss, axis=(1, 2, 3))
        class_loss = tf.reduce_sum(class_loss, axis=(1, 2, 3))

        return xy_loss + wh_loss + obj_loss + class_loss
    return yolo_loss
    

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ функция трансформируСт Ρ†Π΅Π»Π΅Π²Ρ‹Π΅ Π²Ρ‹Π²ΠΎΠ΄Ρ‹ ΠΊ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΡƒ (tuple) ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ Ρ„ΠΎΡ€ΠΌΡ‹:

([N,13,13,3,6],[N,26,26,3,6],[N,52,52,3,6])

Π—Π΄Π΅ΡΡŒ N – количСство ΠΌΠ΅Ρ‚ΠΎΠΊ Π² ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ (batch), Π° 6 прСдставляСт [x, y, w, h, obj, class] содСрТащих Ρ€Π°ΠΌΠΎΠΊ.

        @tf.function
def transform_targets_for_output(y_true, grid_size, anchor_idxs, classes):

  N = tf.shape(y_true)[0]

  y_true_out = tf.zeros(
      (N, grid_size, grid_size, tf.shape(anchor_idxs)[0], 6))

  anchor_idxs = tf.cast(anchor_idxs, tf.int32)

  indexes = tf.TensorArray(tf.int32, 1, dynamic_size=True)
  updates = tf.TensorArray(tf.float32, 1, dynamic_size=True)
  idx = 0
  for i in tf.range(N):
    for j in tf.range(tf.shape(y_true)[1]):
      if tf.equal(y_true[i][j][2], 0):
        continue
      anchor_eq = tf.equal(
        anchor_idxs, tf.cast(y_true[i][j][5], tf.int32))

      if tf.reduce_any(anchor_eq):
        box = y_true[i][j][0:4]
        box_xy = (y_true[i][j][0:2] + y_true[i][j][2:4]) / 2

        anchor_idx = tf.cast(tf.where(anchor_eq), tf.int32)
        grid_xy = tf.cast(box_xy // (1/grid_size), tf.int32)

        indexes = indexes.write(
            idx, [i, grid_xy[1], grid_xy[0], anchor_idx[0][0]])
        updates = updates.write(
          idx, [box[0], box[1], box[2], box[3], 1, y_true[i][j][4]])
        idx += 1

  return tf.tensor_scatter_nd_update(
    y_true_out, indexes.stack(), updates.stack())


def transform_targets(y_train, anchors, anchor_masks, classes):
  outputs = []
  grid_size = 13

  anchors = tf.cast(anchors, tf.float32)
  anchor_area = anchors[..., 0] * anchors[..., 1]
  box_wh = y_train[..., 2:4] - y_train[..., 0:2]
  box_wh = tf.tile(tf.expand_dims(box_wh, -2),
                    (1, 1, tf.shape(anchors)[0], 1))
  box_area = box_wh[..., 0] * box_wh[..., 1]
  intersection = tf.minimum(box_wh[..., 0], anchors[..., 0]) * \
    tf.minimum(box_wh[..., 1], anchors[..., 1])
  iou = intersection / (box_area + anchor_area - intersection)
  anchor_idx = tf.cast(tf.argmax(iou, axis=-1), tf.float32)
  anchor_idx = tf.expand_dims(anchor_idx, axis=-1)

  y_train = tf.concat([y_train, anchor_idx], axis=-1)

  for anchor_idxs in anchor_masks:
    outputs.append(transform_targets_for_output(
      y_train, grid_size, anchor_idxs, classes))
    grid_size *= 2

  return tuple(outputs) # [x, y, w, h, obj, class]


def preprocess_image(x_train, size):
  return (tf.image.resize(x_train, (size, size))) / 255
    

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ создаСм экзСмпляр нашСй ΠΌΠΎΠ΄Π΅Π»ΠΈ, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ вСса ΠΈ ΠΈΠΌΠ΅Π½Π° классов. Π’ датасСтС COCO ΠΈΡ… 80.

        yolo = YoloV3(classes=num_classes)

load_darknet_weights(yolo, weightsyolov3)

yolo.save_weights(checkpoints)

class_names =  ["person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck",
  "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench",
  "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe",
  "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard",
  "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
  "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl",
  "banana","apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
  "cake","chair", "sofa", "pottedplant", "bed", "diningtable", "toilet", "tvmonitor", "laptop",
  "mouse","remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink",
  "refrigerator","book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]
    

Π’ΠΎΡ‚ ΠΈ всС! ΠŸΡ€ΡΠΌΠΎ сСйчас ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΈ ΠΏΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π°ΡˆΡƒ модСль Π½Π° ΠΊΠ°ΠΊΠΎΠΌ-Π½ΠΈΠ±ΡƒΠ΄ΡŒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ.

Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ это ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ» detect.jpg
Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ это ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ» detect.jpg
        name = 'detect.jpg'
img = tf.image.decode_image(open(name, 'rb').read(), channels=3)
img = tf.expand_dims(img, 0)
img = preprocess_image(img, size)

boxes, scores, classes, nums = yolo(img) #eager mode

img = cv2.imread(name)
img = draw_outputs(img, (boxes, scores, classes, nums), class_names)
cv2.imwrite('output.jpg', img)
    

ПослС выполнСния этого ΠΊΠΎΠ΄Π° Π² Ρ„Π°ΠΉΠ»Π΅ output.jpg окаТСтся Ρ‚ΠΎ ΠΆΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ с Ρ€Π°ΠΌΠΊΠ°ΠΌΠΈ, ΠΎΡ‚ΠΌΠ΅Ρ‡Π°ΡŽΡ‰ΠΈΠΌΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, распознанныС нашСй Π½Π΅ΠΉΡ€ΠΎΠ½Π½ΠΎΠΉ ΡΠ΅Ρ‚ΡŒΡŽ:

πŸ” πŸŽ₯ РаспознаваниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ YOLO v3 Π½Π° Tensorflow 2.0

РаспознаваниС Π²ΠΈΠ΄Π΅ΠΎ с ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹

ΠœΡ‹ ΡƒΠΆΠ΅ добились Π²ΠΏΠ΅Ρ‡Π°Ρ‚Π»ΡΡŽΡ‰Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π½ΠΎ Π³Π»Π°Π²Π½ΠΎΠ΅ Π΅Ρ‰Π΅ Π²ΠΏΠ΅Ρ€Π΅Π΄ΠΈ! Π‘Π°ΠΌΠΎΠ΅ Π²Π°ΠΆΠ½ΠΎΠ΅ Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ YOLO Π½Π΅ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° довольно Π½Π΅ΠΏΠ»ΠΎΡ…ΠΎ ΡƒΠΌΠ΅Π΅Ρ‚ Ρ€Π°ΡΠΏΠΎΠ·Π½Π°Π²Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, Π° Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° Π΄Π΅Π»Π°Π΅Ρ‚ это быстро. ΠΠ°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ быстро, Ρ‡Ρ‚ΠΎ успСваСт ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ всС ΠΊΠ°Π΄Ρ€Ρ‹, ΠΏΠΎΡΡ‚ΡƒΠΏΠ°ΡŽΡ‰ΠΈΠ΅ ΠΎΡ‚ Π²Π΅Π±-ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹. Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ Π²Π΅Π±-ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ ΠΈ запуститС ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΊΠΎΠ΄:

        cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    #img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    img = tf.expand_dims(frame, 0)
    img = preprocess_image(img, size)
    boxes, scores, classes, nums = yolo(img) #eager mode
    img = draw_outputs(frame, (boxes, scores, classes, nums), class_names)

    # Display the resulting frame
    cv2.imshow('frame',img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
    

Π’Ρ‹ ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅ Π½Π° экранС ΠΈΠ·ΠΌΠ΅Π½ΡΡŽΡ‰ΡƒΡŽΡΡ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ с ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±ΡƒΠ΄ΡƒΡ‚ ΠΎΡ‚ΠΌΠ΅Ρ‡Π΅Π½Ρ‹ всС распознанныС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Ρ‚ΡŒ свою ΠΊΠ°ΠΌΠ΅Ρ€Ρƒ ΠΈΠ»ΠΈ Π΄Π²ΠΈΠ³Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Π² ΠΊΠ°Π΄Ρ€Π΅, ΠΈ нСйронная ΡΠ΅Ρ‚ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΡΠΏΠ΅Π²Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ ΠΌΠ΅Π½ΡΡŽΡ‰ΠΈΠ΅ΡΡ изобраТСния.

Π–Π΅Π»Π°ΡŽ ΡƒΠ΄Π°Ρ‡Π½Ρ‹Ρ… ΠΈ Π·Π°Π±Π°Π²Π½Ρ‹Ρ… экспСримСнтов с YOLO!

Бсылки:

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

ΠœΠ•Π ΠžΠŸΠ Π˜Π―Π’Π˜Π―

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

Π’ΠΠšΠΠΠ‘Π˜Π˜

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ вакансию

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•