সরাসরি পর্বে যান
পর্ব ৮১ · ৯১-এর মধ্যে · মডিউল ১২

Generative model-এর মূল্যায়ন আর নিরাপত্তা — FID, CLIP score, deepfake আর watermark

Evaluating and Securing Generative Models — FID, CLIP Score, Deepfakes and Watermarks

Taught in Bangla, this lesson separates quality, diversity and novelty when judging generative models. It computes the Fréchet distance behind FID by hand and its sample-size bias, measures Inception and classifier-feature FID, precision, recall and nearest-neighbour memorisation on the course's Fashion-MNIST DDPM samples, and computes CLIP score. It then covers deepfake harms, C2PA, SynthID and a real spread-spectrum watermark test against JPEG, resize and crop, from desktop runs with in-page Python.

এই পর্বে যা শিখবেন

  • Inception Score আর FID কী মাপে, দুটি Gaussian-এর Fréchet distance হাতে, আর নমুনা-সংখ্যার পক্ষপাত
  • Generative model-এর precision আর recall: মান আর বৈচিত্র্য আলাদা করে মাপা
  • CLIP score দিয়ে লেখা আর ছবির মিল মাপা, আর মানুষের মূল্যায়ন কেন এখনও লাগে
  • নিজের model training ছবি কপি করছে কি না, nearest-neighbour দিয়ে যাচাই
  • Deepfake-এর ক্ষতি, C2PA, SynthID আর invisible watermark: কী পারে, কী পারে না, সত্যিকারের পরীক্ষাসহ

এই মডিউলে পর্ব ৭৪ থেকে পর্ব ৭৯ পর্যন্ত (আর পর্ব ৭৬, ৭৮ ও ৮০-তে) নানা generative model দেখেছেন, আর প্রতিবার প্রশ্ন এসেছে: “কোনটা ভালো?” এই শেষ পর্বে সেই প্রশ্নের হাতিয়ার, আর পরের প্রশ্ন: এত বাস্তব ছবি বানানো গেলে মানুষকে কীভাবে রক্ষা করবেন। চারটি ব্লক ব্রাউজারের Python-এ চলে (প্রথমবার প্যাকেজ নামতে কয়েক সেকেন্ড লাগে)। FID, CLIP score, memorisation আর watermark-এর সংখ্যা ডেস্কটপের সত্যিকারের run থেকে, Python 3.14-এ।

১ · মূল্যায়ন কেন কঠিন — তিনটি আলাদা প্রশ্ন

ধরুন একজন নতুন রাঁধুনি বাজারঘরের ক্যান্টিনে একশো প্লেট বিরিয়ানি রাঁধলেন। স্বাদ ভালো কি না একটি প্রশ্ন; তিনি শুধু বিরিয়ানিই পারেন না খিচুড়ি-তেহারিও, সেটা আরেক প্রশ্ন; আর পাশের দোকান থেকে কিনে এনে নিজের বলে চালাচ্ছেন কি না, তৃতীয় প্রশ্ন। স্বাদ, বৈচিত্র্য আর মৌলিকতা, তিনটি আলাদা প্রশ্ন; একটি নম্বর দিয়ে তিনটির উত্তর হয় না। Generative model-এর মূল্যায়নেও ঠিক এই তিন প্রশ্ন।

Generative model-এর কোনো “সঠিক উত্তর” নেই; একটি নতুন জুতোর ছবি ভালো কি না, তা নির্ভর করে পুরো ডেটার distribution-এর সঙ্গে মিলের ওপর। পর্ব ৭৪-এ likelihood (bits per dimension) দেখেছিলেন। সেটি ভালো মাপ, কিন্তু GAN-এর মতো model likelihood দেয়ই না, আর Theis ও সহকর্মীরা (২০১৬) দেখান, বেশি likelihood মানেই চোখে ভালো ছবি নয়, উল্টোটাও সত্য। তাই নমুনা-ভিত্তিক মাপ লাগে।

Pixel ধরে তুলনা অর্থহীন (জুতো এক pixel সরালেই দূরত্ব অনেক), তাই প্রতিটি ছবিকে একটি feature extractor দিয়ে vector-এ নেওয়া হয়, যেখানে একই ধরনের ছবি কাছাকাছি থাকে। প্রচলিত পছন্দ ImageNet-এ শেখানো Inception v3 network-এর শেষ pooling স্তরের ২০৪৮-মাত্রার vector. তারপর দুই সেট vector-এর distribution তুলনা। নিচের ছবিতে পুরো পথ।

FID-এর পাইপলাইন

Images → feature vectors → one Gaussian per set → Fréchet distance

FID pipeline: images, feature extractor, Gaussian fit, Fréchet distance আসল ছবি 10,000 নকল ছবি 2,000 Feature Inception v3 2048-d μ₁, Σ₁ μ₂, Σ₂ Fréchet distance কম = কাছাকাছি
ছবি ৮১.১ — দুই সেট ছবি একই network দিয়ে vector-এ যায়; প্রতিটি সেটের শুধু গড় (μ) আর covariance matrix (Σ) রেখে দুটি Gaussian-এর দূরত্ব। Feature extractor বা resize-এর নিয়ম বদলালে সংখ্যাও বদলায়।

তিনটি অনুমান মনে রাখুন: FID শুধু তাই দেখে যা feature extractor দেখে; feature Gaussian না হলেও গড় আর covariance দিয়েই সারাংশ হয়; আর μ ও Σ নমুনা থেকে অনুমান, তাই কম নমুনায় ভুল বাড়ে।

২ · Inception Score আর FID — দুটি Gaussian-এর দূরত্ব

প্রথম জনপ্রিয় মাপ ছিল Inception Score (IS; Salimans ও সহকর্মীরা, ২০১৬)। চাই প্রতিটি generated ছবিতে classifier-এর p(y | x) একটি class-এ নিশ্চিত হোক, আর সব মিলিয়ে p(y) সমতল হোক; দুটি একসঙ্গে মাপে KL divergence-এর গড়:

IS = exp( Ex [ KL( p(y | x) ‖ p(y) ) ] )

IS সর্বোচ্চ class-এর সংখ্যা, সর্বনিম্ন ১ (KL-এর মূল কথা AI-এর ভিত্তি কোর্সের পর্ব ৩৮-এ)। বড় দুর্বলতা: IS আসল ডেটার দিকে তাকায়ই না; প্রতিটি class-এর একটি করে নিখুঁত ছবি বারবার বানালেও সর্বোচ্চ হতে পারে, তাই class-এর ভেতরের mode collapse ধরা পড়ে না।

Heusel ও সহকর্মীরা (২০১৭) প্রস্তাব করেন Fréchet Inception Distance: দুই সেটের feature-কে দুটি multivariate Gaussian N(μ1, Σ1) আর N(μ2, Σ2) ধরে তাদের Fréchet distance (দুটি Gaussian-এর মধ্যে এটি 2-Wasserstein দূরত্বের বর্গের সমান, Dowson আর Landau, ১৯৮২):

d2 = ‖μ1 − μ2‖2 + Tr( Σ1 + Σ2 − 2 (Σ1Σ2)½ )

প্রথম পদ দুই গড়ের দূরত্বের বর্গ, দ্বিতীয় পদ ছড়িয়ে থাকার আকার মেলায়; Tr মানে trace, matrix-এর কর্ণের যোগফল, আর (Σ1Σ2)½ হলো matrix square root, এমন একটি matrix যার বর্গ Σ1Σ2. Gaussian আর covariance-এর ভিত্তি মেশিন লার্নিং কোর্সের পর্ব ১৯-এ। সূত্রটি কেন যুক্তিসংগত, তা এক মাত্রায় পরিষ্কার: তখন Σ হলো variance σ2, আর √(σ12σ22) = σ1σ2, তাই

d2 = (μ1 − μ2)2 + σ12 + σ22 − 2σ1σ2 = (μ1 − μ2)2 + (σ1 − σ2)2

গড় মিলতে হবে, ছড়ানোও মিলতে হবে (সব নমুনা একই রকম হলে দ্বিতীয় পদ বাড়ে)। Covariance কর্ণ-আকারের (diagonal) হলে সূত্র প্রতিটি মাত্রার এক-মাত্রিক দূরত্বের যোগফলে ভেঙে যায়। নিচের stepper-এ দুটি উদাহরণ।

1-D: আসল N(5, 2²), নকল N(3, 1²) · 2-D: আসল μ₁ = (0, 0), Σ₁ = diag(4, 1); নকল μ₂ = (1, 2), Σ₂ = diag(1, 1)
ধাপ
হিসাব
মানে
  1. গড়ের পদ. আসলের গড় ৫, নকলের ৩; পার্থক্যের বর্গ ৪. নকল ছবিগুলো গড়ে একদিকে সরে আছে।
  2. ছড়ানোর পদ. σ1 = ২, σ2 = ১: ৪ + ১ − ৪ = ১, যা (২ − ১)2-এর সমান। নকল ছবি আসলের চেয়ে কম বৈচিত্র্যময়।
  3. মোট. d2 = ৫. FID বলতে সাধারণত এই বর্গটিই বোঝায়; এর বর্গমূল ২.২৩৬ নয়।
  4. দুই মাত্রায় গড়. গড়ের vector-এর পার্থক্য (১, ২), দৈর্ঘ্যের বর্গ ১ + ৪ = ৫.
  5. Trace-এর পদ. Diagonal matrix-এর গুণফল আর বর্গমূল প্রতিটি কর্ণ-উপাদানে আলাদা: diag(২, ১)। ৭ − ২ × ৩ = ১, যা প্রথম মাত্রার (২ − ১)2 আর দ্বিতীয়টির (১ − ১)2-এর যোগফল। মোট d2 = ৬.

এবার নমুনা-সংখ্যার পক্ষপাত। দুই সেট একই distribution থেকে এলে আসল দূরত্ব শূন্য; কিন্তু অনুমিত μ আর Σ-এর এলোমেলো ভুল সূত্রে কাটাকাটি হয় না, যোগ হয়। তাই অনুমিত FID প্রায় সবসময় শূন্যের বেশি, আর প্রায় ১/n হারে কমে। Bińkowski ও সহকর্মীরা (২০১৮) এই পক্ষপাত দেখিয়ে পক্ষপাতহীন বিকল্প KID প্রস্তাব করেন; Chong আর Forsyth (২০২০) বিভিন্ন n-এ FID মেপে n → ∞-এ টেনে নেওয়ার পদ্ধতি দেন। নিচের ব্লক stepper-এর সংখ্যা যাচাই করে, তারপর ৩২-মাত্রার একই Gaussian থেকে দুই সেট টেনে পক্ষপাত দেখায়।

import numpy as np
from scipy import linalg
import matplotlib.pyplot as plt

def frechet(m1, S1, m2, S2):              # ‖μ1 − μ2‖² + Tr(Σ1 + Σ2 − 2(Σ1Σ2)^½)
    covmean = linalg.sqrtm(S1 @ S2).real
    return float(np.sum((m1 - m2) ** 2) + np.trace(S1 + S2 - 2 * covmean))

print("1-D:", frechet(np.array([5.]), np.array([[4.]]), np.array([3.]), np.array([[1.]])))
print("2-D diagonal:", round(frechet(np.zeros(2), np.diag([4., 1.]), np.array([1., 2.]), np.eye(2)), 6))
S = np.array([[2., 1.], [1., 2.]])        # একই গড়, শুধু আকার (covariance) আলাদা
print("2-D full, same means:", round(frechet(np.zeros(2), S, np.zeros(2), np.eye(2)), 4))

