Forberedelse til Computer Vision-interview

Computer Vision Engineer Interviewspørgsmål

15 udvalgte computer vision interviewspørgsmål grupperet efter anciennitetsniveau. Brug dem til at gennemgå grundlæggende principper, praktiske afvejninger og ræsonnement på seniorniveau i produktion.

Start et Computer Vision AI-interviewIntet kreditkort kræves. 1 gratis session er tilgængelig.
Øv tekniske jobsamtaler på engelskEn tilstand, hvor ikke-modersmålstalende kan øve sig i at bestå tekniske interviews.

Junior-spørgsmål

1Hvad er en diskret 2D-konvolution på et billede, og hvordan relaterer det sig til kerner, filtre og krydskorrelation?

Diskret 2D-konvolution på et billede er en lineær, rumlig filtreringsoperation, hvor en matrix af vægte (en kerne) skydes henover inputbilledet. På hver rumlig placering beregnes et elementvis produkt mellem kernevægtene og det overlappende lokale billedudsnit (receptivt felt), og resultaterne summeres (ofte med en bias-term) for at producere en enkelt pixelværdi i output-feature map'et. I klassisk matematik og signalbehandling involverer ægte konvolution at vende (rotere 180 grader) kernen horisontalt og vertikalt, før det glidende indre produkt beregnes: $(I * K)(i, j) = \sum_m \sum_n I(i - m, j - n) K(m, n)$. I modsætning hertil beregner krydskorrelation det glidende prikprodukt direkte uden at vende kernen: $(I \star K)(i, j) = \sum_m \sum_n I(i + m, j + n) K(m, n)$. I deep learning-rammeværker som PyTorch og TensorFlow er den operation, der implementeres under navnet "konvolution", faktisk krydskorrelation. Fordi kernevægtene er trænbare parametre, der optimeres direkte via backpropagation, lærer netværket simpelthen de passende orienterede vægte, hvilket gør det matematiske kerneflip beregningsmæssigt redundant under både træning og inferens.

import numpy as np
from scipy.signal import convolve2d, correlate2d

image = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]], dtype=float)

# Asymmetric directional kernel
kernel = np.array([[1, 0],
                   [0, -1]], dtype=float)

# Convolve flips kernel by 180 degrees: kernel[::-1, ::-1]
conv_res = convolve2d(image, kernel, mode='valid')
corr_res = correlate2d(image, kernel, mode='valid')

print("Convolve output:\n", conv_res)
print("Correlate output:\n", corr_res)
Prøv at besvare dette spørgsmål med en AI-coach

2Hvornår ville du bruge RGB, HSV, Lab, YCbCr eller gråskala-repræsentationer i en vision-pipeline?

