Model multimodal lahir dalam ragam bentuk — mesin pencari gambar, pembuat caption, penjawab pertanyaan gambar, transkripsi ucapan — dan tiap bentuk menuntut cara menilai yang berbeda. Satu angka akurasi global tidak bermakna di sini: jawaban “benar” untuk retrieval berarti pasangan yang tepat masuk peringkat teratas, untuk captioning berarti tumpang tindih n-gram dengan kalimat manusia, dan untuk VQA berarti kesesuaian dengan mayoritas anotator. Chapter penutup section ini memetakan metrik ke tugasnya, lalu menghitung recall@K, akurasi VQA, dan WER secara nyata pada contoh mini — bekal untuk membaca klaim performa model multimodal modern dengan mata kritis.

Peta Tugas ke Metrik #

TugasMetrik utamaPertanyaan yang dijawab
Retrieval gambar-teksrecall@Kseberapa sering pasangan benar masuk peringkat K teratas?
Captioning gambarBLEU, CIDErseberapa besar tumpang tindih n-gram dengan referensi manusia?
Visual question answeringakurasi (konvensi multi-anotator)berapa jawaban yang disetujui mayoritas anotator?
Speech recognitionWERberapa kata yang salah per kata referensi?

Dua metrik generatif di baris kedua bukan barang baru: perhitungan manual BLEU dengan clipping dan brevity penalty sudah kita kerjakan di chapter Evaluasi Model NLP , dan mekanismenya dipakai apa adanya untuk captioning. CIDEr menambahkan bobot TF-IDF per n-gram sehingga kata umum (“sebuah”, “foto”) berbobot kecil dan kata pembeda (“gajah”) berbobot besar, lalu mengukur kesepakatan antar referensi (arxiv.org/abs/1411.5726 ).

Demo: Tiga Metrik dalam Satu Berkas #

Berkas berikut menghitung tiga keluarga metrik pada data mini. Retrieval memakai 20 pasangan embedding sintetis dengan derau pada sisi teks — kembar konseptual dari evaluasi CLIP pada chapter Contrastive Image-Text Learning . VQA memakai enam pertanyaan beranotasi sepuluh jawaban manusia. WER dihitung lewat alignment edit-distance yang kita implementasi penuh:

python
"""Metrik evaluasi multimodal, tiga keluarga dihitung nyata:

1. Retrieval recall@K -- 20 pasangan embedding sintetis (gambar-teks,
   derau Gaussian pada sisi teks); ranking kosinus dihitung dua arah,
   recall@1/@5/@10 dicetak; satu contoh query ditampilkan top-3.
2. Akurasi VQA -- 6 pertanyaan beranotasi 10 jawaban manusia;
   dua konvensi penskoran (mayoritas ketat vs cocok-satu-saja)
   memberikan angka berbeda untuk model yang sama.
3. WER -- alignment edit-distance (DP) antara referensi dan hipotesis
   kata; substitution, deletion, insertion terhitung per contoh plus
   agregat korpus.

NumPy murni + baku Python. Deterministik penuh. NumPy 2.1.
"""

import numpy as np

rng = np.random.default_rng(10)

print("=== 1. Retrieval: recall@K pada embedding sintetis ===")
N, D = 20, 8
emb_gambar = rng.normal(size=(N, D))
emb_teks = emb_gambar + 0.9 * rng.normal(size=(N, D))


def normalisasi(x):
    return x / np.linalg.norm(x, axis=1, keepdims=True)


G, T = normalisasi(emb_gambar), normalisasi(emb_teks)
skor = G @ T.T                      # matriks kosinus (20 x 20)


def recall_at_k(matriks, k):
    """Rata-rata hitung: pasangan benar (diagonal) masuk top-K."""
    peringkat = (-matriks).argsort(axis=1)
    hit = [i in peringkat[i, :k] for i in range(matriks.shape[0])]
    return float(np.mean(hit))


