Tilbake til tidslinjen
skole Våren 2026

En vision transformer som kjenner laksen sin

ML-delen av et fempersoners NTNU-prosjekt om overvåkning av invaderende pukkellaks i norske fjordsund. Undervannskameraer ser fisk passere gjennom et observasjonskammer på 1×2 meter, et lite CNN oppdager dem lokalt på en Raspberry Pi, og en DINOv2 vision transformer finjustert med LoRA klassifiserer art og estimerer lengde på serveren. Jeg delte maskinvareansvaret for kameraoppsettet og bygde klassifikatoren på serversiden.

Hvorfor pukkellaks

Norsk villaks er klassifisert som nær truet på den nasjonale rødlista. Den raskest voksende trusselen er pukkellaks, en invaderende stillehavsart som gyter tidligere og mer aggressivt, fortrenger villaks og sjøørret fra de beste gyteplassene, og deretter dør i store mengder (arten har en fast toårig livssyklus) og forurenser vassdraget med råtnende fisk. I 2025 pågikk bekjempelsestiltak i 63 norske elver.

Eksisterende fiskeovervåkningsteknologi er for det meste laget for bruk inni oppdrettsanlegg eller i feller ved elveutløp. Ingen følger med på det som kommer inn i fjordene før fisken beveger seg oppover. Det er det hullet prosjektet vårt prøver å fylle.

Håndtegnet ovenfra-skisse av et elveutløp: et grønt ledegjerde («Ledenett») vinkles ut fra land og leder fisken inn i et svart observasjonskammer. Fisketegninger viser ønsket svømmeretning; en blå pil merket «Svømmeretning» markerer den naturlige strømmen.
Konseptskisse. Et ledegjerde leder fisken gjennom observasjonskammeret på vei oppover.

Systemet, kort

  • Observasjonskammer. 2040×2040×1000 mm aluminiumsprofilramme med en hvit presenning som bakvegg, montert i strømmen.
  • Kameraer. 1× 8 MP IMX179 (detaljbilder; lakselusidentifikasjon) og 3× 2 MP IMX290 lavlys-kameraer (0,001 lux). Hvert i et forseglet akryl-domehus med linsen i domens geometriske senter for å minimere brytning.
  • Sensorer. Tre ESP32-noder på dybdene 0,5/1,0/1,5 m, hver med en DS18B20-temperatursensor og en Keyestudio TDS-probe (et kostnadseffektivt mål for saltholdighet). I²C-buss til en Raspberry Pi 4B.
  • Edge-compute. Raspberry Pi 4B håndterer fire parallelle USB-3-videostrømmer, kjører den lokale deteksjonsmodellen og laster opp via 4G.
Isometrisk CAD-rendering av kammeret: en aluminiumsprofilramme på rundt 2 × 1 × 2 meter, med nummererte merker for kameramonter, bakvegg av presenning, dybdesensorenes plassering og det øvre detaljkameraet.
CAD av kammeret. Aluminiumsprofilramme, hvit presenning som bakvegg, kameramonter på tre dybder.
Dataflytdiagram for systemet på norsk. Inngangene «Fisk» og «Vann» mater inn i nodene «Fanger video» og «Innhenter data» via kameraer og en temperatur/saltholdighetssensor. MPU-en sender data videre til en «Server» som utfører «Gjenkjenne lengde og art», før det går videre til en «Nettside» og en «Resultat»-node.
Dataflyt fra ende til ende. Kameraer og sensorer → edge-MPU → server → web-UI.

Den tostegs ML-pipelinen

Det interessante designvalget var å splitte deteksjon fra klassifisering:

  • Lokal CNN (YOLO) på Pi-en. En liten detektor følger med på videostrømmen i sanntid og produserer bounding boxes og en tracking-ID per fisk. Mesteparten av tiden ser den bare vann. Når den utløses, sendes bare de relevante framene over 4G, noe som sparer båndbredde og lagring, og holder pipelinen gående når mobilforbindelsen ryker.
  • ViT (DINOv2) på serveren. En mye tyngre transformer kjører på serveren, der datakraft er billig og modellen har råd til å være nøye. Den klassifiserer art (laks / pukkellaks / sjøørret / sjørøye / «ingen fisk») og estimerer lengde samtidig, i et multi-task-hode.

«Ingen fisk»-klassen filtrerer ut falske positive (greiner, bølger, skygger) som den lille lokale modellen slipper gjennom. Tracking-ID-er lar serveren samle flere framer av samme fisk gjennom passasjen og avgjøre i fellesskap, slik at den endelige klassifiseringen blir langt mer robust enn et enkelt frame.

En frame fra et undervannskamera inne i kammeret. En mørk, lakseformet fisk er nede til høyre, med en cyan YOLO-bounding-box rundt seg merket «fish». Streker langs kammerveggen fungerer som lengdereferanse.
Lokal YOLO-utgang. Den lille detektoren som kjører på Pi-en, tegner en boks rundt en fisk i kammeret.
Demo av hele pipelinen med et webkamera på pulten: en person går forbi mens hen holder papirutskrifter av to laks. Web-UI-et legger bounding boxes på hver utskrift, gir «FISK ID: 1» og «FISK ID: 2», og rapporterer estimerte lengder (13,7 cm og 39,0 cm) og artssikkerhet rundt 96–98 %.
Demo fra ende til ende. En testrigg med papirfisker; serveren returnerer ID-er, estimerte lengder og artssikkerhet.

LoRA-delen

DINOv2 er en sterk og generell ViT, men den har ikke sett pukkellaks i lavt lys gjennom en akryldome. Full finjustering ville oppdatert hundrevis av millioner parametere, og det er både dyrt og overkill med tanke på datasettstørrelsen vår.

LoRA (Low-Rank Adaptation) bygger på antagelsen om at endringene du faktisk trenger å gjøre under tilpasning, har lav rang. For hver fryste vektmatrise W ∈ ℝd×k setter du inn en trenbar lavrangs-oppdatering ΔW = B·A der A ∈ ℝr×k og B ∈ ℝd×r med r ≪ min(d, k). De originale vektene blir stående, det er bare adapterne som trenes.

I praksis ga dette oss en modell som håndterte domenet vårt godt, trent på timer i stedet for dager, og som ikke trengte enorme mengder annoterte data for å havne et brukbart sted.

Min andel av prosjektet

Team på fem. Fra rapportens arbeidsfordelingsdel var min del:

  • Maskinvare (delt): fysisk oppsett av kamerasystemet, sammenkobling av komponenter, strømdistribusjon.
  • Artsklassifikator: tilpasse og validere DINOv2 med LoRA for artsoppgaven, og integrere klassifikatoren med videopipelinen.

Lagkameratene hadde ansvar for henholdsvis sensorer, deteksjon og lengdeestimering, frontend og backend. Alle skrev rapport.

Rapport

Full norsk rapport: systemdesign, maskinvarestykkliste, ML-metode, validering, alt sammen.

Tilbake til tidslinjen