Kliknij lub przeciągnij plik

JPG, PNG lub MP4 • maks. 200 MB

podgląd

Klasyfikator gatunków ptaków

Projekt edukacyjny demonstrujący uczenie transferowe z TensorFlow i EfficientNetB0. Realizowany w ramach programu Lekcja AI.

1486 gatunków ptaków
~208K zdjęć treningowych
224×224 wejście sieci (px)
Top-5 wyniki klasyfikacji
Cele edukacyjne
  • Zrozumieć czym jest uczenie transferowe i dlaczego jest efektywne
  • Poznać architekturę EfficientNetB0 i zasadę compound scaling
  • Zbudować model w TensorFlow / Keras z potokiem tf.data
  • Zoptymalizować inferencję za pomocą OpenVINO (Intel)
  • Wdrożyć model jako aplikację webową (Flask + Gunicorn + Nginx)
Jak działa klasyfikacja?
1. Wgraj zdjęcie lub wideo
Obsługiwane formaty: JPG, PNG (zdjęcie), MP4 (wideo do 200 MB).
2. Preprocessing — skalowanie do 224 × 224 px
EfficientNetB0 zawiera wewnętrzną normalizację — piksele podajemy w zakresie 0–255. Dla wideo próbkujemy równomiernie do 120 klatek i uśredniamy wyniki.
3. Inferencja — sieć analizuje wzorce wizualne
Model przetwarza obraz przez setki warstw, wykrywając cechy: od krawędzi i tekstur po dziób, skrzydła i wzory upierzenia.
4. Top-5 — 5 najbardziej prawdopodobnych gatunków
Wyniki jako prawdopodobieństwa (softmax). Przy 1486 gatunkach losowe trafienie to zaledwie 0.07%.
EfficientNetB0 — gotowy szkielet sieci

EfficientNetB0 to sieć konwolucyjna zaprojektowana przez Google (2019). Osiąga doskonałą dokładność przy zaledwie ~5,3 M parametrów dzięki compound scaling — jednoczesnego skalowania głębokości, szerokości i rozdzielczości wejścia.

Głębokość
Więcej warstw = bogatsze, bardziej abstrakcyjne cechy
Szerokość
Więcej kanałów = lepsza detekcja różnych wzorców
Rozdzielczość
Wyższe wejście = drobniejsze szczegóły, większy koszt
Kluczowa zaleta: Model był trenowany na ImageNet (1,4 mln zdjęć, 1000 klas). Nauczył się rozpoznawać krawędzie, tekstury i kształty. W naszym projekcie korzystamy z tej wiedzy — nie zaczynamy od zera.
Uczenie transferowe — dwie fazy trenowania
Faza 1 Uczenie głowy klasyfikacyjnej
  • Szkielet EfficientNetB0 zamrożony — wagi niezmieniane
  • Trenujemy nową głowę: Dense(512) → Dropout → Dense(1486)
  • Wysoka szybkość uczenia: LR = 1e-3
  • Model szybko mapuje cechy ImageNet na gatunki ptaków
Faza 2 Dostrajanie (fine-tuning)
  • Odblokowujemy górne 30% warstw szkieletu
  • Bardzo niska szybkość: LR = 1e-5 (100× mniejsza!)
  • Chronimy przed katastrofalnym zapominaniem wiedzy z ImageNet
  • Model specjalizuje się w cechach charakterystycznych dla ptaków
Dlaczego LR musi być 100× mniejsza w Fazie 2? Zbyt duże gradienty zniszczyłyby wagi wyuczone na 1,4 mln zdjęciach ImageNet. Model "zapomniałby" jak rozpoznawać wzorce wizualne i musiałby uczyć się od zera.
Zbiór danych — iNaturalist Birds

Projekt używa zbioru iNaturalist Birds dostępnego na Kaggle. Zdjęcia przesłane przez obserwatorów przyrody z całego świata, zweryfikowane przez ekspertów ornitologów.

  • 1486 gatunków ptaków z całego świata
  • Około 140 zdjęć na gatunek — uczenie z ograniczonymi danymi
  • Struktura: archive/birds_train_small/<gatunek>/
  • Nazwa folderu: 03111_Animalia_Chordata_Aves_Rząd_Rodzina_Rodzaj_gatunek
1486
gatunków

~208K
zdjęć łącznie

~15 GB
rozmiar zbioru
Optymalizacja inferencji z OpenVINO