rng = np.random.default_rng(0); d = 32     # নমুনা-সংখ্যার পক্ষপাত: দুই দিকই একই distribution
A = rng.normal(size=(d, d)) / np.sqrt(d); L = np.linalg.cholesky(A @ A.T + 0.1 * np.eye(d))
ref = rng.standard_normal((5000, d)) @ L.T
mr, Sr = ref.mean(0), np.cov(ref, rowvar=False)
ns, fd = [100, 250, 500, 1000, 2500], []
for n in ns:
    v = [frechet(x.mean(0), np.cov(x, rowvar=False), mr, Sr)
         for x in (rng.standard_normal((n, d)) @ L.T for _ in range(3))]
    fd.append(np.mean(v))
    print(f"n={n:5d}  FD={fd[-1]:.4f}  n*FD={n * fd[-1]:.1f}")
plt.figure(figsize=(5, 3))
plt.plot(1 / np.array(ns), fd, "o-")
plt.xlabel("1 / n"); plt.ylabel("Frechet distance")
plt.title("Same distribution, FD > 0: bias shrinks like 1/n")
plt.show()

আউটপুট (পাতার Python-এ চালানো; সঙ্গে একটি ছবি):

1-D: 5.0
2-D diagonal: 6.0
2-D full, same means: 0.5359
n=  100  FD=2.5282  n*FD=252.8
n=  250  FD=0.9733  n*FD=243.3
n=  500  FD=0.4769  n*FD=238.5
n= 1000  FD=0.2660  n*FD=266.0
n= 2500  FD=0.1250  n*FD=312.4

প্রথম দুই লাইন stepper-এর ৫ আর ৬. তৃতীয় লাইনে দুই গড় একই, শুধু Σ = [[২, ১], [১, ২]] বনাম I; দূরত্ব ০.৫৩৫৯, পুরোটাই আকারের পার্থক্য থেকে (eigenvalue ৩ আর ১, তাই ৪ + ২ − ২(√৩ + ১) ≈ ০.৫৩৬)। এরপর আসল কথা: দুই দিকই একই distribution, তবু n = ১০০-এ দূরত্ব প্রায় ২.৫৩, n = ১০০০-এ ০.২৭. n × FD প্রায় ২৪০-২৭০-এ থাকে, অর্থাৎ পক্ষপাত মোটামুটি ১/n হারে কমে। n = ২৫০০-এ গুণফল একটু বাড়ে, কারণ reference সেটও মাত্র ৫০০০টি নমুনার, তার নিজের অনুমানের ভুল একটি স্থির অংশ যোগ করে। শিক্ষা: তুলনার আগে একই n আর একই reference নিশ্চিত করুন।

৩ · Precision আর recall — মান আর বৈচিত্র্য আলাদা করে

FID দুটি ভিন্ন ব্যর্থতা মেশায়: ঝাপসা কিন্তু সব ধরনের ছবি, আর নিখুঁত কিন্তু অর্ধেক ধরন বাদ; দুটির FID সমান হতে পারে। Sajjadi ও সহকর্মীরা (২০১৮) generative model-এর জন্য precision আর recall আলাদা করার প্রস্তাব দেন; Kynkäänniemi ও সহকর্মীদের (২০১৯) সংস্করণটি বেশি প্রচলিত, আর সেটাই এখানে।

ধারণা: আসল ছবির feature-গুলোর চারপাশে একটি “এলাকা” আঁকুন। প্রতিটি আসল বিন্দুর চারপাশে একটি বল, যার ব্যাসার্ধ সেই বিন্দুর k-তম নিকটতম আসল প্রতিবেশীর দূরত্ব (প্রবন্ধে k = ৩)। সব বলের মিলন হলো আসল ডেটার আনুমানিক manifold.

  • Precision = নকল নমুনার কত ভাগ আসল এলাকার ভেতরে পড়ে। কম মানে model এমন ছবি বানায় যা আসল ডেটায় নেই (ঝাপসা, বিকৃত)।
  • Recall = উল্টো দিক থেকে: নকল নমুনার চারপাশে একইভাবে এলাকা বানিয়ে, আসল নমুনার কত ভাগ সেই এলাকায় পড়ে। কম মানে আসল ডেটার কিছু অংশ model কখনো বানায় না (mode বাদ পড়া)।

এখানে কোনো label নেই; “হ্যাঁ” মানে k-NN বলের এলাকার ভেতরে থাকা। নিচের ব্লক বৃত্তের ওপর ৮টি দলের একটি খেলনা ডেটায় তিন ধরনের “model” তুলনা করে: প্রায় নিখুঁত, শুধু ৪টি দল, আর সব দল কিন্তু ঝাপসা।

import numpy as np
from scipy.spatial.distance import cdist
from scipy import linalg
import matplotlib.pyplot as plt

rng = np.random.default_rng(1); K, n = 8, 600
ang = 2 * np.pi * np.arange(K) / K
mu = 2 * np.c_[np.cos(ang), np.sin(ang)]                   # বৃত্তের ওপর ৮টি দল
def ring(modes, sd):
    return mu[rng.choice(modes, n)] + sd * rng.standard_normal((n, 2))
real = ring(np.arange(K), 0.1)
fakes = {"good": ring(np.arange(K), 0.1), "4 modes only": ring(np.arange(4), 0.1),
         "blurry": ring(np.arange(K), 0.35)}

def radius(x, k=3):                         # k-তম নিকটতম প্রতিবেশীর দূরত্ব
    return np.sort(cdist(x, x), 1)[:, k]
def prec_rec(r, f):
    D = cdist(f, r)
    prec = (D <= radius(r)[None, :]).any(1).mean()     # নকল বিন্দু আসলের "এলাকায়"?
    rec = (D.T <= radius(f)[None, :]).any(1).mean()    # আসল বিন্দু নকলের "এলাকায়"?
    return prec, rec
def fd(a, b):
    S1, S2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
    return np.sum((a.mean(0) - b.mean(0)) ** 2) + np.trace(S1 + S2 - 2 * linalg.sqrtm(S1 @ S2).real)

fig, axs = plt.subplots(1, 3, figsize=(10, 3.2), sharex=True, sharey=True)
for ax, (name, f) in zip(axs, fakes.items()):
    p, r = prec_rec(real, f)
    print(f"{name:13s} precision {p:.2f}  recall {r:.2f}  FD {fd(real, f):.3f}")
    ax.scatter(*real.T, s=2, c="grey"); ax.scatter(*f.T, s=2, c="tab:red")
    ax.set_title(f"{name}: P={p:.2f}, R={r:.2f}")
plt.show()

আউটপুট (পাতার Python-এ চালানো; সঙ্গে তিনটি ছবি):

good          precision 0.97  recall 0.96  FD 0.009
4 modes only  precision 0.95  recall 0.47  FD 2.583
blurry        precision 0.33  recall 0.98  FD 0.029

“good” নকলের দুটিই প্রায় ১. “4 modes only”: যা বানায় তা নিখুঁত (precision ০.৯৫), কিন্তু আসল ডেটার প্রায় অর্ধেক কখনো আসে না (recall ০.৪৭)। “blurry”: সব দল ঢাকে (recall ০.৯৮), কিন্তু নমুনার দুই-তৃতীয়াংশ আসল এলাকার বাইরে (precision ০.৩৩)। আর Fréchet distance: অর্ধেক দল বাদে ২.৫৮, কিন্তু ঝাপসা model-এর মাত্র ০.০২৯, কারণ একটি Gaussian আটটি দলকে একটি বড় গোল মেঘ হিসেবে দেখে, দলের ভেতরের ছড়ানো তাতে সামান্যই বদলায়। এই খেলনায় ঝাপসা ভাব FID প্রায় দেখেনি, precision দেখেছে।

সতর্কতা: k বদলালে মান বদলায়, আর দূরের outlier-এর বিশাল বল অনেক নকলকে “ভেতরে” ধরে ফেলে; তাই Naeem ও সহকর্মীরা (২০২০) “density” আর “coverage” প্রস্তাব করেন। প্রতিবেদনে feature, k আর n লিখুন।

৪ · সত্যিকারের run — Fashion-MNIST-এ FID: Inception বনাম নিজের classifier

ডেটা Fashion-MNIST (Zalando Research, MIT লাইসেন্স), বাজারঘরের পণ্যের ছবির বদলি; আসল দোকানের ছবি নয়। Reference সেট: ১০,০০০টি test ছবি। Generator: পর্ব ৭৯-এর linear schedule-এর DDPM checkpoint (EMA weight, ৫১ epoch) কপি করে নতুন seed ৭-এ নমুনা। তুলনায় training সেটের আসল ছবি, আর তাতে Gaussian noise (pixel ০-১ মাপে sd ০.০৫, ০.১, ০.২) ও blur (σ = ১, ২ pixel).

দুটি feature extractor পাশাপাশি: (১) pytorch-fid 0.3.0 (Apache 2.0 লাইসেন্স), যার Inception v3 weight মূল TensorFlow FID implementation থেকে আনা বলে package-এর docs জানায় (প্রায় ৯৬ MB); ধূসর ছবি তিন channel-এ কপি করে ২৯৯ × ২৯৯-এ বড় করা হয়। (২) পর্ব ৭৯-এর নিজের ছোট CNN classifier-এর ১২৮-মাত্রার feature (test accuracy ০.৯০৬৭), যাকে বলছি FID(clf); এটি প্রচলিত FID নয়, অন্য কোনো প্রবন্ধের সংখ্যার সঙ্গে তুলনা চলে না। Precision/recall Inception feature-এ, ২০০০ বনাম ২০০০টি test ছবি, k = ৩; IS(clf) নিজের classifier দিয়ে (সর্বোচ্চ ১০)। Python 3.14, torch 2.15.0; নমুনা আর feature GPU-তে, বাকি CPU-তে।

~/bazarghar-dl$ uv run python gen.py
ddim10      2000 samples     2.0s
ddim50     10000 samples    39.5s
ddpm1000    2000 samples   156.0s
peak GPU memory allocated: 1272 MiB

~/bazarghar-dl$ uv run python feats.py
test        10000 images  inception 2048-d  clf 128-d
train10k    10000 images  inception 2048-d  clf 128-d
noise0.05    2000 images  inception 2048-d  clf 128-d
noise0.1     2000 images  inception 2048-d  clf 128-d
noise0.2     2000 images  inception 2048-d  clf 128-d
blur1        2000 images  inception 2048-d  clf 128-d
blur2        2000 images  inception 2048-d  clf 128-d
ddpm1000     2000 images  inception 2048-d  clf 128-d
ddim50      10000 images  inception 2048-d  clf 128-d
ddim10       2000 images  inception 2048-d  clf 128-d
feature time 93.1s on GPU
peak GPU memory allocated: 3642 MiB

~/bazarghar-dl$ uv run python analyze.py
reference: 10,000 Fashion-MNIST test images
set                     n  FID(Inception)  FID(clf)  prec   rec  IS(clf)
real train           2000            8.14     1.657  0.77  0.78     7.87
real train          10000            2.53     0.323  0.77  0.78     7.86
noise sd 0.05        2000           68.37    10.745  0.18  0.15     7.41
noise sd 0.1         2000          115.16    39.846  0.08  0.02     6.79
noise sd 0.2         2000          193.44   140.460  0.03  0.00     4.76
blur sigma 1         2000           96.04   151.030  0.14  0.06     5.46
blur sigma 2         2000          216.92   304.144  0.02  0.00     2.99
DDPM 1000 steps      2000           14.67     4.764  0.74  0.63     7.11
DDIM 50 steps        2000           17.14     9.668  0.65  0.66     6.46
DDIM 10 steps        2000           23.33    34.789  0.61  0.60     5.84
test itself         10000                                           7.78

FID vs number of samples n (reference: 10,000 test images)
     n | real train: Inc     clf | DDIM 50: Inc     clf
   250 |           45.47  11.635 |        53.75  21.821
   500 |           28.09   5.699 |        37.17  15.522
  1000 |           15.69   2.069 |        24.13  10.818
  2000 |            8.14   1.657 |        17.14   9.668
  5000 |            3.80   0.461 |        12.42   8.595
 10000 |            2.53   0.323 |        11.15   8.241