print(f"{N} pasangan, dimensi {D}, derau teks sigma 0.9")
for K in (1, 5, 10):
    r_i2t = recall_at_k(skor, K)
    r_t2i = recall_at_k(skor.T, K)
    print(f"recall@{K:2d}: gambar->teks {r_i2t:.2f}  "
          f"teks->gambar {r_t2i:.2f}")
peringkat = (-skor).argsort(axis=1)
q = 3
top3 = peringkat[q, :3]
print(f"query gambar {q}: top-3 teks = {top3.tolist()} "
      f"(benar: {q})")
print("skor kosinus:", " ".join(f"t{int(t)}={skor[q, t]:.3f}"
                                for t in top3))

print()
print("=== 2. Akurasi VQA: konvensi penskoran berbeda ===")
vqa = [
    ("ada berapa orang di foto?", "dua",
     {"dua": 7, "2": 3}),
    ("kendaraan apa yang terlihat?", "kereta",
     {"kereta": 5, "ka": 4, "krl": 1}),
    ("warna apa dindingnya?", "putih",
     {"putih": 4, "abu": 4, "perak": 2}),
    ("apakah ada meja?", "tidak",
     {"tidak": 6, "bukan": 4}),
    ("apakah ada ikan?", "ya",
     {"ya": 2, "ada": 5, "ada ikan": 3}),
    ("benda apa di depan toko?", "sepeda",
     {"sepeda motor": 6, "motor": 4}),
]


def skor_vqa(ketat):
    benar = 0
    for tanya, jawab_model, anotasi in vqa:
        n_cocok = anotasi.get(jawab_model, 0)
        if ketat:
            benar += n_cocok >= 5
        else:
            benar += n_cocok >= 1
    return benar / len(vqa)


ak_ketat = skor_vqa(ketat=True)
ak_longgar = skor_vqa(ketat=False)
print("6 pertanyaan, 10 anotator per pertanyaan")
print("rincian per pertanyaan (jawaban model vs jumlah anotator):")
for tanya, jawab_model, anotasi in vqa:
    n_cocok = anotasi.get(jawab_model, 0)
    print(f"  '{tanya}' model='{jawab_model}': {n_cocok}/10")
print(f"konvensi mayoritas ketat (>=5/10) : akurasi {ak_ketat:.3f}")
print(f"konvensi longgar  (>=1 anotator)  : akurasi {ak_longgar:.3f}")

print()
print("=== 3. WER: alignment referensi vs hipotesis ===")


def alignment_wer(ref, hyp):
    """DP edit distance; kembalikan (S, D, I, daftar operasi)."""
    R, H = ref.split(), hyp.split()
    n, m = len(R), len(H)
    dp = [[0] * (m + 1) for _ in range(n + 1)]
    for i in range(n + 1):
        dp[i][0] = i
    for j in range(m + 1):
        dp[0][j] = j
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            biaya = 0 if R[i - 1] == H[j - 1] else 1
            dp[i][j] = min(dp[i - 1][j - 1] + biaya,  # OK / SUB
                           dp[i - 1][j] + 1,          # DEL
                           dp[i][j - 1] + 1)          # INS
    ops, i, j = [], n, m
    while i > 0 or j > 0:
        if i > 0 and j > 0 and dp[i][j] == dp[i - 1][j - 1] + (
                0 if R[i - 1] == H[j - 1] else 1):
            jenis = "OK" if R[i - 1] == H[j - 1] else "SUB"
            ops.append((jenis, R[i - 1], H[j - 1]))
            i, j = i - 1, j - 1
        elif i > 0 and dp[i][j] == dp[i - 1][j] + 1:
            ops.append(("DEL", R[i - 1], None))
            i -= 1
        else:
            ops.append(("INS", None, H[j - 1]))
            j -= 1
    ops.reverse()
    S = sum(1 for jenis, _, _ in ops if jenis == "SUB")
    D = sum(1 for jenis, _, _ in ops if jenis == "DEL")
    I = sum(1 for jenis, _, _ in ops if jenis == "INS")
    return S, D, I, ops