OpenVINO (Open Visual Inference and Neural Network Optimization) to biblioteka Intel optymalizująca modele AI do inferencji na CPU, iGPU i NPU.

Szybsza inferencja
Fuzja warstw i optymalizacja grafu
Mniejszy model
Wagi kompresowane do FP16
Auto-dobór urządzenia
CPU, iGPU, NPU — tryb AUTO

Pełne instrukcje konwersji i wizualizacji w zakładce Architektura.

Stan systemu
Ładowanie danych serwera…
Konwersja modelu do formatu IR

Uruchom poniższy skrypt po wytrenowaniu modelu Keras:

import openvino as ov
import tensorflow as tf

# 1. Wczytaj wytrenowany model Keras
model = tf.keras.models.load_model("www/public/bird_model.keras")

# 2. Konwertuj do formatu OpenVINO IR
ov_model = ov.convert_model(
    model,
    input=[1, 224, 224, 3]   # stały batch=1 przyspiesza inferencję
)

# 3. Zapisz jako .xml (topologia) + .bin (wagi)
ov.save_model(ov_model, "bird_model_ov/bird_model.xml")
Plik .xml = topologia sieci (graf operacji). Plik .bin = wagi modelu. Aplikacja automatycznie wykrywa IR i używa OpenVINO jeśli jest dostępne.
Wizualizacja sieci — Netron

Netron to przeglądarka modeli sieci neuronowych. Kliknięcie dowolnej warstwy pokazuje jej parametry: typ operacji, rozmiar kernela, stride, padding oraz kształty wejścia i wyjścia.

Pobierz plik XML
Topologia sieci (graf warstw)
bird_model.xml
Otwórz Netron
Aplikacja webowa — bez instalacji
netron.app
Załaduj plik
Przeciągnij bird_model.xml do okna Netron lub File → Open Model…
Co zobaczysz w Netron?
  • Pełny graf od wejścia do wyjścia
  • Bloki MBConv z EfficientNetB0
  • Warstwy splotowe (kernele 3×3, 5×5)
  • Połączenia residualne (skip connections)
  • Mechanizm Squeeze-and-Excitation (SE)
  • Głowa: Dense(512) → Dense(1486)
Dla wizualizacji wartości wag potrzebne są oba pliki: .xml i .bin. Sama topologia widoczna jest już przy samym pliku .xml.
Endpointy REST API
Metoda Endpoint Opis
GET / Strona główna (ta aplikacja)
POST /predict Klasyfikacja zdjęcia lub wideo — zwraca Top-5 gatunków
GET /health Status serwera — Nginx i monitoring
GET /backend Backend (OpenVINO / Keras), dostępne urządzenia
GET /model/info Statystyki modelu — warstwy, typy, kształty
GET /model/xml Pobierz topologię modelu XML (do Netron)
POST /translate Tłumaczenie łacińskich nazw na język potoczny (PL / EN)
POST /predict — klasyfikacja zdjęcia
curl -X POST http://localhost/predict \
     -F "file=@kos.jpg"

Odpowiedź JSON:

{
  "top": [
    { "gatunek": "Turdus merula",      "pewnosc": 87.32 },
    { "gatunek": "Turdus philomelos",  "pewnosc":  6.14 },
    { "gatunek": "Turdus viscivorus",  "pewnosc":  3.21 },
    { "gatunek": "Turdus iliacus",     "pewnosc":  1.88 },
    { "gatunek": "Turdus torquatus",   "pewnosc":  0.97 }
  ],
  "backend": "openvino"
}
POST /translate — tłumaczenie nazw
curl -X POST http://localhost/translate \
     -H "Content-Type: application/json" \
     -d '{"names": ["Turdus merula", "Parus major", "Aquila chrysaetos"]}'

Odpowiedź JSON:

{
  "Turdus merula":     "Kos",
  "Parus major":       "Sikora bogatka",
  "Aquila chrysaetos": "Orzeł Przedni"
}

Wyniki są cachowane lokalnie w common_names.json. Kolejne zapytania o te same gatunki są natychmiastowe.

Przykład w Pythonie
import requests

with open("kos.jpg", "rb") as f:
    resp = requests.post(
        "http://localhost/predict",
        files={"file": ("kos.jpg", f, "image/jpeg")}
    )

data = resp.json()
for i, wynik in enumerate(data["top"], 1):
    print(f"{i}. {wynik['gatunek']}: {wynik['pewnosc']:.1f}%")