ছয়টি পর্যবেক্ষণ, একটি স্থানীয় run থেকে, সাধারণ ফল নয়।

এক, মাপকাঠি আগে। Training সেটের ২০০০টি আসল ছবিও test সেটের সঙ্গে Inception FID ৮.১৪ দেয়, ১০,০০০টিতে ২.৫৩. তাই DDPM-এর ১৪.৬৭ পড়ুন ৮.১৪-এর পাশে রেখে, শূন্যের পাশে নয়। পর্ব ৭৯-এ অন্য ১০০০টি train ছবিতে FID(clf) ছিল ৪.২৩৫, এখানে ২.০৬৯: কোন ছবি নমুনায় পড়ল, তাতেও মান ওঠানামা করে।

দুই, feature extractor যা দেখে, FID তাই দেখে। প্রায় চোখে না-পড়া noise (sd ০.০৫) Inception FID-কে ৬৮.৩৭-এ তোলে, যা DDIM-এর ১০ ধাপের ঝাপসা-ভাঙা নমুনার (২৩.৩৩) প্রায় তিন গুণ; অথচ নিজের classifier-এর চোখে একই noise মাত্র ১০.৭৫. উল্টো দিকে blur σ = ১-এ classifier-এর FID ১৫১.০৩, Inception-এর ৯৬.০৪.

তিন, ক্রম মেলে, মাত্রা মেলে না। তিনটি sampler-এর ক্রম দুই মাপেই এক: DDPM ১০০০ < DDIM ৫০ < DDIM ১০. কিন্তু DDIM ১০ বনাম DDPM-এর অনুপাত Inception-এ প্রায় ১.৬ গুণ, classifier-এ প্রায় ৭.৩ গুণ।

চার, precision আর recall কারণ দেখায়. আসল train ছবি এই n আর k-তে ০.৭৭/০.৭৮ পায় (ছাদ)। DDPM ১০০০-এর precision ০.৭৪, প্রায় আসলের সমান, কিন্তু recall ০.৬৩: নমুনা বাস্তব, বৈচিত্র্য কম। Noise sd ০.১-এ precision ০.০৮.

পাঁচ, IS(clf) আসল ডেটা দেখে না. Test সেট ৭.৭৮, DDPM ৭.১১, blur σ = ২-এ ২.৯৯; কিন্তু প্রতিটি class-এর একটি নিখুঁত ছবি বারবার বানালে IS প্রায় ১০ হতো, আসল ডেটার চেয়েও বেশি।

ছয়, n না মিললে তুলনা নয়। শেষ টেবিলে একই ডেটা, শুধু n বদলানো। আসল train ছবির Inception FID ২৫০টিতে ৪৫.৪৭, ১০,০০০টিতে ২.৫৩; DDIM ৫০-এর ৫৩.৭৫ থেকে ১১.১৫. লক্ষ করুন: ১০০০টি আসল ছবির FID (১৫.৬৯) ২০০০টি DDPM নমুনার FID-এর (১৪.৬৭) চেয়ে বেশি। ভিন্ন n-এর সংখ্যা পাশাপাশি রাখলে আসল ছবিকেও model-এর চেয়ে “খারাপ” দেখানো যায়। আসল ছবির FID n বাড়লে শূন্যের দিকে যায়, model-এরটা একটি ধনাত্মক মানে (এখানে প্রায় ১১) থামে।

৫ · CLIP score আর মানুষের মূল্যায়ন — লেখা আর ছবি মেলে কি না

Text-to-image model (পর্ব ৮০)-এ আরেক প্রশ্ন: ছবি prompt মানছে কি না? “লাল মগ, কাঠের টেবিলে” লিখে নীল জগ পেলে FID খুশি হতে পারে, ক্রেতা নন। প্রচলিত মাপ CLIP score. CLIP (Radford ও সহকর্মীরা, ২০২১) দুটি encoder-এর একটি model: একটি ছবিকে, অন্যটি লেখাকে একই মাপের vector-এ নেয়, আর কোটি কোটি ছবি-caption জোড়ায় contrastive উপায়ে শেখে, যাতে মিলে যাওয়া জোড়ার vector কাছাকাছি থাকে। CLIP-এর ভেতরের গঠন পর্ব ৮২ (Multimodal model)-এর বিষয়; এখানে শুধু মাপটি।

CLIP score = 100 × max( cos(eছবি, eলেখা), 0 )

এখানে cos হলো cosine similarity. ১০০-গুণ রূপটি torchmetrics-এর মতো library-র; মূল CLIPScore প্রবন্ধ (Hessel ও সহকর্মীরা, ২০২১) ২.৫ দিয়ে গুণ করেছিল, তাই দুই উৎসের সংখ্যা সরাসরি তুলনীয় নয়।

ছবি e_i = (1, 2, 0, −1) · caption A e_a = (2, 1, 1, 2) · ভুল caption B e_b = (−1, 0, 1, 2)
ধাপ
হিসাব
মানে
  1. Dot product. অনুরূপ স্থানের গুণফলের যোগ: ২.
  2. দৈর্ঘ্য. √৬ আর √১০. Library সাধারণত embedding-কে আগেই দৈর্ঘ্য ১-এ আনে, তখন dot product-ই cosine.
  3. Cosine. ২ ÷ ৭.৭৪৬ ≈ ০.২৫৮২. উঁচু-মাত্রার CLIP-এ মিলে যাওয়া জোড়ার cosine প্রায়ই এমনই ছোট।
  4. CLIP score. ১০০ দিয়ে গুণ: ২৫.৮২. আমাদের সত্যিকারের run-এ একটি sneaker ছবি আর “a photo of a sneaker”-এর cosine ছিল ০.২০২৬, score ২০.২৬.
  5. ভুল caption. Cosine −০.৫, তাই score শূন্য। বাস্তবে ভুল caption সাধারণত শূন্যের ওপরে কিন্তু কম পায় (run-এ sneaker বনাম “handbag” ৪.৯৭)।

এবার সত্যিকারের run. Model: laion/CLIP-ViT-B-32-laion2B-s34B-b79K (OpenCLIP দলের ViT-B/32, প্রায় ১৫.১ কোটি parameter, card-এ MIT লাইসেন্স, token ছাড়া নামে, প্রায় ৬০৫ MB); card অনুযায়ী চালু পণ্যে ব্যবহার “out of scope”, আমরা শুধু মাপ নিচ্ছি। ছবি: Fashion-MNIST test সেটের প্রতিটি class-এর ২০টি (মোট ২০০), সাদা পটভূমিতে গাঢ় পণ্য করে উল্টে নেওয়া; caption “a photo of a …”. CPU-তে, transformers 5.22.2.

~/bazarghar-dl$ uv run python clipscore.py
model: laion/CLIP-ViT-B-32-laion2B-s34B-b79K, params 151277313
embedding size 512, 200 test images x 10 captions, 7.3s on CPU
matched caption    CLIP score mean 21.3  (min 12.3, max 30.0)
mismatched caption CLIP score mean 11.0
matched > every mismatched caption: 0.83 of images (zero-shot accuracy)
per class: matched / mean mismatched
  T-shirt            21.5 /  11.8
  pair of trousers   22.8 /  10.0
  pullover sweater   22.0 /  11.8
  dress              20.0 /  11.7
  coat               20.5 /  11.8
  sandal             21.5 /  12.2
  shirt              18.5 /  12.1
  sneaker            21.1 /   9.7
  handbag            21.2 /   9.8
  ankle boot         24.0 /   9.4
one pair: sneaker image vs 'a photo of a sneaker' cos 0.2026 -> score 20.26; vs 'a photo of a handbag' cos 0.0497 -> 4.97
first 4 dims of that image embedding: [ 0.0666 -0.1574  0.0064 -0.0254] | caption: [-0.0095 -0.0372 -0.0196 -0.0294]
DDPM samples (200), caption = class predicted by own classifier: CLIP score mean 22.0
  same samples, caption of the next class: mean 11.3
  CLIP zero-shot label agrees with own classifier: 0.76
random-noise images (20): best caption score mean 19.6, all captions mean 18.0
test images, best of 10 captions: mean 21.7

চারটি জিনিস লক্ষ করুন। এক, মিলে যাওয়া caption-এ গড় ২১.৩, ভুল caption-এ ১১.০, আর ৮৩% ছবিতে সঠিক caption-ই সবচেয়ে বেশি পায়। দুই, “shirt” সবচেয়ে কম (১৮.৫), কারণ T-shirt, pullover আর coat-এর সঙ্গে গুলিয়ে যায়। তিন, পর্ব ৭৯-এর DDPM-এর ২০০টি generated ছবি, caption হিসেবে নিজের classifier-এর বলা class: গড় ২২.০, আসল ছবির কাছাকাছি; পাশের class-এর caption-এ ১১.৩. চার, এবং সবচেয়ে শিক্ষণীয়: ২০টি এলোমেলো noise-এর ছবি, যাতে কোনো পণ্যই নেই, যেকোনো caption-এ গড়ে প্রায় ১৮ পায়। অর্থাৎ CLIP score-এর একক মান (“২১ ভালো”) প্রায় অর্থহীন; শুধু একই prompt সেট, একই CLIP model আর একই preprocessing-এ দুটি model-এর তুলনা অর্থবহ। ২৮ × ২৮ ধূসর ছবি CLIP-এর training ডেটার মতো নয়; এটি একটি ছোট স্থানীয় run, সাধারণ ফল নয়।

CLIP গণনা (“তিনটি মগ”) আর কোনটা কার ওপরে, এসবে দুর্বল বলে গবেষণায় দেখা গেছে; আর যে model CLIP দিয়েই guide করা, CLIP score-এ সে মাপকাঠিকেই “খুশি” করতে শেখে। তাই এখনও মানুষের মূল্যায়ন লাগে: একই prompt-এ দুটি model-এর ছবি পাশাপাশি, এলোমেলো ক্রমে দেখিয়ে “কোনটা বেশি বাস্তব, কোনটা prompt বেশি মানে” জিজ্ঞেস করা। এটি ধীর আর ব্যয়বহুল, কিন্তু শেষ বিচারে মানুষই ব্যবহারকারী।

৬ · Memorisation — model কি training ছবি কপি করছে?

তৃতীয় প্রশ্ন: নতুনত্ব। যে model training ছবি হুবহু ফিরিয়ে দেয়, তার FID চমৎকার হতে পারে, কিন্তু সেটি ফটোকপি মেশিন। এটি memorisation. এতে ব্যক্তিগত ছবি ফাঁস বা কপিরাইট-সুরক্ষিত কাজ প্রায় হুবহু বের হতে পারে। Carlini ও সহকর্মীরা (২০২৩) Stable Diffusion-এর মতো model থেকে এক হাজারের বেশি training ছবি প্রায় হুবহু বের করার কথা জানান, বেশির ভাগই ডেটায় বহুবার থাকা ছবি। তাই training ডেটা থেকে প্রায়-নকল ছবি সরানো (deduplication) একটি প্রচলিত প্রতিরক্ষা।

সহজ যাচাই: প্রতিটি generated ছবির নিকটতম training ছবি খুঁজে দূরত্বকে একটি মাপকাঠির সঙ্গে তুলনা করুন: model-এর না-দেখা test ছবি training সেটের কতটা কাছে থাকে। Generated ছবি নিয়মিতভাবে অনেক বেশি কাছে থাকলে সন্দেহ জাগে। আমাদের run: DDPM-এর ২০০০টি নমুনা আর ২০০০টি test ছবি বনাম ৬০,০০০টি training ছবি, pixel-এর L2 দূরত্বে, CPU-তে।

~/bazarghar-dl$ uv run python memo.py
pixel L2 distance (pixels in [0,1], 784 pixels) to the nearest of 60,000 training images
                          min     5%  median