contoh_wer = [
    ("siti makan nasi", "siti minum nasi"),
    ("budi pergi ke pasar", "budi ke pasar"),
    ("kucing hitam", "kucing hitam besar"),
]
total_err = total_kata = 0
for ref, hyp in contoh_wer:
    S, D, I, ops = alignment_wer(ref, hyp)
    n_ref = len(ref.split())
    wer = (S + D + I) / n_ref
    total_err += S + D + I
    total_kata += n_ref
    jejak = " ".join(
        f"{r}->{h if h else '-'}[{o}]" for o, r, h in ops)
    print(f"ref '{ref}' vs hyp '{hyp}': S={S} D={D} I={I} "
          f"-> WER {wer:.3f}")
    print(f"  alignment: {jejak}")
print(f"WER korpus (gabungan): {total_err}/{total_kata} = "
      f"{total_err / total_kata:.3f}")

Output yang Dihasilkan:

text
=== 1. Retrieval: recall@K pada embedding sintetis ===
20 pasangan, dimensi 8, derau teks sigma 0.9
recall@ 1: gambar->teks 0.55  teks->gambar 0.55
recall@ 5: gambar->teks 0.95  teks->gambar 1.00
recall@10: gambar->teks 1.00  teks->gambar 1.00
query gambar 3: top-3 teks = [8, 3, 4] (benar: 3)
skor kosinus: t8=0.699 t3=0.689 t4=0.507

=== 2. Akurasi VQA: konvensi penskoran berbeda ===
6 pertanyaan, 10 anotator per pertanyaan
rincian per pertanyaan (jawaban model vs jumlah anotator):
  'ada berapa orang di foto?' model='dua': 7/10
  'kendaraan apa yang terlihat?' model='kereta': 5/10
  'warna apa dindingnya?' model='putih': 4/10
  'apakah ada meja?' model='tidak': 6/10
  'apakah ada ikan?' model='ya': 2/10
  'benda apa di depan toko?' model='sepeda': 0/10
konvensi mayoritas ketat (>=5/10) : akurasi 0.500
konvensi longgar  (>=1 anotator)  : akurasi 0.833

=== 3. WER: alignment referensi vs hipotesis ===
ref 'siti makan nasi' vs hyp 'siti minum nasi': S=1 D=0 I=0 -> WER 0.333
  alignment: siti->siti[OK] makan->minum[SUB] nasi->nasi[OK]
ref 'budi pergi ke pasar' vs hyp 'budi ke pasar': S=0 D=1 I=0 -> WER 0.250
  alignment: budi->budi[OK] pergi->-[DEL] ke->ke[OK] pasar->pasar[OK]
ref 'kucing hitam' vs hyp 'kucing hitam besar': S=0 D=0 I=1 -> WER 0.500
  alignment: kucing->kucing[OK] hitam->hitam[OK] None->besar[INS]
WER korpus (gabungan): 3/9 = 0.333

Mari kita telaah kode di atas baris per baris:

  1. Baris 21-31: 20 embedding “gambar” ditarik dari Gaussian, lalu embedding “teks” adalah salinannya ditambah derau sigma 0,9 — pasangan benar tetap paling mirip secara rata-rata, tetapi tidak selalu berjarak terdekat, persis situasi retrieval nyata. Matriks G @ T.T berisi kosinus semua pasangan; diagonalnya adalah pasangan benar.
  2. Baris 34-38 (recall_at_k): (-matriks).argsort mengurutkan kandidat dari skor tertinggi; sebuah pasangan dihitung benar bila indeks diagonalnya muncul pada kolom k pertama barisnya. Rata-rata biner inilah definisi recall@K.
  3. Baris 57-70 (data VQA): setiap pertanyaan membawa distribusi jawaban sepuluh anotator — manusia memang tidak seragam; “dua” dan “2”, “kereta” dan “ka”, adalah jawaban sama yang ditulis berbeda.
  4. Baris 73-81 (skor_vqa): dua konvensi diuji — ketat (jawaban model dipilih minimal lima dari sepuluh anotator) dan longgar (cukup satu anotator saja). Konvensi resmi dataset VQA berada di antara keduanya: jawaban dihitung benar bila disetujui minimal tiga dari sepuluh anotator.
  5. Baris 98-130 (alignment_wer): tabel DP dp[i][j] menyimpan biaya edit minimum antara i kata pertama referensi dan j kata pertama hipotesis; tiga operasi (OK/SUB diagonal, DEL dari atas, INS dari kiri) mengisi tabel, lalu backtrace merakit alignment kata-per-kata.
  6. Baris 133-151: tiga contoh WER sengaja memuat satu substitution, satu deletion, dan satu insertion; WER korpus menjumlahkan seluruh galat lalu membagi total kata referensi.