Forskellige farverum afkobler specifikke fysiske, perceptuelle og statistiske egenskaber ved visuelle data, hvilket gør dem velegnede til specifikke vision-opgaver: 1. **RGB / BGR**: Standardformat for kamerasensorer og skærmhardware, der repræsenterer additive grundfarver (rød, grøn, blå). Farvekanaler er stærkt korrelerede med luminans (lysændringer påvirker alle tre kanaler samtidigt). Det er standardinput for dybe neurale netværk (CNN'er, Vision Transformers). Et stort produktionsproblem er RGB- vs. BGR-kanalombytning (f.eks. indlæser OpenCV BGR, mens PIL/PyTorch forventer RGB), hvilket stille og roligt skader modellens nøjagtighed. 2. **HSV / HSL**: Afkobler eksplicit kromaticitet (Hue = farvetone, Saturation = farvemætning) fra intensitet (Value/Lightness). Det er ideelt til klassisk farvetærskling (color thresholding), objektsporing via farve og farvesegmentering under varierende belysning, fordi Hue er relativt invariant over for skygger og lysstyrkeændringer. 3. **CIE Lab**: Et perceptuelt ensartet farverum, hvor den Euklidiske afstand mellem to punkter ($\Delta E$) direkte afspejler menneskelig perceptuel forskel. Det adskiller lyshed ($L^*$) fra modfarveakser ($a^*$ grøn-rød, $b^*$ blå-gul). Det bruges til inspektion af farveforskelle, farvekorrektion, vurdering af billedkvalitet og farvelægningsopgaver. 4. **YCbCr**: Adskiller luminans ($Y$) fra blå-forskel ($Cb$) og rød-forskel ($Cr$) kroma-komponenter. Det er rygraden i video- og billedkompressionsstandarder (JPEG, MPEG, H.264/H.265), fordi det menneskelige visuelle system er mindre følsomt over for kromadetaljer, hvilket muliggør kroma-subsampling (f.eks. 4:2:0) for at reducere båndbredde og beregningskrav. 5. **Gråskala (Grayscale)**: Enkeltkanals intensitetsrepræsentation ($Y \approx 0.299R + 0.587G + 0.114B$). Det er ideelt til geometri- og teksturbaserede opgaver, hvor farve er irrelevant (f.eks. optisk flow, SLAM, klassisk feature-ekstraktion som SIFT/ORB, kantdetektion) for at spare 66% hukommelse og beregningskraft. Det bør dog ikke bruges, når farve er et afgørende diskriminerende signal (f.eks. klassificering af trafiklysstatus).

import cv2
import numpy as np

# Sample image: saturated red under normal and shaded lighting
img_bgr = np.zeros((100, 100, 3), dtype=np.uint8)
img_bgr[:, :50] = [0, 0, 255]    # Bright Red in BGR
img_bgr[:, 50:] = [0, 0, 120]    # Shaded/Dark Red in BGR

# Convert to HSV (OpenCV H: 0-179, S: 0-255, V: 0-255)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

# Red Hue wraps around 0/180; track red with single Hue range [0, 10] & high saturation
lower_red = np.array([0, 100, 50])
upper_red = np.array([10, 255, 255])
mask_hsv = cv2.inRange(img_hsv, lower_red, upper_red)

print("HSV segmented pixels:", np.count_nonzero(mask_hsv), "out of", mask_hsv.size)
Prøv at besvare dette spørgsmål med en AI-coach

3Hvorfor er kanal-baseret billednormalisering, per-billede normalisering og konsistent pixelskalering vigtige i synssystemer?

Billednormalisering er afgørende i vision-pipelines for at opretholde numerisk stabilitet, accelerere konvergens af gradient descent og forhindre forskydning i trænings- og serving-distribution: 1. **Pixelskalering ([0, 1] eller [-1, 1])**: Rå billedpixels gemmes som usignerede 8-bit heltal (`uint8` $\in [0, 255]$). At føde rå $[0, 255]$ værdier ind i neurale netværk forårsager ekstremt store tidlige aktiveringer og gradient-eksplosion eller -mætning. Skalering til $[0.0, 1.0]$ (ved at dividere med 255.0) eller $[-1.0, 1.0]$ centrerer input omkring nul, hvilket stemmer overens med standard vægtinitialiseringsmetoder (He, Xavier). 2. **Dataset-niveau Kanalnormalisering (Middel-Standardafvigelsesstandardisering)**: Standardiserer input via $x_{norm} = \frac{x - \mu_c}{\sigma_c}$ ved hjælp af forudberegnede globale statistikker per kanal (f.eks. ImageNet middel `[0.485, 0.456, 0.406]` og standardafvigelse `[0.229, 0.224, 0.225]`). Dette centrerer hver kanal omkring nul middelværdi med enhedsvarians på tværs af datasættet, hvilket sikrer balanceret gradientflow på tværs af kanaler. En kritisk operationel fejl er **trænings-serving skævhed**: hvis inferens udelader division med 255, bruger uoverensstemmende middel-/standardafvigelseskonstanter eller anvender dem i forkert kanalrækkefølge (RGB vs BGR), falder modellens ydeevne drastisk. 3. **Per-billede Normalisering (Instance Normalization / Min-Max / Z-score)**: Beregner middelværdi og standardafvigelse for hvert enkelt billede: $x_{norm} = \frac{x - \mu_{img}}{\sigma_{img}}$. Dette fjerner globale kontrast- og belysningsvariationer på tværs af forskellige optagelsesforhold. Selvom det er effektivt i stiloverførsel, MRI/CT medicinsk billeddannelse eller satellitbilleder, kan det være skadeligt, når absolut pixelintensitet har fysisk betydning (f.eks. dag- vs natklassifikation, materialereflektans eller defektdetektering under kalibreret belysning).

import torch
import torchvision.transforms as T
from PIL import Image
import numpy as np

# Create a mock uint8 RGB image
raw_img = Image.fromarray(np.random.randint(0, 256, (224, 224, 3), dtype=np.uint8))

# Standard transform pipeline:
# 1. ToTensor scales uint8 [0, 255] -> float32 [0.0, 1.0] and permutes HWC -> CHW
# 2. Normalize standardizes per-channel using dataset mean and std
preprocess = T.Compose([
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

tensor_img = preprocess(raw_img)
print("Tensor shape:", tensor_img.shape)
print("Tensor dtype:", tensor_img.dtype)
print("Channel 0 min/max:", round(tensor_img[0].min().item(), 2), round(tensor_img[0].max().item(), 2))
Prøv at besvare dette spørgsmål med en AI-coach

4Hvordan fremmer geometriske og fotometriske augmentationer invarians, og hvordan afgør man, om en augmentation bevarer etiketter?

Geometriske augmentationer (såsom rotation, translation, skalering og spejling) ændrer den rumlige koordinatmapping af pixels, mens fotometriske augmentationer (såsom lysstyrke, kontrast, hue jitter og sløring) ændrer pixelintensitet og farvekanaler uden at modificere rumlige koordinater. Inden for klassifikation udsætter begge kategorier modellen for realistiske variationer, hvilket opmuntrer den til at lære invariante repræsentationer, hvor forudsigelser forbliver stabile på trods af ændringer i positur, synspunkt eller lysforhold. I rumlige forudsigelsesopgaver (detektion og segmentering) kræver geometriske transformationer matchende transformationer til ground-truth-bokse eller masker for at bevare ækvarians. Beslutningen om, hvorvidt en augmentation bevarer etiketter, kræver evaluering af domænesemantik og fysisk forhåndsviden. En transformation er etiketbevarende, hvis det resulterende billede forbliver en sandsynlig instans af den originale målgruppe uden at ændre dens semantiske identitet. For eksempel bevarer horisontal spejling identitet for generelle objekter (som biler eller dyr), men ændrer identitet eller ugyldiggør tegn i optisk tegngenkendelse (OCR) og cifferklassifikation. Tilsvarende er fuld 360-graders rotation gyldig i histologi eller satellitbilleder, hvor ingen kanonisk orientering eksisterer, men unaturlig i autonom kørsel, hvor objekter på hovedet krænker virkelige fysiske begrænsninger.

import albumentations as A

# Natural scene classification / object detection: horizontal flip is valid
natural_scene_transform = A.Compose([
    A.HorizontalFlip(p=0.5),
    A.RandomBrightnessContrast(p=0.2),
], bbox_params=A.BboxParams(format='pascal_voc', label_fields=['category_ids']))

# OCR / Digit classification: horizontal flip corrupts semantics
ocr_transform = A.Compose([
    A.Affine(scale=(0.9, 1.1), rotate=(-10, 10), p=0.5),
    A.ColorJitter(brightness=0.2, contrast=0.2, p=0.5),
])
Prøv at besvare dette spørgsmål med en AI-coach

5Hvad er nearest-neighbor, bilinear, bicubic og area-interpolering, og hvordan kan skalering introducere aliasing eller sløring?

Interpolationsmetoder estimerer pixelintensiteter ved kontinuerlige koordinater, når der resampling foretages til et nyt diskret gitter: - **Nearest-Neighbor:** Tildeler intensiteten fra den nærmeste diskrete pixel. Det er beregningsmæssigt $O(1)$ og bevarer nøjagtige originale værdier, men skaber blokkede artefakter ved opskalering og kraftige takkede kanter ved nedskalering. - **Bilinear Interpolation:** Beregner et afstands-vægtet gennemsnit af de $2 \times 2$ (4 nærmeste) nabopixels ved hjælp af lineær interpolation langs begge akser, hvilket giver jævne overgange med moderat sløring. - **Bicubic Interpolation:** Sampler et $4 \times 4$ (16 nærmeste) nabolag ved hjælp af kubiske polynomielle kerner. Det fanger lokale intensitetsgradienter og producerer skarpere kanter og jævnere kurver end bilinear, men kan give overshoot/ringing-artefakter omkring skarpe overgange. - **Area (Box) Interpolation:** Beregner det fraktionerede områdeoverlap af målpixels projiceret på kildepixels og gennemsnitliggør de underliggende kildeintensiteter. Det er især effektivt til nedskalering uden moiré. **Aliasing kontra sløringsmekanismer:** - **Aliasing** opstår under nedskalering, når højfrekvent indhold overstiger Nyquist-frekvensen ($f_s / 2$) af den nye samplingrate uden tilstrækkelig lavpasfiltrering. Højfrekvenser folder tilbage i lavere frekvensbånd, hvilket producerer falske mønstre, moiré og takkede kanter. - **Sløring (Blur)** opstår, når interpolationskerner fungerer som lavpas-udjævningsfiltre, der dæmper legitime højfrekvenser (f.eks. bilinear udjævning), eller når højfrekvente detaljer udjævnes under nedskalering.

import cv2

# Severe downsampling: area downsampling prevents aliasing
img = cv2.imread('high_res_pattern.jpg')
downscaled_area = cv2.resize(img, (400, 300), interpolation=cv2.INTER_AREA)
downscaled_nn = cv2.resize(img, (400, 300), interpolation=cv2.INTER_NEAREST)  # heavy aliasing/moiré

# Upscaling: bicubic preserves edge sharpness
upscaled_cubic = cv2.resize(downscaled_area, (400, 400), interpolation=cv2.INTER_CUBIC)
upscaled_linear = cv2.resize(downscaled_area, (400, 400), interpolation=cv2.INTER_LINEAR)
Prøv at besvare dette spørgsmål med en AI-coach

6Hvilke visuelle fejltyper fra den virkelige verden bør et synssystem evalueres ud fra, og hvordan ændrer de inputfordelingen?

Visuelle fejltyper fra den virkelige verden falder i flere brede kategorier: miljøforhold (svagt lys, direkte genskin, regn, sne, tåge), sensor- og optiske effekter (bevægelsessløring, defokuseringssløring, høj ISO-sensorstøj, rolling shutter-skævhed), kompressions- og transmissionsnedbrydning (JPEG-blokdannelse, videobitrate-begrænsning, nedskalering) og semantiske/rumlige forskydninger (delvis okklusion, trunkering, objektpositioner uden for fordelingen). Disse fejltyper forskubber inputfordelingen væk fra nominelle træningsdomæner på flere niveauer. På pixel-niveau ændrer de luminans- og krominanshistogrammer, ødelægger lokal kontrast, reducerer signal-støj-forholdet (SNR) og introducerer kunstige højfrekvente artefakter eller sløringskerneler. På strukturelt og semantisk niveau svækker de kantgradienter, tilslører centrale visuelle træk, forvrænger silhuetter og skjuler kritiske diagnostiske regioner. Når modeller trænet på rene data møder disse forskudte inputs, aktiveres lavniveaus konvolutionelle eller attention feature extractors ikke korrekt, hvilket fører til manglende detektioner, hallicinerende falske positiver på støjbilleder og overkonfidente fejl.

Category              | Physical Mechanism             | Input Shift & Feature Impact
-----------------------------------------------------------------------------------------
Low Light / Noise     | Low photon flux, high sensor gain | Drops SNR, suppresses gradient edges, fires spurious texture filters
Motion / Defocus Blur | Scene/camera motion, out-of-focus| Attenuates high spatial frequencies, smears object boundaries
Adverse Weather/Glare | Fog/rain scattering, lens flare  | Compresses dynamic range, lowers contrast, masks semantic regions
Occlusion / Cutoff    | Physical foreground obstructions | Masks critical keypoints/parts, breaks holistic spatial priors
Compression Artifacts | Block DCT quantization, subsampling| Introduces 8x8 grid boundaries, removes fine textural details
Prøv at besvare dette spørgsmål med en AI-coach

7Hvordan repræsenterer klassiske deskriptorer som HOG billedstruktur, og hvilke begrænsninger har de sammenlignet med indlærte CNN (Convolutional Neural Network)-features?

Histogram of Oriented Gradients (HOG) er en klassisk, håndlavet feature-deskriptor designet til at fange lokal objektform og -udseende gennem fordelingen af intensitetsgradientorienteringer. HOG-beregningspipeline involverer: (1) beregning af horisontale og vertikale billedgradienter (f.eks. med 1D derivationsfiltre [-1, 0, 1]) for at opnå gradientstørrelse og -orientering; (2) opdeling af billedet i små rumlige regioner kaldet 'celler' (såsom 8x8 pixels) og akkumulering af 1D histogrammer af gradientorienteringer vægtet efter gradientstørrelse; (3) gruppering af tilstødende celler i større overlappende 'blokke' (såsom 2x2 celler) og normalisering af blok-feature-vektorer (ved hjælp af L2-norm eller L1-sqrt) for at opnå robusthed over for lokale belysnings-, kontrast- og skyggevariationer; og (4) konkatenering af normaliserede blokvektorer til en endelig 1D feature-repræsentation, historisk parret med lineære SVM'er til fodgænger- og objektdetektion. Sammenlignet med indlærte Convolutional Neural Network (CNN)-features har HOG store begrænsninger: For det første er HOG-features faste og håndlavede, og de fanger kun lavniveau lokale kantorienteringsstatistikker uden evnen til at lære opgavespecifikke hierarkiske repræsentationer (såsom teksturer, objektdelene og semantiske koncepter). For det andet giver HOG meget begrænset geometrisk invarians: mens bloknormalisering håndterer monotone belysningsændringer og små rumlige forskydninger inden for celler, er HOG sårbar over for 3D rotationer ud af planen, betydelige skalavariationer, ikke-stive positionelle artikulationer og kraftig baggrundsforstyrrelse. I modsætning hertil lærer CNN'er flerlags ikke-lineære abstraktioner optimeret end-to-end for målet.

Input Image Patch (e.g., 64x128)
  │
  ▼
[ 1. Compute Gradients ] ──> Gx, Gy -> Mag = sqrt(Gx^2 + Gy^2), Angle = atan2(Gy, Gx)
  │
  ▼
[ 2. Cell Histograms   ] ──> 8x8 pixel cells accumulate 9-bin orientation histograms (0°-180°)
  │
  ▼
[ 3. Block Normalization] ──> Overlapping 2x2 cell blocks normalized (e.g., v / sqrt(||v||_2^2 + eps^2))
  │
  ▼
[ 4. Feature Vector    ] ──> Concatenate block vectors -> Feed to Linear SVM / Classifier
Prøv at besvare dette spørgsmål med en AI-coach

Middle-spørgsmål

8Hvordan bestemmer stride, padding, dilation og kernelstørrelse konvolutionens outputstørrelse og receptive felt?

De rumlige output-dimensioner af et konvolutionelt lag og dets kumulative receptive felt bestemmes af kernelstørrelse $k$, stride $s$, padding $p$ og dilation $d$: 1. **Outputets rumlige størrelse**: Dilation introducerer $(d - 1)$ mellemrum mellem kerneelementer, hvilket giver en effektiv kernelstørrelse på $k' = d(k - 1) + 1$. Output-dimensionen langs en akse er givet ved: $$O = \left\lfloor \frac{I + 2p - k'}{s} \right\rfloor + 1 = \left\lfloor \frac{I + 2p - d(k - 1) - 1}{s} \right\rfloor + 1$$ Her nedprøver stride (eller reducerer opløsningen) ved at flytte kernen $s$ pixel per trin, padding tilføjer virtuelle kantpixel for at bevare eller justere rumlige dimensioner, og dilation udvider filterets aftryk uden at tilføje ekstra parametre. 2. **Receptive Felt (RF)**: Det teoretiske receptive felt beskriver den rumlige udstrækning i inputbilledet, der påvirker en bestemt aktivering. På tværs af stablede lag opdateres det receptive felt $RF_l$ og den kumulative stride (jump $j_l$) rekursivt: * Jump: $j_l = j_{l-1} \cdot s_l$, med $j_0 = 1$ * Receptive Felt: $RF_l = RF_{l-1} + (k'_l - 1) \cdot j_{l-1}$, med $RF_0 = 1$ Strides og pooling udvider det receptive felt multiplikativt på tværs af dybde, fordi efterfølgende lags kernel-trin svarer til større pixel-spring i den oprindelige input-koordinatrum. Dilation udvider det receptive felt additivt inden for et enkelt lag ved at øge $k'_l$ uden rumlig nedprøvning.

def compute_conv_output_and_rf(layers, input_size=224):
    current_size = input_size
    rf = 1
    jump = 1
    
    for idx, layer in enumerate(layers, 1):
        k, s, p, d = layer['k'], layer['s'], layer['p'], layer['d']
        k_eff = d * (k - 1) + 1
        current_size = ((current_size + 2 * p - k_eff) // s) + 1
        rf = rf + (k_eff - 1) * jump
        jump = jump * s
        print(f"Layer {idx}: Out={current_size}x{current_size}, RF={rf}x{rf}, Jump={jump}")

layers = [
    {'k': 3, 's': 1, 'p': 1, 'd': 1},  # Conv1: 3x3 standard
    {'k': 3, 's': 2, 'p': 1, 'd': 1},  # Conv2: 3x3 strided
    {'k': 3, 's': 1, 'p': 2, 'd': 2},  # Conv3: 3x3 dilated (d=2)
]
compute_conv_output_and_rf(layers, 224)
Prøv at besvare dette spørgsmål med en AI-coach

9Hvordan svarer en konvolutionskerne til et klassisk lineært billedfilter, og hvornår kan et 2D filter gøres separabelt?

I klassisk lineær signal- og billedbehandling repræsenterer en konvolutionskerne den rumlige impulsrespons (punktspredningsfunktion) for et Lineært Skift-Invariant (LSI) system. Anvendelsen af kernen er en lineær filtreringsoperation i det rumlige domæne, der former billedets frekvensrespons (dets 2D Fouriertransformation). Lavpasfiltre (f.eks. Gaussian, box blur) dæmper høje rumlige frekvenser for at undertrykke støj og udglatte teksturer, mens højpas- eller båndpasfiltre (f.eks. Sobel, Laplacian, Prewitt) forstærker høje frekvenser for at detektere kanter og gradienter. Et 2D filterkerne $K \in \mathbb{R}^{M \times N}$ er rumligt separabelt, hvis det kan dekomponeres til yderproduktet af to 1D filtre: $K = u \cdot v^T$, hvor $u \in \mathbb{R}^{M \times 1}$ og $v \in \mathbb{R}^{N \times 1}$. I lineær algebra-termer er en 2D matrix separabel, hvis og kun hvis dens matrixrang er 1. Dette kan verificeres via Singularværdidekomponering (SVD), hvor præcis én singulær værdi er ikke-nul ($ \sigma_1 > 0, \sigma_2 = \dots = 0$). Separabilitet reducerer den beregningsmæssige kompleksitet betydeligt. Anvendelse af en ikke-separabel $K \times K$ kerne på et $H \times W$ billede kræver $O(H \cdot W \cdot K^2)$ multiplikationer og additioner. Når den dekomponeres i to på hinanden følgende 1D passager (horisontal og derefter vertikal), falder kompleksiteten til $O(H \cdot W \cdot 2K)$. For en $15 \times 15$ kerne giver dette omtrent en 7.5x hastighedsforøgelse.

import numpy as np

# Gaussian kernel is rank-1 (separable)
gaussian_1d = np.array([1, 2, 1], dtype=float)[:, None]
gaussian_2d = gaussian_1d @ gaussian_1d.T
gaussian_2d /= gaussian_2d.sum()

# Sobel-X kernel is rank-1 (separable)
sobel_x = np.array([[-1, 0, 1],
                    [-2, 0, 2],
                    [-1, 0, 1]], dtype=float)

# Diagonal kernel is rank-2 (non-separable)
non_sep = np.array([[1, 0],
                    [0, 1]], dtype=float)

print("Gaussian rank:", np.linalg.matrix_rank(gaussian_2d))
print("Sobel-X rank:", np.linalg.matrix_rank(sobel_x))
print("Diagonal rank:", np.linalg.matrix_rank(non_sep))

# SVD decomposition for Sobel-X
U, S, Vt = np.linalg.svd(sobel_x)
print("Sobel-X singular values:", np.round(S, 4))
Prøv at besvare dette spørgsmål med en AI-coach

10Hvordan ændrer ændring af størrelse, centerbeskæring, `Random-Resized Cropping` (tilfældig størrelsesændret beskæring), strækning og `letterboxing` inputdatafordelingen?

Forskellige strategier for ændring af størrelse og beskæring ændrer inputdatafordelingen på tværs af geometri, skala, indholdsdækning og rumlige grænser: 1. **Direkte ændring af størrelse (strækning/sammentrykning):** Skalerer billedet ikke-isotropisk til en måldimension $(H, W)$, hvilket forvrænger de originale billedformater. Dette tvinger modellen til at behandle deformerede objektformer (f.eks. bliver cirkulære objekter aflange ellipser). 2. **Centerbeskæring:** Uddrager en central beskæring af fast størrelse eller forhold. Den bevarer det oprindelige billedformat og den lokale skala, men introducerer en stærk central bias (forudsat at målobjekter er centralt indrammet) og kasserer perifert indhold eller skærer objekter ved kanten af. 3. **`Random-Resized Cropping` (RRC):** Uddrager tilfældige delregioner på tværs af varierende arealstørrelser og billedformater, hvorefter de ændres til en fast dimension. Dette udvider træningsskalafordelingen og fremmer delfokuseret feature-læring, men ekstreme beskæringer kan udelukke målobjektet fuldstændigt. 4. **`Letterboxing` (isotropisk størrelsesændring med udfyldning):** Skalerer billedet ensartet, indtil dets længste dimension passer til målstørrelsen, og udfylder derefter de resterende kanter med en konstant værdi. Den opretholder ægte objektdimensioner og billedformater, men introducerer kunstige højkonstrastkanter og uinformative udfyldte pixels.

import cv2
import numpy as np

def letterbox_image(image, target_size=(640, 640), pad_color=(114, 114, 114)):
    h, w = image.shape[:2]
    target_w, target_h = target_size
    scale = min(target_w / w, target_h / h)
    new_w, new_h = int(w * scale), int(h * scale)
    
    resized = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    canvas = np.full((target_h, target_w, 3), pad_color, dtype=np.uint8)
    
    top = (target_h - new_h) // 2
    left = (target_w - new_w) // 2
    canvas[top:top+new_h, left:left+new_w] = resized
    return canvas, scale, (left, top)
Prøv at besvare dette spørgsmål med en AI-coach

11Hvilke former for annoteringsstøj forekommer i computer vision-datasæt, og hvordan ville du detektere eller afhjælpe dem?

Computer vision-datasæt udviser almindeligvis fire primære former for annoteringsstøj: 1. **Kategorisk labelstøj:** Et billede eller objekt tildeles den forkerte klasselabel (f.eks. fejlkategorisering af en kat som en hund, eller forveksling af subtile finkornede klasser). 2. **Manglende annoteringer (udladelsesstøj):** Gyldige forgrundsobjekter forbliver uannoterede. Inden for objektdetektering behandles udeladte mål som negative baggrunde, hvilket direkte straffer korrekte modeldetekteringer under træning. 3. **Bounding-Box / Keypoint Jitter (lokaliseringsstøj):** Unøjagtige, løse eller forskudte `bounding box`-koordinater og landmark-lokationer forårsaget af menneskelig annotator-inkonsistens. 4. **Maskegrænseambiguitet:** Inkonsistente eller grove segmenteringskonturer langs komplekse eller slørede grænser (f.eks. hår, semi-transparente overflader, bevægelsesslør). **Detektions- og afhjælpningsstrategier:** - **Loss Outlier Tracking & Confident Learning:** Sporing af sample-loss på tværs af træningsepoker identificerer vedvarende `high-loss outliers`, som ofte indikerer fejllabelerede eller udeladte instanser. Algoritmer som Confident Learning estimerer støjfordelinger for at fjerne eller korrigere fejl. - **Out-of-Fold (OOF) Prediction Discrepancies:** Træning af `cross-validation`-modeller og sammenligning af `holdout`-forudsigelser mod grundsandhed fremhæver fejllabelerede billeder og manglende `bounding boxes`. - **Inter-Annotator Agreement (IAA) og konsensusgennemgang:** Måling af metrikker som Cohens Kappa (klassifikation) eller gennemsnitlig Intersection-over-Union (IoU) (lokalisering) på tværs af flere annotatorer markerer prøver med lav enighed for konsensusgennemgang. - **Robuste loss-formuleringer:** Brug af `label smoothing`, støjtolerante klassifikations-loss-funktioner eller robuste IoU-baserede regressions-loss-funktioner reducerer følsomhed over for `jitter` og fejllabelering.

import torch
import torch.nn.functional as F

def find_label_noise_candidates(model, dataloader, device, top_k=50):
    model.eval()
    sample_losses = []
    
    with torch.no_grad():
        for batch_idx, (images, targets, sample_ids) in enumerate(dataloader):
            images, targets = images.to(device), targets.to(device)
            logits = model(images)
            loss_per_sample = F.cross_entropy(logits, targets, reduction='none')
            
            for sid, l, target, pred in zip(sample_ids, loss_per_sample.cpu(), targets.cpu(), logits.argmax(dim=-1).cpu()):
                sample_losses.append({'id': sid, 'loss': l.item(), 'target': target.item(), 'pred': pred.item()})
                
    sample_losses.sort(key=lambda x: x['loss'], reverse=True)
    return sample_losses[:top_k]
Prøv at besvare dette spørgsmål med en AI-coach

12Hvordan påvirker klasseubalance træning af billedklassifikation, detektion og tæt prædiktion?

Klasseubalance påvirker optimeringsdynamik og tabsfunkionslandskaber på tværs af synsopgaver: 1. **Billedklassifikation:** Når flertalsklasser er i overtal i forhold til mindretalsklasser, medfører empirisk risikominimering, at parameteropdateringer domineres af gradienter fra flertalsklasser. Modellen lærer den empiriske klasseprior $P(Y)$ og fordrejer sin beslutningsgrænse mod sjældne klasser. Dette giver en høj samlet top-1 nøjagtighed, men lider af et alvorligt sammenbrud i mindretals recall. 2. **Objektdetektion:** - *For-/baggrundsubalance:* I tætte et-trins- og ankerbaserede detektorer evalueres hundredtusindvis af kandidatplaceringer pr. billede, hvor >99% er baggrund. Selvom individuelle lette baggrundsankre giver små tab, overskygger deres store aggregerede gradient de informative gradientsignaler fra spredte forgrundsobjekter. - *Forgrundsklasseubalance:* Almindelige objektkategorier forekommer størrelsesordener hyppigere end sjældne kategorier, hvilket reducerer den effektive stikprøvestørrelse og læringssignal for sjældne klasser. 3. **Tæt Prædiktion (Segmentering):** Pixelniveau-ubalance er alvorlig, fordi store baggrunds- og 'stuff'-klasser (f.eks. vej, himmel) optager millioner af pixels, mens små 'thing'-klasser (f.eks. trafikskilte, fodgængere) kan optage færre end 0,1% af billedpixels. Standard pixel-per-pixel krydsentropitab domineres af klasser med stort areal, hvilket fører til undersegmentering eller fuldstændig forsvinden af små, tynde strukturer.

# Illustrating cumulative gradient dominance by background anchors
import torch

num_bg_anchors = 100_000
num_fg_anchors = 10

bg_loss_per_sample = torch.tensor(0.001, requires_grad=True)
fg_loss_per_sample = torch.tensor(1.5, requires_grad=True)

total_loss = (num_bg_anchors * bg_loss_per_sample) + (num_fg_anchors * fg_loss_per_sample)
total_loss.backward()

print(f'Total BG gradient contribution: {num_bg_anchors * bg_loss_per_sample.grad.item():.1f}')
print(f'Total FG gradient contribution: {num_fg_anchors * fg_loss_per_sample.grad.item():.1f}')
Prøv at besvare dette spørgsmål med en AI-coach

Senior-spørgsmål

13Hvordan ville du fejlfinde NaN-værdier (ikke-et-tal-værdier) eller ustabilt tab under storstilet distribueret visionstræning?

Fejlfinding af NaN-værdier eller ustabilt tab i storstilet distribueret visionstræning med Distributed Data Parallel (DDP) kræver isolering af, om rodårsagen stammer fra dårlige inputdata, numerisk overløb/underløb i blandet præcision (Automatic Mixed Precision - AMP) eller optimeringsustabiliteter på tværs af workers. For det første skal determinisme og sikkerhedshooks etableres: aktiver anomalidetektion (`torch.autograd.set_detect_anomaly(True)`), registrer gradient-/aktiveringshooks for at fange det præcise lag, hvor NaN-værdier dukker op, og tilføj streng datavalidering i DataLoader (sikring af endelige værdier, kontrol af 0-byte korrupte billeder, tomme bounding boxes eller normaliseringsdivisorer med nul varians). Logning på minibatch-niveau bør spore tab pr. rank, input-URI'er, gradientnorm før klipning og GradScaler-skalafaktorer. For det andet skal Automatic Mixed Precision (AMP) og dynamisk tabsskalering inspiceres: I FP16 (Floating Point 16) kan store gradienter let overløbe (`> 65504`), hvilket får tabsskaleren til at springe trin over og gentagne gange halvere sin skalafaktor, indtil skalaen når nul; at skifte ustabile operationer (f.eks. softmax, LayerNorm, focal loss-eksponenter eller bounding box IoU-nævnere) til FP32 (Floating Point 32) eller anvende BF16 (Bfloat16), som matcher FP32's dynamiske område, stabiliserer typisk træningen. Endelig skal DDP-specifikke faldgruber kontrolleres, såsom all-reduce-operationer, der propagerer NaN-værdier fra en enkelt worker til alle ranks, opskalering af learning rate warmup (f.eks. lineær skaleringsregel med store globale batchstørrelser) og gradientklipning.

import torch
from torch.cuda.amp import autocast, GradScaler

scaler = GradScaler()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)

for step, (images, targets, uris) in enumerate(dataloader):
    # 1. Input sanitization
    if not torch.isfinite(images).all():
        print(f"Corrupt input detected from URIs: {uris}")
        continue
        
    optimizer.zero_grad(set_to_none=True)
    
    with autocast(dtype=torch.float16):
        outputs = model(images)
        loss = criterion(outputs, targets)
    
    if not torch.isfinite(loss):
        print(f"NaN/Inf loss at step {step} on rank {torch.distributed.get_rank()}; skipping step.")
        continue
        
    scaler.scale(loss).backward()
    
    # Unscale before clipping to inspect true gradient norms
    scaler.unscale_(optimizer)
    grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    
    if torch.isnan(grad_norm) or torch.isinf(grad_norm):
        print(f"Warning: Grad norm is {grad_norm}. Scaler will adjust.")
        
    scaler.step(optimizer)
    scaler.update()
Prøv at besvare dette spørgsmål med en AI-coach

14Hvordan ville du designe en online digital videostabiliseringskomponent til et kamera med billedrystelser?

At designe en online digital videostabiliseringspipeline til realtids kamerarystelser involverer fire primære trin: bevægelsesestimering, bevægelsesudjævning, bevægelseskompensation (warping) og grænsehåndtering. 1. **Mellem-billed bevægelsesestimering:** Udtræk 2D sparse nøglepunkter på tværs af på hinanden følgende billeder ved hjælp af hurtige feature-detektorer (f.eks. ORB, FAST eller Shi-Tomasi hjørner) og beregn korrespondancer ved hjælp af Lucas-Kanade optisk flow eller feature descriptor matching. Estimer en geometrisk transformation mellem billeder (såsom en Affine- eller homografi-model) ved hjælp af RANSAC for at afvise outlier-matches forårsaget af uafhængigt bevægelige forgrundsobjekter. 2. **Akkumulering af bevægelsesbane og online udjævning:** Integrer transformationer fra billede til billede over tid for at opretholde den kumulative kamerapath $P_t = P_{t-1} \cdot H_t$. Anvend et online udjævningsfilter – såsom et 1D/2D Kalman-filter eller et kausalt bevægende gennemsnit med kort vindue – for at adskille højfrekvent utilsigtet rystelse fra lavfrekvent intentionel kamerapanorering. 3. **Kompensation og billedwarping:** Beregn korrektionstransformationen $C_t = S_t \cdot P_t^{-1}$ (hvor $S_t$ er den udjævnede path) og warp det nuværende billede ved hjælp af bilinær/bikubisk interpolation. 4. **Grænsehåndtering og latenstidskrav:** Warping introducerer manglende kantpixler / sorte kanter; løs dette ved at anvende en fast dynamisk beskæringsfaktor (f.eks. 5-10% zoom ind) med grænseekstrapolation eller adaptiv skala. I et online miljø skal der opretholdes minimal buffering (1-3 lookahead-billeder) for at begrænse behandlingslatenstiden.

import cv2
import numpy as np

class OnlineStabilizer:
    def __init__(self, crop_ratio=0.9):
        self.prev_gray = None
        self.smoothed_x = 0.0
        self.smoothed_y = 0.0
        self.smoothed_a = 0.0
        self.alpha = 0.85  # Low-pass filter smoothing coefficient
        self.crop_ratio = crop_ratio

    def process_frame(self, frame):
        curr_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        h, w = curr_gray.shape
        
        if self.prev_gray is None:
            self.prev_gray = curr_gray
            return frame
            
        # 1. Feature detection & tracking
        p0 = cv2.goodFeaturesToTrack(self.prev_gray, maxCorners=200, qualityLevel=0.01, minDistance=30)
        p1, status, _ = cv2.calcOpticalFlowPyrLK(self.prev_gray, curr_gray, p0, None)
        
        good_p0 = p0[status == 1]
        good_p1 = p1[status == 1]
        
        # 2. Estimate rigid motion (dx, dy, da) with RANSAC
        T, inliers = cv2.estimateAffinePartial2D(good_p0, good_p1, method=cv2.RANSAC)
        if T is None: 
            return frame
            
        dx = T[0, 2]
        dy = T[1, 2]
        da = np.arctan2(T[1, 0], T[0, 0])
        
        # 3. Online low-pass filtering of jitter
        self.smoothed_x = self.alpha * self.smoothed_x + (1 - self.alpha) * dx
        self.smoothed_y = self.alpha * self.smoothed_y + (1 - self.alpha) * dy
        self.smoothed_a = self.alpha * self.smoothed_a + (1 - self.alpha) * da
        
        diff_x = self.smoothed_x - dx
        diff_y = self.smoothed_y - dy
        diff_a = self.smoothed_a - da
        
        # 4. Warp and crop frame
        M = np.array([
            [np.cos(diff_a), -np.sin(diff_a), diff_x],
            [np.sin(diff_a),  np.cos(diff_a), diff_y]
        ])
        stabilized = cv2.warpAffine(frame, M, (w, h))
        
        # Center-crop to remove boundary artifacts
        cw, ch = int(w * self.crop_ratio), int(h * self.crop_ratio)
        x1, y1 = (w - cw) // 2, (h - ch) // 2
        stabilized = cv2.resize(stabilized[y1:y1+ch, x1:x1+cw], (w, h))
        
        self.prev_gray = curr_gray
        return stabilized
Prøv at besvare dette spørgsmål med en AI-coach

15Hvordan ville du optimere en realtids-vision-pipeline, når detektoren er langsommere end den tilsigtede billedhastighed?

Når en objektdetektor ikke kan opretholde den tilsigtede billedhastighed (f.eks. kører med 15-20 FPS på et 60 FPS videofeed), afkobler en robust produktionsarkitektur detektering fra realtidspræsentationsloopet ved hjælp af en asynkron flertrådet pipeline, der kombinerer tung detektering med letvægtssporing. I denne hybridarkitektur fanger en indtags-tråd kontinuerligt videobilleder. Den tunge detektor kører asynkront som en 'keyframe'-detektor på en baggrunds-arbejdstråd. I mellemtiden kører en letvægtssporer (såsom optisk flow Lucas-Kanade, ByteTrack/BoT-SORT eller et hurtigt korrelationsfilter/Kalman-filter) synkront på hvert billede med fuld 60 FPS, opretholder objekttilstand, identitet og jævne bounding box-trajektorier. For at håndtere forsinkelse og backpressure uden at introducere ubegrænset latenstid eller forældede billeder, bruges begrænsede ringbuffere og politikker for at droppe seneste billede. Når detektoren er færdig med et billede T_0 på tidspunkt T_curr, er dens output forældet. Pipelinen udfører koordinat-genjustering/bagudprojektion: den associerer de forsinkede detektionsresultater med den historiske tracklet-tilstand ved T_0, opdaterer identiteter og mistede spor og propagerer korrektionerne fremad til T_curr via sporings-bevægelsesvektorerne eller Kalman-filterets forudsigelsestrin.

import queue
import threading

frame_queue = queue.Queue(maxsize=1)  # Drop stale frames, keep latest
det_result_queue = queue.Queue()

def detector_worker():
    while True:
        frame, frame_id, timestamp = frame_queue.get()
        boxes, scores, classes = heavy_detector.infer(frame)
        det_result_queue.put({'frame_id': frame_id, 'boxes': boxes, 'timestamp': timestamp})

def realtime_pipeline(video_stream):
    tracker = FastTracker()  # e.g. Optical flow or Kalman tracker
    
    for frame, frame_id, timestamp in video_stream:
        if frame_queue.empty():
            frame_queue.put((frame, frame_id, timestamp))
            
        if not det_result_queue.empty():
            det_result = det_result_queue.get()
            tracker.reconcile_and_correct(det_result, current_frame_id=frame_id)
            
        active_tracks = tracker.update(frame)
        display_or_downstream(frame, active_tracks)
Prøv at besvare dette spørgsmål med en AI-coach