2000 real test images    0.83   1.95    3.43
2000 DDPM samples        1.48   2.24    3.56
samples closer than the 1st percentile of test distances (1.52): 2 of 2000
test images below 1.0: 1, samples below 1.0: 0
pairs shown: closest 3 samples and the median sample, distances [1.48, 1.5, 1.53, 3.56]

DDPM নমুনার নিকটতম training ছবির দূরত্বের median ৩.৫৬, test ছবির ৩.৪৩: প্রায় সমান, বরং নমুনা একটু দূরে। সবচেয়ে কাছের নমুনাও ১.৪৮, যেখানে একটি test ছবি ০.৮৩-এ আছে (Fashion-MNIST-এ কাছাকাছি-নকল ছবি আছে)। Test দূরত্বের নিচের ১%-এর চেয়ে কাছে মাত্র ২টি নমুনা। এই ছোট model-এ হুবহু কপির চিহ্ন পাওয়া যায়নি। তবে pixel দূরত্ব সরানো বা উল্টানো কপি ধরতে পারে না, তাই গবেষণায় feature-ভিত্তিক দূরত্বও লাগে; আর শত কোটি ছবিতে শেখানো বড় model-এর আচরণ আলাদা হতে পারে।

নিচের ব্লক run-এর আসল ছবি আঁকে (সবচেয়ে কাছের তিনটি আর মাঝামাঝি একটি নমুনা, প্রতিটির নিকটতম training ছবিসহ; ৪-bit-এ base64, প্রায় ৪ KB), আর অংশ ৪-এর “FID বনাম n”-এর আসল সংখ্যা।

import base64
import numpy as np
import matplotlib.pyplot as plt

raw = np.frombuffer(base64.b64decode(open("nn_pairs.b64").read()), np.uint8)
imgs = np.stack([raw >> 4, raw & 15], 1).reshape(8, 28, 28) / 15   # 4-bit থেকে খোলা
dist = [1.48, 1.50, 1.53, 3.56]           # run-এ মাপা L2 দূরত্ব
fig, axs = plt.subplots(2, 4, figsize=(7, 3.8))
for k in range(4):
    axs[0, k].imshow(imgs[2 * k], cmap="gray"); axs[0, k].set_title(f"sample, d={dist[k]}", fontsize=8)
    axs[1, k].imshow(imgs[2 * k + 1], cmap="gray"); axs[1, k].set_title("nearest train", fontsize=8)
for ax in axs.flat:
    ax.set_xticks([]); ax.set_yticks([])
fig.suptitle("DDPM samples (seed 7) and their nearest training images", fontsize=9)
plt.show()

n = np.array([250, 500, 1000, 2000, 5000, 10000])        # অংশ ৪-এর আসল সংখ্যা
fid = {"real train, Inception": [45.47, 28.09, 15.69, 8.14, 3.80, 2.53],
       "DDIM 50, Inception": [53.75, 37.17, 24.13, 17.14, 12.42, 11.15],
       "real train, own clf": [11.635, 5.699, 2.069, 1.657, 0.461, 0.323],
       "DDIM 50, own clf": [21.821, 15.522, 10.818, 9.668, 8.595, 8.241]}
fig, ax = plt.subplots(figsize=(6, 3.4))
for name, v in fid.items():
    ax.plot(n, v, "o-" if "Inception" in name else "s--", label=name)
    print(f"{name:22s} n=250: {v[0]:6.2f}  n=10000: {v[-1]:6.2f}  ratio {v[0] / v[-1]:5.1f}")
ax.set_xscale("log"); ax.set_xlabel("number of samples n"); ax.set_ylabel("FID vs 10k test")
ax.set_title("FID depends on n (one run each)"); ax.legend(fontsize=7)
plt.show()

আউটপুট (পাতার Python-এ চালানো; সঙ্গে দুটি ছবি):

real train, Inception  n=250:  45.47  n=10000:   2.53  ratio  18.0
DDIM 50, Inception     n=250:  53.75  n=10000:  11.15  ratio   4.8
real train, own clf    n=250:  11.63  n=10000:   0.32  ratio  36.0
DDIM 50, own clf       n=250:  21.82  n=10000:   8.24  ratio   2.6

ওপরের সারিতে সবচেয়ে কাছের তিনটি নমুনা আর মাঝামাঝি একটি (দূরত্ব ৩.৫৬), নিচের সারিতে প্রতিটির নিকটতম training ছবি। প্রথম তিনটি জোড়া (দুটি প্যান্ট আর একটি গাঢ় জামা) খুব কাছাকাছি, কিন্তু কিনারা, উজ্জ্বলতা আর ভেতরের দাগে পার্থক্য আছে; প্যান্টের মতো সরল আকারের পণ্যে ডেটাসেটের ভেতরেও এমন কাছাকাছি জোড়া স্বাভাবিক, তাই এগুলো হুবহু কপির প্রমাণ নয়। মাঝামাঝি নমুনাটি (একটি নকশাদার লম্বা হাতার জামা) তার নিকটতম training ছবি থেকে স্পষ্ট আলাদা। দ্বিতীয় ছবিতে অংশ ৪-এর আসল সংখ্যা: n = ২৫০ থেকে ১০,০০০-এ আসল ছবির FID Inception-এ প্রায় ১৮ গুণ আর classifier-এ প্রায় ৩৬ গুণ কমে, অথচ DDIM ৫০-এর FID মাত্র ৪.৮ আর ২.৬ গুণ কমে একটি স্থির মানের দিকে যায়। ছোট n-এ দুই রেখা কাছাকাছি, বড় n-এ পরিষ্কার আলাদা: কম নমুনায় পার্থক্যও ঢাকা পড়ে।

কপিরাইট আর সম্মতি: Training ডেটার অনুমতি আর generated ছবির মালিকানা নিয়ে বিভিন্ন দেশে আইন আর আদালতের অবস্থান এখনও তৈরি হচ্ছে (লেখার সময়ে, নভেম্বর ২০২৬); এই কোর্স আইনি পরামর্শ দেয় না। প্রকৌশলীর করণীয় স্পষ্ট: ডেটার উৎস আর লাইসেন্স লিখে রাখা, deduplication, memorisation যাচাই। নৈতিকতার গভীর আলোচনা পরে AI ethics কোর্সে আসবে।

৭ · Deepfake — ক্ষতি, চেনার সীমা আর প্রতিরক্ষা

Deepfake মানে AI দিয়ে তৈরি বা বদলানো ছবি, ভিডিও বা কণ্ঠ, যা আসল মানুষের মতো দেখায় বা শোনায়। এই পর্ব শুধু প্রতিরক্ষার দিক দেখে: কী ক্ষতি করে, কেন চেনা কঠিন, আর কী করবেন। তিন ধরনের ক্ষতি সবচেয়ে আলোচিত:

প্রতারণা

পরিচিত কারও নকল কণ্ঠ বা ভিডিও দিয়ে জরুরি টাকা চাওয়া। এটি পুরোনো social engineering-এর নতুন রূপ; প্রতিরক্ষা সাইবার নিরাপত্তা কোর্সের পর্ব ৫২-এ।

সম্মতিহীন অন্তরঙ্গ ছবি

কারও সাধারণ ছবি থেকে অন্তরঙ্গ নকল ছবি বানানো; ক্ষতি মানসিক ও সামাজিক, কখনো জীবনঘাতী। বড় AI সেবাগুলোর নীতিতে এটি নিষিদ্ধ (নিচের টেবিল)।

নির্বাচন আর ভুয়া তথ্য

প্রার্থীর মুখে বানানো কথা। পরোক্ষ ক্ষতি: আসল প্রমাণকেও “deepfake” বলে উড়িয়ে দেওয়া, যাকে Chesney আর Citron (২০১৯) “liar's dividend” বলেছেন।

বাংলাদেশের প্রসঙ্গ (সূত্রসহ): fact-checking প্রতিষ্ঠান Dismislab-এর ৩০ জুলাই ২০২৫-এর বিশ্লেষণ অনুযায়ী, ২০২৫-এর এপ্রিল-জুনে দেশের আটটি fact-checking সাইটে চিহ্নিত AI-তৈরি ভুয়া তথ্য প্রথমবার ছবির চেয়ে ভিডিওতে বেশি ছড়িয়েছে, আর নির্বাচন-সংক্রান্ত ভুয়া তথ্য ৭টি থেকে অন্তত ৫৫টিতে উঠেছে। আইনে, মে ২০২৫-এ জারি হওয়া সাইবার সুরক্ষা অধ্যাদেশ রহিত করে পরে সাইবার সুরক্ষা আইন, ২০২৬ (২০২৬ সনের ৮১ নং আইন) প্রণীত হয়েছে। সরকারি bdlaws.minlaw.gov.bd-এর পাতায় (লেখার সময়ে, নভেম্বর ২০২৬-এ পড়া) এর সংজ্ঞায় আর কয়েকটি অপরাধের ধারায় কৃত্রিম বুদ্ধিমত্তার উল্লেখ আছে; যেমন ধারা ২৫-এ ব্ল্যাকমেইল, যৌন হয়রানি বা sextortion-এর উদ্দেশ্যে কৃত্রিম বুদ্ধিমত্তা দিয়ে বানানো বা সম্পাদিত ছবি-ভিডিও প্রকাশ বা প্রকাশের হুমকিকে অপরাধ বলা হয়েছে। আইনটি পরে সংশোধিতও হয়েছে; ঠিক ভাষা আর বর্তমান রূপ সরকারি পাতায় দেখুন, এটি আইনি পরামর্শ নয়।

চেনা কেন কঠিন: “আঙুল বেশি” ধরনের লক্ষণ পরের প্রজন্মের model-এ মিলিয়ে যায়। Deepfake detector নিজের training-এর ধরনের generator-এ ভালো কাজ করে, নতুন generator বা compress করা ছবিতে প্রায়ই ভেঙে পড়ে, আর ভুল-ইতিবাচক নিরীহ মানুষের ক্ষতি করে। AI assistant-ও detector নয়: Claude-এর vision ডকুমেন্টেশনে লেখা আছে, Claude ছবি AI-তৈরি কি না নির্ধারণ করতে পারে না। তাই প্রতিরক্ষা কয়েক স্তরের:

বড় AI সেবাগুলো আসল মানুষের ছবি নিয়ে কী লিখেছে? শুধু প্রতিটির নিজের নথি থেকে, লেখার সময়ে (নভেম্বর ২০২৬) পড়া; পরিবর্তন হতে পারে। বাস্তবে কে কতটা মানে, তা এখানে মাপা হয়নি।