Angka-angka pada keluaran memuat pelajaran pembacaan metrik. Recall@1 sebesar 0,55 tampak buruk, tetapi recall@5 mencapai 0,95 — untuk mesin pencari, jawaban benar di peringkat atas lima tetap berguna karena pengguna menelusuri beberapa hasil; pilihan K harus mengikuti kasus pemakaian. Query contoh memperlihatkan kegagalan yang informatif: teks benar (t3, kosinus 0,689) kalah tipis oleh teks lain (t8, 0,699). Pada VQA, model yang sama dinilai 0,500 atau 0,833 bergantung konvensi — pertanyaan “warna apa dindingnya” memperlihatkan penyebabnya: anotator terbelah antara “putih” (4) dan “abu” (4). WER sendiri bisa melebihi 1,0 bila hipotesis memuat banyak kata sisipan, karena pembagi tetap jumlah kata referensi.

Tantangan Khusus Evaluasi Multimodal #

Dua kelemahan model multimodal modern tidak tertangkap oleh metrik di atas. Pertama, halusinasi VLM: model menjawab pertanyaan tentang objek yang tidak ada di gambar dengan keyakinan penuh, sementara skor BLEU bisa tetap tinggi karena sebagian besar kalimatnya benar. Pengujian POPE (arxiv.org/abs/2305.10355 ) menyodorkan pertanyaan ya/tidak tentang objek yang sengaja tidak ada lalu mengukur akurasi sebagai skor halusinasi. Kedua, bias komposisional: model mahir mencocokkan kata secara terpisah tetapi gagal pada relasi antar kata. Winoground (arxiv.org/abs/2204.03162 ) menguji ini dengan pasangan caption yang berbeda hanya pada urutan kata (“pelukis menyisir model” vs “model menyisir pelukis”) dan sepasang gambar yang bertukar subjek-objeknya; banyak model yang unggul di retrieval biasa jatuh di tes ini.

Sintesis: Menutup Section Multimodal #

Sembilan chapter di section ini bermuara pada satu pola besar. Kita mulai dari penyatuan ruang representasi dan fusi di Pengenalan Multimodal Learning , membangun ruang bersama image-text beserta jebakan degenerasinya, lalu melihat pelatihan kontrastif CLIP memecahkannya. Vision-language model menambahkan kemampuan menalar di atas ruang bersama itu melalui cross-attention — mekanisme yang kembali muncul ketika Whisper menyatukan audio dan teks pada Speech Recognition , dibalik oleh Text-to-Speech , dan diperluas ke sumbu waktu oleh Video Understanding . Evaluasi menutup lingkaran ini: setiap keluarga tugas membawa definisi “benar” sendiri, dan angka yang sehat hanya lahir dari metrik yang cocok dengan tugasnya.

Seluruh kemampuan itu pada akhirnya bertumpu pada satu hal yang belum kita bahas secara sistematis: data. Kualitas pasangan image-text, cakupan aksen pada korpus ucapan, dan keberagaman video latih menentukan batas atas model sebelum arsitektur mana pun bekerja. Section berikutnya, Data dan Dataset , mengangkat topik itu ke pusat pembahasan — dari pengumpulan, pembersihan, augmentasi, hingga etika penggunaan data.