সেবানিজের নথিতে যা পেয়েছি
ChatGPT (OpenAI)Usage policies-এর নথির পাতা খোলা যায়নি (লেখার সময়ে, নভেম্বর ২০২৬)। অনুসন্ধানে দেখা একটি পুরোনো সংস্করণে কারও বাস্তবসম্মত ছবি বা কণ্ঠ সম্মতি ছাড়া এমনভাবে ব্যবহার নিষেধ ছিল, যাতে আসল-নকল গুলিয়ে যায়; বর্তমান সংস্করণে একই ভাষা আছে কি না যাচাই করতে পারিনি। মূল পাতায় মিলিয়ে নিন।
Claude (Anthropic)Docs অনুযায়ী Claude ছবি তৈরি বা সম্পাদনা করে না, ছবিতে মানুষের নাম বলে না। Usage policy (Anthropic-এর পাতায় কার্যকর হওয়ার তারিখ ১২ নভেম্বর ২০২৬ লেখা) সম্মতিহীন অন্তরঙ্গ ছবি, আসল ব্যক্তির ছদ্মবেশ আর নির্বাচনে অঘোষিত synthetic media নিষেধ করে।
Gemini (Google)Generative AI Prohibited Use Policy (শেষ পরিবর্তন ১৭ ডিসেম্বর ২০২৪) সম্মতিহীন অন্তরঙ্গ ছবি আর প্রতারণার উদ্দেশ্যে ঘোষণা ছাড়া কোনো ব্যক্তির (জীবিত বা মৃত) ছদ্মবেশ নিষেধ করে; ছবিতে SynthID যোগ হয় (অংশ ৮)। আসল মানুষের ছবি সম্পাদনার আলাদা নিয়ম নথিতে পাইনি।
Grok (xAI)Acceptable use policy-র নথির পাতা খোলা যায়নি (লেখার সময়ে, নভেম্বর ২০২৬)। অনুসন্ধানে দেখা পুরোনো সংস্করণগুলোতে (জানুয়ারি ২০২৫-এর, আর জুন ২০২৬-এ বদলানো সংস্করণে) কারও likeness অশ্লীলভাবে দেখানো নিষেধ। বর্তমান ভাষা যাচাই করতে পারিনি।
DeepSeekTerms of Use-এ কোনো ব্যক্তির ছদ্মবেশ ধরা কনটেন্ট (সম্মতি বা “parody” লেবেল ছাড়া) আর অশ্লীল কনটেন্ট নিষেধ; ছবি তৈরির সুবিধার কথা নথিতে পাইনি।
Kimi (Moonshot AI)Terms of Service (হালনাগাদ ৫ নভেম্বর ২০২৬): input যেন কারও portrait rights লঙ্ঘন না করে, ছদ্মবেশ আর অশ্লীল কনটেন্ট নিষেধ; তৈরি কনটেন্টে দৃশ্যমান ও অদৃশ্য চিহ্ন যোগ হয়, ব্যবহারকারী তা সরাতে পারবেন না। ছবি তৈরির সুবিধার বিবরণ নথিতে পাইনি।

৮ · Provenance আর watermark — C2PA, SynthID আর একটি সত্যিকারের পরীক্ষা

দুটি পথ: ছবির সঙ্গে স্বাক্ষরিত উৎস-তথ্য রাখা (provenance), আর pixel-এর ভেতরেই অদৃশ্য চিহ্ন বসানো (watermark).

C2PA আর Content Credentials: Coalition for Content Provenance and Authenticity-র খোলা মান (লেখার সময়ে, নভেম্বর ২০২৬, সাইটে সংস্করণ ২.৫)। ছবির সঙ্গে একটি “manifest” থাকে: কয়েকটি দাবি (কোন ক্যামেরা বা AI tool, কী সম্পাদনা) আর একটি digital signature. ছবির byte-এর একটি hash manifest-এ বাঁধা থাকে (“hard binding”), তাই ছবির এক bit বদলালেও যাচাই ভেঙে যায়। Hash আর signature-এর ভিত্তি সাইবার নিরাপত্তা কোর্সের পর্ব ৯ আর পর্ব ১১-এ। সীমা: অনেক প্ল্যাটফর্ম আপলোডে metadata মুছে ফেলে, তখন manifest হারায়; এজন্য মানে “soft binding” আছে, invisible watermark বা fingerprint দিয়ে হারানো manifest খুঁজে পাওয়ার ব্যবস্থা। আর C2PA বলে কে, কোন tool দিয়ে, কী করেছে; বিষয়বস্তু সত্য কি না, তা নয়।

SynthID: Google DeepMind-এর SynthID Google-এর AI দিয়ে তৈরি ছবি, ভিডিও, অডিও আর লেখায় অদৃশ্য watermark বসায়। Google-এর পাতায় (নভেম্বর ২০২৬-এ পড়া) লেখা, ছবির watermark crop, filter আর lossy compression সহ্য করার জন্য নকশা করা, আর SynthID Detector পোর্টালে যাচাই করা যায়। এটি নকশার লক্ষ্য, নিশ্চয়তা নয়; watermark না পাওয়া মানে শুধু “এই watermark নেই”. SynthID Text খোলা উৎস, তবে নতুন করে লেখা বা অনুবাদ করা লেখায় detector-এর আত্মবিশ্বাস অনেক কমতে পারে বলে Google-এর docs জানায়।

সবচেয়ে সহজ ধারণা spread-spectrum watermark (ভিত্তি হিসেবে Cox ও সহকর্মীদের ১৯৯৭-এর কাজ পরিচিত): গোপন চাবি থেকে ±১-এর এলোমেলো প্যাটার্ন w বানিয়ে x' = x + α·w, প্রতিটি pixel মাত্র α (যেমন ১ বা ২) বদলায়। যাচাইয়ে ছবি আর প্যাটার্নের correlation: ছবির নিজস্ব অংশ গড়ে শূন্যের কাছে, watermark প্রতিটি pixel-এ α·w·w = α যোগ করে, আর N pixel-এ সংকেত √N অনুপাতে শক্ত হয়।

x = (100, 102, 101, 99, 100, 98, 101, 99) · c(v) = mean((v − v̄) · w) · সীমা α/2 = 1.5
ধাপ
হিসাব
মানে
  1. চাবি. ±১-এর প্যাটার্ন, গড় শূন্য। গড় শূন্য বলে ছবির গড় উজ্জ্বলতা বদলায় না।
  2. বসানো. প্রতিটি pixel-এ ৩ যোগ বা বিয়োগ। ০ থেকে ২৫৫-এর মাপে এটি প্রায় অদৃশ্য।
  3. চিহ্ন ছাড়া. আসল ছবি আর চাবির correlation −০.৫: ছবির নিজস্ব ওঠানামা থেকে আসা ছোট একটি এলোমেলো সংখ্যা, সীমা ১.৫-এর নিচে।
  4. চিহ্নসহ. (v − v̄)·w-তে watermark-এর অংশ ৩·w·w = ৩, তাই correlation ঠিক ৩ বাড়ে: ২.৫, সীমার ওপরে।
  5. Noise-এর পরে. Noise-এর নিজের correlation −০.৭৫, তাই ১.৭৫: এখনও ধরা পড়ে। Noise আরও বড় হলে মাত্র ৮ pixel-এ ভুল হতো; হাজার হাজার pixel-এ এলোমেলো অংশ গড়ে কাটাকাটি হয়, সংকেত টেকে।

নিচের ব্লক একই ধারণা ৬৪ × ৬৪-এর খেলনা পণ্যের ছবিতে চালায়। যাচাইয়ের আগে ছবি থেকে তার ৩ × ৩ গড় বাদ দেওয়া হয় (high-pass), যাতে মসৃণ অংশ correlation নষ্ট না করে; ফল একটি z-score, চিহ্ন না থাকলে মোটামুটি standard normal. সীমা z > ৪.

import numpy as np

rng = np.random.default_rng(42)
yy, xx = np.mgrid[0:64, 0:64]                 # ছোট "পণ্যের ছবি": হালকা পটভূমিতে একটি গাঢ় ব্যাগ
img = np.where((abs(xx - 32) < 16) & (abs(yy - 36) < 14), 70.0, 225.0)
img += 8 * np.sin(xx / 5) + rng.normal(0, 2, img.shape)          # একটু টেক্সচার

key = np.random.default_rng(2026).choice([-1.0, 1.0], img.shape)  # গোপন চাবি: ±1 প্যাটার্ন
alpha = 2.0
marked = np.clip(img + alpha * key, 0, 255)
print(f"max pixel change {np.abs(marked - img).max():.1f} of 255, "
      f"PSNR {10 * np.log10(255**2 / np.mean((marked - img)**2)):.1f} dB")

def highpass(v):                              # ৩×৩ গড় বাদ: মসৃণ ছবি সরে, প্যাটার্ন থাকে
    p = np.pad(v, 1, mode="edge")
    box = sum(p[i:i + 64, j:j + 64] for i in range(3) for j in range(3)) / 9
    return v - box
def z_score(v, k):                            # correlation, noise-এর মাপে ভাগ
    h = highpass(v)
    return float((h * k).sum() / (h.std() * np.sqrt(h.size)))

print("noise sd | z (marked) | z (no mark) | detected (z > 4)?")
for sd in [0, 5, 10, 20, 40]:
    n = np.random.default_rng(sd).normal(0, sd, img.shape)
    zm, zu = z_score(marked + n, key), z_score(img + n, key)
    print(f"{sd:8d} | {zm:10.2f} | {zu:11.2f} | {zm > 4} / {zu > 4}")
wrong = [z_score(marked, np.random.default_rng(s).choice([-1.0, 1.0], img.shape)) for s in range(200)]
print(f"200 wrong keys on the marked image: max |z| = {np.max(np.abs(wrong)):.2f}")

আউটপুট (পাতার Python-এ চালানো):

max pixel change 2.0 of 255, PSNR 42.1 dB
noise sd | z (marked) | z (no mark) | detected (z > 4)?
       0 |       8.71 |       -0.32 | True / False
       5 |       8.15 |       -0.36 | True / False
      10 |       6.85 |       -0.37 | True / False
      20 |       4.98 |       -0.01 | True / False
      40 |       3.08 |        0.18 | False / False
200 wrong keys on the marked image: max |z| = 2.49

সর্বোচ্চ পরিবর্তন ২ মাত্রা, PSNR প্রায় ৪২ dB: চোখে প্রায় অদৃশ্য। Noise ছাড়া z ≈ ৮.৭; noise-এর standard deviation ২০ পর্যন্ত (watermark-এর ১০ গুণ!) ধরা পড়ে, ৪০-এ আর না, কারণ মাত্র ৪০৯৬ pixel. চিহ্নহীন ছবি কখনো “আছে” বলেনি, আর ভুল চাবির ২০০টি চেষ্টায় সর্বোচ্চ |z| ২.৪৯. চাবি ছাড়া কেউ যাচাই করতে পারে না: জাল করা কঠিন, কিন্তু সাধারণ মানুষও নিজে যাচাই করতে পারে না।

এবার ডেস্কটপে একটি খোলা library: invisible-watermark 0.2.0 (PyPI-তে MIT লাইসেন্স; README নিজেই একে “experimental” বলে), যা ৩২-bit বার্তা ছবির রঙের অংশে DWT-DCT পদ্ধতিতে বসায়; Stable Diffusion-এর প্রথম দিকের reference script এটি ব্যবহার করত বলে জানা যায়। পাশে নিজের spread-spectrum, α = ১, high-pass করে correlation. ছবি: Fashion-MNIST-এর ১০০টি test ছবি ২৫৬ × ২৫৬-এ বড় করে, প্রতিটি পণ্যকে একটি এলোমেলো রঙে, হালকা ধূসর পটভূমিতে; আসল দোকানের ছবি নয়। আক্রমণ OpenCV দিয়ে, CPU-তে (opencv-python-headless 5.0). “bit acc” = ৩২টি bit-এর কত ভাগ ঠিক; এলোমেলো অনুমানে প্রায় ০.৫.

~/bazarghar-dl$ uv run python wm.py
invisible-watermark dwtDct: embed 5.2 ms/image, mean PSNR 41.5 dB
attack                           mean bit acc all 32 bits >= 29 bits
none                                    0.916        0.55       0.67
JPEG q90                                0.602        0.00       0.00
JPEG q75                                0.588        0.00       0.00
JPEG q50                                0.582        0.00       0.00
JPEG q75, no chroma subsampling         0.664        0.00       0.05
resize 50% and back                     0.922        0.55       0.69
crop 10% each side                      0.500        0.00       0.00
noise sd 5                              0.902        0.47       0.61
brightness +20                          0.724        0.01       0.16
no watermark (FP)                       0.579        0.00       0.00

own spread-spectrum (alpha 1.0, threshold z > 4.0): mean PSNR 48.1 dB
attack                            median z  detected
none                                147.90      1.00
JPEG q90                             35.33      1.00
JPEG q75                             10.02      1.00
JPEG q50                              5.80      0.83
JPEG q75, no chroma subsampling       9.79      1.00
resize 50% and back                  31.93      1.00
crop 10% each side                    0.79      0.00
noise sd 5                           76.22      1.00
brightness +20                      147.90      1.00
no watermark (FP)                     0.06      0.00   (900 image-attack pairs, max |z| 2.87)

Library-র dwtDct আক্রমণ ছাড়াই মাত্র ৫৫% ছবিতে ৩২টি bit-ই ঠিক পড়ে (বড় সমতল পটভূমির এই ছবিতে), আর JPEG-এ (q৯০-ও) গড় bit acc ০.৫৮-০.৬০, watermark-হীন ছবির ০.৫৭৯-এর সমান: কার্যত মুছে গেছে। JPEG-এর chroma subsampling বন্ধ করলেও ০.৬৬৪, তাই শুধু সেটাই কারণ নয়। নিজের spread-spectrum JPEG q৭৫ (z-এর median ১০.০২) আর অর্ধেক resize-এ ১০০টিতেই ধরা পড়ে, q৫০-এ ৮৩%. কিন্তু চার পাশ থেকে ১০% crop করলেই দুটি পদ্ধতিই পুরো ব্যর্থ: প্যাটার্ন আর ছবির grid এক ঘরও সরে গেলে correlation শূন্যে নামে। ৯০০টি চিহ্নহীন ছবি-আক্রমণ জোড়ায় একটিও ভুল-ইতিবাচক নেই (সর্বোচ্চ |z| ২.৮৭)। শিক্ষা: watermark-এর “robust” দাবি কোন আক্রমণে, কোন ছবিতে, কত শতাংশ, তা নিজে মাপুন; crop, rotate আর নতুন করে আঁকানোর বিরুদ্ধে সরল watermark দুর্বল। এটি একটি ছোট স্থানীয় পরীক্ষা; SynthID-এর মতো শেখা watermark এসব আক্রমণ সামলানোর চেষ্টা করে, যা এখানে মাপা হয়নি।

৯ · সীমা, সাধারণ ভুল আর ভালো প্রতিবেদন

একই শর্ত, নইলে তুলনা নয়

একই reference, n, feature extractor, resize আর library. শুধু resize-এর পার্থক্যে FID কয়েক একক বদলাতে পারে বলে Parmar ও সহকর্মীরা (২০২২) দেখান।

Seed আর ওঠানামা

পর্ব ৭৯-এর একই model-এ seed বদলালে FID(clf) ৫.৪৯ থেকে ৬.৬০. কয়েকটি seed-এর গড় আর পরিসর দিন; ০.৫-এর পার্থক্যে “ভালো” দাবি করবেন না।

Feature-এর পক্ষপাত

Kynkäänniemi ও সহকর্মীরা (২০২৩) দেখান, Inception feature ImageNet-এর class-এর দিকে ঝোঁকে, তাই ছবির মান না বাড়িয়েও FID কমানো যায়। Stein ও সহকর্মীরা (২০২৩) মানুষের বিচারের সঙ্গে মিলের জন্য DINOv2-এর মতো self-supervised feature প্রস্তাব করেন।

নিরাপত্তা একক নয়

Detector, watermark আর C2PA প্রতিটিরই ব্যর্থতা আছে; কয়েক স্তর একসঙ্গে, সঙ্গে মানুষের সচেতনতা।

আরও গভীরে: Fréchet distance দুটি Gaussian-এর মধ্যে optimal transport-এর 2-Wasserstein দূরত্বের বর্গের সমান (Dowson আর Landau, ১৯৮২; Olkin আর Pukelsheim, ১৯৮২)। KID (Bińkowski ও সহকর্মী, ২০১৮) একটি polynomial kernel-এর maximum mean discrepancy, যার অনুমান পক্ষপাতহীন, তাই ছোট n-এ তুলনায় নিরাপদ। Watermark-এ robustness, ধারণক্ষমতা আর অদৃশ্যতা পরস্পরের বিপরীতে টানে; Zhang ও সহকর্মীরা (২০২৪) যুক্তি দেন, শক্তিশালী আক্রমণকারীর বিরুদ্ধে মুছে-ফেলা-অসম্ভব watermark তাত্ত্বিকভাবেই কঠিন।

পরীক্ষা ও ইন্টারভিউতে:

  • আসল N(৪, ৩2), নকল N(১, ১2)-এর Fréchet distance? (৪ − ১)2 + (৩ − ১)2 = ৯ + ৪ = ১৩.
  • FID আর IS-এর মূল পার্থক্য? IS আসল ডেটা দেখে না, শুধু classifier-এর আত্মবিশ্বাস আর class-এর বৈচিত্র্য; FID আসল আর নকলের feature distribution তুলনা করে।
  • ১০০০ নমুনার FID কেন ১০,০০০ নমুনার চেয়ে বেশি আসে? μ আর Σ-এর অনুমানের ভুল সূত্রে যোগ হয়, পক্ষপাত প্রায় ১/n.
  • Precision কম, recall বেশি মানে? সব ধরন আসে কিন্তু অনেক নমুনা অবাস্তব (ঝাপসা); উল্টোটা হলে mode বাদ পড়া।
  • CLIP score-এর একক মান কেন অর্থহীন? Model, prompt আর preprocessing-এ মান বদলায়; noise-এর ছবিও প্রায় ১৮ পেতে পারে।

১০ · AI-এর যুগে — মূল্যায়নের কোডে আর নিরাপত্তার দাবিতে AI-এর ভুল

AI assistant কয়েক লাইনে FID-এর কোড দেয়, আর তা চলেও; ভুল শর্তে বের হওয়া সংখ্যাও দেখতে স্বাভাবিক। “এই ছবি AI-এর কি না” প্রশ্নেও ভিত্তিহীন আত্মবিশ্বাসী উত্তর আসতে পারে। সাধারণ ভুলগুলো:

AI প্রায়ই যা করেকেন সমস্যাকীভাবে ধরবেন
ভুল পরিসরে ছবি দেয় ([−১, ১] বনাম [০, ১]), বা ধূসর ছবিকে ৩ channel-এ নিতে ভোলেFID অর্থহীন কিন্তু চলেDocs-এ input-এর পরিসর দেখুন; train বনাম test FID ছোট আসে কি না দেখুন
ভিন্ন n বা ভিন্ন reference-এর FID তুলনা করেপক্ষপাত ১/n, তুলনা অন্যায্যএকই n, একই reference, কয়েকটি seed
পুরোনো বা বানানো API (যেমন scipy-র sqrtm-এর বাদ দেওয়া argument)Error, বা নীরবে অন্য ফলনিজের version-এর docs দেখুন, ছোট batch-এ চালান
Test সেট দিয়ে generator বাছাই করে আবার সেই test-এই FID দেয়Test ডেটা ফাঁস, ফল আশাবাদীবাছাইয়ের জন্য আলাদা validation সেট
“এই ছবি ৯৫% AI-তৈরি” ধরনের উত্তর দেয়বেশির ভাগ assistant detector নয়; ভুল অভিযোগ কারও ক্ষতি করেProvenance, উৎস আর অন্য পথে যাচাই; assistant-এর নিজের docs-এ সীমা পড়ুন
Watermark-কে “মুছে ফেলা যায় না” বলেCrop বা নতুন করে আঁকায় বহু watermark যায়নিজের আক্রমণ-তালিকায় detection হার মাপুন

AI-কে কোডের সঙ্গে যাচাইয়ের উপায়ও চাইতে বলুন:

আমি ২৮ × ২৮ ধূসর ছবির একটি generative model-এর FID মাপতে চাই। আমার torch, torchvision আর pytorch-fid-এর version নিচে দিলাম। ১. ছবিকে কোন পরিসরে, কোন আকারে আর কত channel-এ feature extractor-এ দিতে হবে, docs-এর কোন অংশ থেকে বলছ তা লেখো। ২. FID-এর সূত্রটি কোডের পাশে মন্তব্যে লেখো, আর matrix square root-এ complex মান এলে কী করছ বলো। ৩. Train-এর আসল ছবি বনাম test-এর আসল ছবির FID বের করার একটি sanity check দাও। ৪. ২৫০, ১০০০ আর ৫০০০ নমুনায় FID মেপে পক্ষপাত দেখানোর কোড দাও। ৫. কোনো API বা argument সম্পর্কে নিশ্চিত না হলে স্পষ্ট বলো; বানিয়ে লিখো না।

মূল্যায়ন আর নিরাপত্তার দাবি — যাচাইয়ের চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১Inception Score থেকে FID — একটি মাপকাঠি কেন জনপ্রিয় হয়, আর কেন তার সমালোচনাও বাড়ে?

২০১৬ সালে Tim Salimans ও সহকর্মীরা GAN-এর training উন্নত করার একটি প্রবন্ধে Inception Score প্রস্তাব করেন। GAN likelihood দেয় না, মানুষ দিয়ে হাজার ছবি দেখানো ধীর; classifier-এর আত্মবিশ্বাস আর class-এর বৈচিত্র্য থেকে একটি সংখ্যা মানুষের বিচারের সঙ্গে মোটামুটি মেলে বলে তাঁরা দেখান।

কিন্তু দুর্বলতা দ্রুত চোখে পড়ে। Barratt আর Sharma (২০১৮) দেখান, IS-এর মান Inception network-এর কোন implementation, কোন weight ব্যবহার হলো তার ওপর বেশ নির্ভর করে, আর ImageNet ছাড়া অন্য ডেটায় এর অর্থ অস্পষ্ট। সবচেয়ে বড় সমস্যা: IS আসল ডেটার দিকে তাকায় না, তাই প্রতিটি class-এর একটি করে ছবি বারবার বানালেও স্কোর ভালো আসে।

Martin Heusel ও সহকর্মীরা ২০১৭ সালে GAN training-এর আরেকটি প্রবন্ধে (two time-scale update rule) FID প্রস্তাব করেন। FID আসল আর নকল দুটিকেই একই feature-এ নিয়ে তুলনা করে, তাই mode বাদ পড়লে বা ছবি বিকৃত হলে মান বাড়ে; তাঁরা দেখান noise, blur আর নানা বিকৃতিতে FID নিয়মিত বাড়ে। কয়েক বছরের মধ্যে এটি কার্যত মানদণ্ড হয়ে যায়।

জনপ্রিয়তার সঙ্গেই সমালোচনা বাড়ে, কারণ সবাই যখন একটি সংখ্যা কমাতে প্রতিযোগিতা করে, তখন সেই সংখ্যার ফাঁকগুলোও কাজে লাগে। নমুনা-সংখ্যার পক্ষপাত (Bińkowski ও সহকর্মী ২০১৮; Chong আর Forsyth ২০২০), resize আর library-র পার্থক্যে মান বদলানো (Parmar ও সহকর্মী ২০২২), আর Inception feature ImageNet class-এর দিকে ঝোঁকে বলে ছবি না বদলেও FID কমানো যায় (Kynkäänniemi ও সহকর্মী ২০২৩), সবই এসেছে। Stein ও সহকর্মীরা (২০২৩) বড় মানব-মূল্যায়ন করে দেখান, আধুনিক diffusion model-এর ক্ষেত্রে Inception-ভিত্তিক মাপ মানুষের পছন্দের সঙ্গে প্রায়ই মেলে না। এটি Goodhart's law-এর পরিচিত গল্প: মাপকাঠি লক্ষ্য হয়ে গেলে আর ভালো মাপকাঠি থাকে না।

মূল উপলব্ধি: FID IS-এর বড় ফাঁক (আসল ডেটা না দেখা) বন্ধ করেছিল বলে জনপ্রিয় হয়; কিন্তু একটি সংখ্যা, একটি feature extractor আর নির্দিষ্ট n-এর ওপর নির্ভরতা মনে রেখে, অন্য মাপ আর মানুষের বিচারের পাশে ব্যবহার করতে হয়।

প্র ০২মান বনাম বৈচিত্র্য — truncation trick আর guidance কেন precision আর recall-কে উল্টো দিকে টানে?

Generative model-এ প্রায় সবসময় একটি নিয়ন্ত্রণ-চাকা থাকে যা “নিরাপদ” আর “সাহসী” নমুনার মধ্যে ভারসাম্য ঠিক করে। BigGAN (Brock ও সহকর্মী, ২০১৯) আর StyleGAN-এ এটি truncation trick: latent vector-কে গড়ের কাছাকাছি টেনে আনলে প্রতিটি ছবি বেশি নিখুঁত হয়, কিন্তু সবগুলো একে অপরের মতো হয়ে যায়। Diffusion-এ একই কাজ করে classifier-free guidance-এর মাপ (পর্ব ৮০-এর বিষয়): বেশি guidance-এ ছবি prompt বেশি মানে, স্পষ্ট হয়, কিন্তু বৈচিত্র্য কমে।

Mehdi Sajjadi ও সহকর্মীরা (২০১৮) প্রথম দেখান যে generative model-এর জন্য precision আর recall আলাদা করে মাপা যায়: precision প্রশ্ন করে “নকলগুলো আসলের এলাকায় আছে কি না”, recall প্রশ্ন করে “আসলের সব এলাকা নকল দিয়ে ঢাকা কি না”। Tuomas Kynkäänniemi ও সহকর্মীরা (২০১৯) এটিকে k-nearest-neighbour বলের মিলন দিয়ে সরল আর স্থির করেন, আর দেখান truncation বাড়ালে precision বাড়ে, recall কমে, একটি স্পষ্ট বাঁকা রেখায়।

এর ব্যবহারিক মূল্য বড়। বাজারঘরের একটি পণ্য-ছবির generator ধরুন, যা বিজ্ঞাপনের ছবি বানায়। বিজ্ঞাপনে প্রতিটি ছবি নিখুঁত হওয়া জরুরি, বৈচিত্র্য কম হলেও চলে: precision অগ্রাধিকার। কিন্তু একই model দিয়ে একটি classifier-এর জন্য synthetic training ডেটা বানালে বৈচিত্র্যই আসল; সব ধরনের জুতো না এলে classifier দুর্বল হবে: recall অগ্রাধিকার। একই model, একই FID, কিন্তু কাজভেদে আলাদা সেটিং।

সীমাও আছে। k-NN বল outlier-এ ফুলে যায়, তাই Naeem ও সহকর্মীরা (২০২০) density আর coverage প্রস্তাব করেন; আর সব মাপই feature extractor-এর চোখ দিয়ে দেখে।

মূল উপলব্ধি: মান আর বৈচিত্র্য সাধারণত পরস্পরের বিপরীতে টানে; FID সেই টানাটানি একটি সংখ্যায় লুকায়, precision আর recall তা দেখায়, আর কাজের প্রয়োজন ঠিক করে কোন দিকে ঝুঁকবেন।

প্র ০৩Generative model কি training ডেটা “মনে রাখে”? Memorisation, গোপনীয়তা আর কপিরাইটের প্রশ্ন

Generative model-এর প্রতিশ্রুতি হলো নতুন নমুনা, কিন্তু ভালোভাবে training-এর ডেটা মেলাতে গিয়ে model কিছু উদাহরণ প্রায় হুবহু মুখস্থও করতে পারে। ভাষার model-এ Nicholas Carlini ও সহকর্মীরা ২০২১ সালে দেখান, GPT-2 থেকে training ডেটার কিছু অংশ, এমনকি ব্যক্তিগত তথ্যসহ, হুবহু বের করা যায়। ২০২৩ সালে তাঁরা একই প্রশ্ন diffusion model-এ তোলেন: অনেক prompt দিয়ে অনেক ছবি বানিয়ে training ছবির সঙ্গে মিলিয়ে, Stable Diffusion আর Imagen-এর মতো model থেকে এক হাজারের বেশি training ছবি প্রায় হুবহু বের করার কথা জানান। একই বছরে Gowthami Somepalli ও সহকর্মীরা দেখান, কিছু generated ছবি training ছবির অংশ বা গঠন প্রায় কপি করে।

দুটি গবেষণাতেই একটি প্যাটার্ন স্পষ্ট: যে ছবি training ডেটায় বহুবার আছে, সেটিই বেশি মুখস্থ হয়। এজন্য deduplication একটি প্রধান প্রতিরক্ষা; আরেকটি differential privacy, যা প্রতিটি উদাহরণের প্রভাব সীমিত রাখে, মানের দামে। আমাদের ছোট DDPM-এ pixel-দূরত্বের যাচাই কোনো কপি দেখায়নি, কিন্তু তা থেকে বড় model সম্পর্কে কিছু বলা যায় না।

গোপনীয়তার দিক সরাসরি: হাসপাতালের স্ক্যান বা মানুষের মুখে শেখানো model যদি কোনো ছবি ফিরিয়ে দেয়, তা ব্যক্তিগত তথ্য ফাঁস। কপিরাইটের দিক জটিল: শিল্পী, আলোকচিত্রী আর সংবাদ প্রতিষ্ঠান প্রশ্ন তুলেছেন, অনুমতি ছাড়া তাঁদের কাজে শেখানো আর প্রায়-নকল তৈরি বৈধ কি না। কয়েকটি দেশে মামলা চলছে; লেখার সময়ে বিষয়টি নিষ্পত্তি হয়নি বলেই ধরে নিন।

প্রকৌশলীর দিক থেকে কিছু কাজ আইনি সিদ্ধান্তের অপেক্ষা ছাড়াই করা যায়: ডেটার উৎস আর লাইসেন্স লিখে রাখা, ডুপ্লিকেট সরানো, generated নমুনা আর training ডেটার nearest-neighbour যাচাই, আর মুখের মতো সংবেদনশীল ডেটায় সম্মতি নিশ্চিত করা।

মূল উপলব্ধি: Memorisation মাপা যায় আর কমানো যায়; বহুবার থাকা ডেটা বেশি মুখস্থ হয়, আর গোপনীয়তা ও কপিরাইটের প্রশ্ন শুধু আইনের নয়, ডেটা বাছাইয়ের প্রকৌশলেরও।

প্র ০৪Detector, watermark না provenance — নকল ছবির বিরুদ্ধে কোন পথ কতটা ভরসার?

প্রথম পথ detector: আসল আর AI-তৈরি ছবি দিয়ে একটি classifier শেখানো। এটি সহজ শোনায়, কিন্তু এটি একটি অসম লড়াই। Detector যে generator-এর ছবিতে শিখেছে, নতুন generator-এর ছবিতে প্রায়ই ভেঙে পড়ে; ছবি compress করলে বা ছোট করলে সূক্ষ্ম চিহ্ন হারায়; আর ভুল-ইতিবাচক কোনো নিরীহ মানুষের আসল ছবিকে “নকল” বলে দিতে পারে।

দ্বিতীয় পথ watermark: তৈরির মুহূর্তেই ছবির ভেতরে চিহ্ন বসানো। Ingemar Cox ও সহকর্মীদের ১৯৯৭ সালের spread-spectrum কাজ থেকে শুরু করে দীর্ঘ গবেষণা আছে। সুবিধা: চিহ্ন pixel-এর ভেতরে, তাই metadata মুছলেও থাকে। সীমা আমাদের পরীক্ষাতেই দেখা গেল: crop-এ সরল watermark পুরো হারায়, আর একটি open-source পদ্ধতি JPEG-এ টেকেনি। আর নিজের কম্পিউটারে চালানো খোলা model watermark বসাতে বাধ্য নয়।

তৃতীয় পথ provenance: Adobe, Microsoft, BBC আর অন্যরা মিলে ২০২১ সালে C2PA গঠন করে। এখানে প্রশ্ন উল্টানো: “এটা নকল কি না” নয়, “এটা কোথা থেকে এসেছে, কে স্বাক্ষর করেছে”। ক্যামেরা ছবি তোলার মুহূর্তে স্বাক্ষর করতে পারে, সম্পাদনার প্রতিটি ধাপ যোগ হয়। সীমা: সব ডিভাইস আর প্ল্যাটফর্ম এটি সমর্থন করে না, অনেক প্ল্যাটফর্ম metadata মুছে ফেলে, আর স্বাক্ষর বলে কে বানিয়েছে, বিষয়বস্তু সত্য কি না নয়।

তাই তিনটি পথ পরস্পরের পরিপূরক। Watermark দিয়ে হারানো C2PA manifest খুঁজে পাওয়া যায় (spec-এর soft binding), detector সন্দেহজনক ক্ষেত্রে সংকেত দেয়, আর শেষে মানুষের উৎস-যাচাই আর মিডিয়া সাক্ষরতা। আরেকটি সামাজিক দিক: সবাই যখন জানে নকল সম্ভব, তখন আসল প্রমাণকেও “AI-এর বানানো” বলে অস্বীকার করা সহজ হয়; Chesney আর Citron একে liar's dividend বলেছেন। Provenance-এর বড় সুবিধা এখানেই: আসলকে আসল প্রমাণের একটি উপায় দেয়।

মূল উপলব্ধি: কোনো একক প্রযুক্তি deepfake সমস্যার সমাধান নয়; detector অনুমান করে, watermark চিহ্ন রাখে, provenance উৎস দেখায়, আর তিনটির ফাঁক ঢাকে মানুষের সতর্ক যাচাই।

প্র ০৫CLIP score আর মানুষের মূল্যায়ন — স্বয়ংক্রিয় মাপ কি কখনো মানুষের বিচারের জায়গা নিতে পারে?

Text-to-image model আসার পর প্রশ্ন দাঁড়াল: ছবি শুধু বাস্তব হলেই হবে না, prompt-ও মানতে হবে। ২০২১ সালে OpenAI-এর Alec Radford ও সহকর্মীরা CLIP প্রকাশ করেন, যা ছবি আর লেখাকে একই vector-জায়গায় আনে। একই বছরে Jack Hessel ও সহকর্মীরা CLIPScore প্রস্তাব করেন, মূলত image captioning মূল্যায়নের জন্য, আর দেখান এটি reference caption ছাড়াই মানুষের বিচারের সঙ্গে ভালোভাবে মেলে। শিগগিরই text-to-image প্রবন্ধে FID-এর পাশে CLIP score দেওয়া প্রচলিত হয়।

কিন্তু CLIP-এর নিজের দুর্বলতা মাপকাঠিতে ঢোকে। Yuksekgonul ও সহকর্মীরা (২০২৩) দেখান, CLIP-এর মতো model অনেক সময় শব্দের ক্রম আর সম্পর্ক তেমন বোঝে না, “ঘোড়া মানুষের ওপর” আর “মানুষ ঘোড়ার ওপর” প্রায় একই রকম দেখে। গণনা, স্থানিক সম্পর্ক আর লেখা-ছবির খুঁটিনাটিতে দুর্বলতা আছে। আর আমাদের ছোট run দেখাল, এলোমেলো noise-ও প্রায় ১৮ পায়, তাই একক মান অর্থহীন। যে generator CLIP-এর সংকেত দিয়ে guide করা, সে CLIP-কে খুশি করতে শেখে, মানুষকে নয়।

মানুষের মূল্যায়নেরও নিজস্ব কৌশল আছে। দুটি ছবি পাশাপাশি দেখিয়ে পছন্দ জিজ্ঞেস করা (pairwise comparison) সাধারণত ১ থেকে ৫ রেটিংয়ের চেয়ে স্থির; Zhou ও সহকর্মীদের HYPE (২০১৯) মানুষকে অল্প সময় ছবি দেখিয়ে আসল-নকল চেনার হার মাপার একটি নিয়ন্ত্রিত পদ্ধতি দেয়। কিন্তু খরচ, সময়, মূল্যায়নকারীর সংস্কৃতি আর নির্দেশনার ভাষা ফলকে প্রভাবিত করে।

তাই বাস্তব কৌশল একটি স্তরভিত্তিক পদ্ধতি: প্রতিদিনের পরীক্ষায় দ্রুত স্বয়ংক্রিয় মাপ (FID, precision/recall, CLIP score) দিয়ে খারাপ সংস্করণ বাদ দেওয়া, আর বড় সিদ্ধান্তের আগে লক্ষ্য-ব্যবহারকারীদের নিয়ে ছোট কিন্তু যত্নশীল মানব-মূল্যায়ন। স্বয়ংক্রিয় মাপ মানুষের বিচারের ছাঁকনি, বিকল্প নয়।

মূল উপলব্ধি: CLIP score prompt-মানা মাপার সস্তা আর কাজের উপায়, কিন্তু CLIP-এর নিজের দুর্বলতা বহন করে; শেষ বিচার এখনও লক্ষ্য-ব্যবহারকারীদের নিয়ে সঠিকভাবে নকশা করা মানব-মূল্যায়ন।

অনুশীলন

প্রথমে খাতায় করুন, তারপর উত্তর মেলান। পাতার ব্লক বদলে নিজের সংখ্যাও যাচাই করতে পারেন।

  1. পূর্ণ numerical: (ক) আসল feature-এর distribution μ1 = (২, ০), Σ1 = diag(৯, ৪); নকলের μ2 = (০, ১), Σ2 = diag(১, ৪). Fréchet distance d2 কত? কোন অংশ গড় থেকে, কোন অংশ ছড়ানো থেকে? (খ) একটি ছবির embedding (৩, ৪) আর একটি caption-এর (৪, ৩)। CLIP score কত? Caption (−৩, ৪) হলে?

    (ক) গড়ের পদ: (২ − ০)2 + (০ − ১)2 = ৪ + ১ = ৫. Diagonal, তাই ছড়ানোর পদ প্রতিটি মাত্রায় (σ1 − σ2)2: (৩ − ১)2 + (২ − ২)2 = ৪. সূত্র দিয়েও: Tr = ৯ + ৪ + ১ + ৪ = ১৮, (Σ1Σ2)½ = diag(৩, ৪), ১৮ − ২ × ৭ = ৪. মোট d2 = ৯: ৫ গড় থেকে, ৪ প্রথম মাত্রার ছড়ানো থেকে (নকল ছবি সেই দিকে কম বৈচিত্র্যময়)।

    (খ) Dot = ২৪, দুই দৈর্ঘ্যই ৫, cos = ০.৯৬, CLIP score = ৯৬ (খেলনা সংখ্যা)। (−৩, ৪)-এর সঙ্গে dot = −১২ + ১৬ = ৪, cos = ৪ ÷ ২৫ = ০.১৬, score ১৬.

  2. সমালোচনা ও নকশা: সহকর্মী বললেন: “নতুন generator B-এর FID ১২.১, পুরোনো A-এর ১২.৮; তাই B চালু।” পরে জানা গেল, A মাপা হয়েছিল ৫০০০ নমুনায় torchmetrics দিয়ে, B ১০০০ নমুনায় pytorch-fid দিয়ে, প্রতিটি একটি seed-এ, আর B-এর prompt-গুলো test সেট দেখে বাছা। সমস্যা কী, আর ন্যায্য তুলনা কীভাবে?

    সমস্যা: (১) n আলাদা: ১০০০ নমুনার FID পক্ষপাতে বেশি আসে, তাই আসলে B হয়তো আরও ভালো, বা নয়; তুলনাই চলে না। (২) Library আলাদা: resize আর preprocessing-এর পার্থক্যে কয়েক একক বদলাতে পারে। (৩) একটি seed: ০.৭-এর পার্থক্য seed-এর ওঠানামার মধ্যেই থাকতে পারে (পর্ব ৭৯-এর run-এ একই model-এ ৫.৪৯ থেকে ৬.৬০)। (৪) Test দেখে prompt বাছাই মানে test ডেটা ফাঁস।

    ন্যায্য নকশা: একই library, reference আর n (যেমন ১০,০০০), অন্তত তিনটি seed-এর গড় ও পরিসর; prompt বাছাই আলাদা validation সেটে; পাশে precision/recall, CLIP score, ছোট মানব-মূল্যায়ন আর memorisation যাচাই।

  3. আউটপুট অনুমান করুন: নিচের কোড কী ছাপবে?
    import numpy as np
    m1, s1, m2, s2 = 4.0, 3.0, 1.0, 1.0
    print((m1 - m2)**2 + s1**2 + s2**2 - 2*s1*s2)
    a = np.array([1.0, 1.0]); b = np.array([1.0, -1.0])
    cos = a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
    print(cos, 100 * max(cos, 0))
    w = np.array([1, -1, 1, -1]); x = np.array([5, 5, 7, 7])
    y = x + 2 * w
    print(np.mean((y - y.mean()) * w))
    13.0
    0.0 0.0
    2.0

    প্রথম লাইন ৯ + ৯ + ১ − ৬ = ১৩ = (৪ − ১)2 + (৩ − ১)2. দ্বিতীয়তে dot = ০ (সমকোণ), তাই cos আর score দুটিই ০.০. তৃতীয়তে x-এর নিজের correlation শূন্য (x − x̄ = (−১, −১, ১, ১), w-এর সঙ্গে গুণফলের গড় ০), আর watermark ঠিক α = ২ যোগ করে।

  4. কোড লিখুন: NumPy আর SciPy দিয়ে fid(feats_a, feats_b) লিখুন, যা দুটি (n, d) feature array থেকে Fréchet distance দেয়। তারপর একটি sanity check: একই array-এর দুটি আলাদা অর্ধেকের FID ছোট কিন্তু শূন্যের বেশি আসে কি না, আর একটি অর্ধেকে সব মানে ১ যোগ করলে প্রায় d বাড়ে কি না।
    import numpy as np
    from scipy import linalg
    
    def fid(a, b):
        m1, m2 = a.mean(0), b.mean(0)
        s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
        covmean = linalg.sqrtm(s1 @ s2)
        covmean = covmean.real            # সংখ্যার ভুলে আসা ক্ষুদ্র imaginary অংশ বাদ
        return float(((m1 - m2) ** 2).sum() + np.trace(s1 + s2 - 2 * covmean))
    
    rng = np.random.default_rng(0)
    x = rng.standard_normal((4000, 16))
    print(fid(x[:2000], x[2000:]))        # ছোট, শূন্যের বেশি (নমুনার পক্ষপাত)
    print(fid(x[:2000], x[2000:] + 1.0))  # প্রায় 16 বেশি: গড়ের পদ ‖1‖² = d

    প্রথম print একটি ছোট ধনাত্মক সংখ্যা দেবে (নমুনার পক্ষপাত), দ্বিতীয়টি তার চেয়ে প্রায় ১৬ বেশি, কারণ প্রতিটি মাত্রায় গড় ১ সরে। sqrtm অস্থির হলে covariance-এর কর্ণে ছোট সংখ্যা (যেমন 1e-6) যোগ করা প্রচলিত।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি generator-এর FID মাপার কাজগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Reference সেট আর নমুনার সংখ্যা n ঠিক করা, সব model-এর জন্য একই
  2. Generator থেকে n-টি ছবি বানানো, নির্দিষ্ট seed-এ
  3. আসল আর নকল ছবি একই preprocessing-এ feature extractor-এ পাঠানো
  4. প্রতিটি সেটের feature-এর গড় μ আর covariance Σ হিসাব
  5. ‖μ1 − μ2‖2 + Tr(Σ1 + Σ2 − 2(Σ1Σ2)½) বের করা
  6. কয়েকটি seed-এ পুনরাবৃত্তি করে গড় আর পরিসর লেখা

আসল feature N(৬, ২2) আর generated feature N(৩, ১2) ধরা হলো। দুটি Gaussian-এর Fréchet distance d2 = (μ1 − μ2)2 + (σ1 − σ2)2 কত?

  • ৯
  • ১০
  • ১২
  • ৩.১৬

একই distribution থেকে আসা দুই সেট নমুনার FID মাপা হলো, প্রথমে ৫০০টি করে, পরে ৫০০০টি করে। কোনটি প্রত্যাশিত?

  • দুটিই ঠিক শূন্য, কারণ distribution একই
  • ৫০০০ নমুনার FID বেশি, কারণ বেশি নমুনায় বেশি পার্থক্য জমে
  • দুটিই শূন্যের বেশি, আর ৫০০ নমুনার মান ৫০০০-এর চেয়ে বেশি
  • নমুনার সংখ্যা FID-কে প্রভাবিত করে না

একটি generator-এর precision ০.৯৫ কিন্তু recall ০.৪০ (Kynkäänniemi-ধরনের k-NN মাপে)। সবচেয়ে সম্ভাব্য সমস্যা কী?

  • নমুনা বাস্তব, কিন্তু আসল ডেটার অনেক ধরন কখনো তৈরি হয় না
  • নমুনা ঝাপসা, কিন্তু সব ধরন আসে
  • Model training ছবি হুবহু কপি করছে
  • মাপে ভুল আছে, কারণ precision আর recall সবসময় কাছাকাছি হয়

একটি ছবির normalised embedding আর একটি caption-এর normalised embedding-এর dot product −০.১২. torchmetrics-এর রীতিতে CLIP score কত?

  • −১২
  • ১২
  • −০.১২
  • ০

C2PA (Content Credentials) সম্পর্কে কোন বক্তব্য ঠিক?

  • এটি যাচাই করে ছবির বিষয়বস্তু সত্য কি না
  • এটি ছবির সঙ্গে স্বাক্ষরিত উৎস-তথ্য রাখে, তবে প্ল্যাটফর্ম metadata মুছলে তা হারাতে পারে
  • এটি Google-এর একটি অদৃশ্য watermark
  • একবার যোগ করলে ছবি যত বদলানো হোক, যাচাই অটুট থাকে

একটি সরল spread-spectrum watermark (±১ প্যাটার্ন, correlation দিয়ে যাচাই) কোন পরিবর্তনে সবচেয়ে বেশি দুর্বল?

  • সামান্য Gaussian noise যোগ
  • পুরো ছবির উজ্জ্বলতা একটু বাড়ানো
  • ছবির চারপাশ থেকে কেটে নেওয়া (crop)
  • উচ্চ মানের JPEG (যেমন q ৯০)

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. তিন প্রশ্ন: মান, বৈচিত্র্য আর নতুনত্ব আলাদা; FID প্রথম দুটি মেশায়, precision/recall আলাদা করে, nearest-neighbour তৃতীয়টি দেখে।
  2. FID: ‖μ1 − μ2‖2 + Tr(Σ1 + Σ2 − 2(Σ1Σ2)½); এক মাত্রায় (Δμ)2 + (Δσ)2. কম n-এ বেশি আসে; একই n, reference, feature আর preprocessing ছাড়া তুলনা নয়।
  3. CLIP score: 100 × max(cos, 0); শুধু একই শর্তে তুলনা অর্থবহ, আর মানুষের মূল্যায়নের বিকল্প নয়।
  4. Memorisation: নমুনার নিকটতম training ছবির দূরত্ব test ছবির দূরত্বের সঙ্গে তুলনা করুন।
  5. নিরাপত্তা: Deepfake-এর বিরুদ্ধে detector, watermark, C2PA আর মানুষের যাচাই একসঙ্গে; watermark-এর robustness নিজে মাপুন (আমাদের run-এ crop-এ দুটি পদ্ধতিই ব্যর্থ)।

পরের পর্বে: পর্ব ৮২ (Multimodal model — CLIP, image captioning আর vision-language model): এই পর্বে মাপকাঠি হিসেবে ব্যবহার করা CLIP কীভাবে শেখে, আর ছবি ও লেখা একসঙ্গে বোঝা model-এর গঠন।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান