সিঙ্গুলার ভ্যালু ডিকম্পোজিশন (SVD)
এই পাঠে যা শিখবেন
- SVD-এর সংজ্ঞা এবং
U,Σ,V-এর জ্যামিতিক অর্থ (ঘূর্ণন-প্রসারণ-ঘূর্ণন) - সিঙ্গুলার ভ্যালু ও
AᵀA-এর আইগেনভ্যালুর মধ্যে সম্পর্ক, এবং কেন এই সম্পর্কটি M8-এর পাওয়ার মেথডকে পুনর্ব্যবহারযোগ্য করে তোলে - SVD-এর বাস্তব প্রয়োগ — ডাইমেনশনালিটি রিডাকশন, লো-র্যাংক অ্যাপ্রক্সিমেশন, সিউডো-ইনভার্স
- একটি সত্যিকারের, চলমান ডেমো যা প্রথম সিঙ্গুলার ভ্যালু/ভেক্টর জোড়া বের করে ও rank-1 রিকনস্ট্রাকশনের প্রকৃত এরর গণনা করে
- এই সরলীকৃত পদ্ধতির সীমাবদ্ধতা — এটি কেন প্রোডাকশন-গ্রেড SVD-এর বিকল্প নয়
১ · SVD কী — সংজ্ঞা ও জ্যামিতিক অর্থ
SVDSingular Value Decompositionযেকোনো ম্যাট্রিক্সকে তিনটি সরল রূপান্তরে (ঘূর্ণন, স্কেলিং, ঘূর্ণন) ভেঙে ফেলার একটি পদ্ধতি — বর্গাকার বা আইগেনভ্যালু-সংজ্ঞায়িত হওয়ার প্রয়োজন ছাড়াই যেকোনো m×n ম্যাট্রিক্সের জন্য কাজ করে।
হলো এমন একটি ডিকম্পোজিশন যা যেকোনো m × n ম্যাট্রিক্স A-কে তিনটি ম্যাট্রিক্সের
গুণফলে লেখে:
$$A = U \Sigma V^T$$
যেখানে U (m × m) ও V (n × n) হলো
অর্থোগোনাল ম্যাট্রিক্স (এদের কলামগুলো একে অপরের সাথে লম্ব এবং একক-দৈর্ঘ্যের — বিশুদ্ধ
ঘূর্ণন/প্রতিফলন প্রতিনিধিত্ব করে), আর Σ (m × n) একটি ডায়াগোনাল ম্যাট্রিক্স যার
ডায়াগোনাল এন্ট্রিগুলো সিঙ্গুলার ভ্যালু (σ₁ ≥ σ₂ ≥ ... ≥ 0), সবসময়
অ-ঋণাত্মক এবং বৃহৎ থেকে ক্ষুদ্র ক্রমে সাজানো। জ্যামিতিকভাবে, যেকোনো লিনিয়ার ট্রান্সফর্মেশন
A তিনটি ধাপে ভেঙে ফেলা যায় — প্রথমে একটি ঘূর্ণন (Vᵀ), তারপর অক্ষ বরাবর প্রসারণ/
সংকোচন (Σ), তারপর আরেকটি ঘূর্ণন (U)। AᵀA-এর আইগেনভেক্টরগুলোই
V-এর কলাম, আর সিঙ্গুলার ভ্যালুগুলো AᵀA-এর আইগেনভ্যালুর বর্গমূল — এই সম্পর্কটিই
নিচের ডেমোর ভিত্তি।
২ · কেন SVD গুরুত্বপূর্ণ
সবচেয়ে বড় কয়েকটি সিঙ্গুলার ভ্যালু ও তাদের ভেক্টর রেখে বাকিগুলো বাদ দিলে একটি ম্যাট্রিক্সের সবচেয়ে ভালো লো-র্যাংক অ্যাপ্রক্সিমেশন পাওয়া যায় — ইমেজ কম্প্রেশন, নয়েজ রিডাকশন ও ডেটা কম্প্রেশনে ব্যবহৃত হয়।
যখন
A বর্গাকার নয় বা সিঙ্গুলার (ইনভার্স অস্তিত্বহীন), SVD দিয়ে একটি সাধারণীকৃত ইনভার্স গণনা করা যায় — লিস্ট-স্কয়ার্স সমস্যার (M4/L20) সবচেয়ে সাধারণ সমাধান দেয়।প্রিন্সিপাল কম্পোনেন্ট অ্যানালাইসিস (PCA) মূলত ডেটা ম্যাট্রিক্সের SVD-ই — সিঙ্গুলার ভেক্টরগুলো প্রিন্সিপাল কম্পোনেন্ট দেয় (M8/L41-এ আইগেনভ্যালু-PCA সংযোগ দেখুন, এবং Machine Learning কোর্সে বিস্তারিত প্রয়োগ)।
একটি প্রোডাকশন-গ্রেড SVD রুটিন একসাথে সব সিঙ্গুলার ভ্যালু ও ভেক্টর বের করে, এবং সরাসরি
AᵀA না গুণেই (কারণ সেটা সংখ্যাগতভাবে কন্ডিশন নাম্বার বর্গ করে ফেলে, নির্ভুলতা কমায়)
Golub-Kahan বাইডায়াগোনালাইজেশনের মতো অনেক বেশি স্থিতিশীল কৌশল ব্যবহার করে। নিচের ডেমো ইচ্ছাকৃতভাবে
এই জটিলতা এড়িয়ে শুধু প্রথম (বৃহত্তম) সিঙ্গুলার ভ্যালু/ভেক্টর জোড়া বের করে, M8-এর
পাওয়ার মেথড সরাসরি পুনর্ব্যবহার করে — এটি একটি শিক্ষামূলক ইলাস্ট্রেশন, প্রোডাকশন রুটিন নয়।
৩ · একটি সরলীকৃত হাতে-লেখা ডেমো — AᵀA-এর উপর পাওয়ার মেথড
যেকোনো ম্যাট্রিক্স A-এর জন্য, AᵀA সবসময় সিমেট্রিক এবং পজিটিভ সেমি-ডেফিনিট —
অর্থাৎ এর সব আইগেনভ্যালু বাস্তব ও অ-ঋণাত্মক, তাই বর্গমূল নেওয়া সবসময় সংজ্ঞায়িত। M8/L38-এর পাওয়ার মেথড
(বারবার ম্যাট্রিক্স-ভেক্টর গুণ ও নরমালাইজ করা) এখানে সরাসরি প্রয়োগ করা যায় — এটি AᵀA-এর
ডমিনেন্ট (বৃহত্তম) আইগেনভ্যালু λ₁ ও তার আইগেনভেক্টর v₁-এ কনভার্জ করবে। তারপর
σ₁ = √λ₁ (প্রথম সিঙ্গুলার ভ্যালু), এবং u₁ = (1/σ₁) A v₁ (প্রথম লেফট সিঙ্গুলার
ভেক্টর)।
import math
# A হলো 3x2 ম্যাট্রিক্স (৩টি সারি, ২টি কলাম) -- একটি ইলাস্ট্রেটিভ উদাহরণ
A = [
[3.0, 1.0],
[1.0, 3.0],
[1.0, 1.0],
]
def transpose(M):
rows, cols = len(M), len(M[0])
return [[M[r][c] for r in range(rows)] for c in range(cols)]
def matmul(M1, M2):
r1, c1 = len(M1), len(M1[0])
r2, c2 = len(M2), len(M2[0])
result = [[0.0]*c2 for _ in range(r1)]
for i in range(r1):
for j in range(c2):
s = 0.0
for k in range(c1):
s += M1[i][k]*M2[k][j]
result[i][j] = s
return result
def matvec(M, v):
return [sum(M[i][j]*v[j] for j in range(len(v))) for i in range(len(M))]
def vec_norm(v):
return math.sqrt(sum(x*x for x in v))
def normalize(v):
n = vec_norm(v)
return [x/n for x in v]
At = transpose(A)
AtA = matmul(At, A)
print("A^T A =", AtA)
print()
# M8-এর পাওয়ার মেথড, এখানে A^T A-এর উপর প্রয়োগ করা হচ্ছে
v = [1.0, 0.0]
print(f"{'ইটারেশন':>8} | {'v (normalized)':<26} | {'lambda estimate':>16}")
lambda_est = None
for i in range(1, 13):
w = matvec(AtA, v)
lambda_est = vec_norm(w)
v = normalize(w)
print(f"{i:8d} | {str([round(x,6) for x in v]):<26} | {lambda_est:16.8f}")
lambda1 = lambda_est
sigma1 = math.sqrt(lambda1)
v1 = v
print()
print(f"কনভার্জড ডমিনেন্ট আইগেনভ্যালু (lambda1): {lambda1:.6f}")
print(f"রাইট সিঙ্গুলার ভেক্টর v1: {[round(x,6) for x in v1]}")
print(f"প্রথম সিঙ্গুলার ভ্যালু sigma1 = sqrt(lambda1): {sigma1:.6f}")
# u1 = (1/sigma1) * A v1
Av1 = matvec(A, v1)
u1 = [x/sigma1 for x in Av1]
print(f"লেফট সিঙ্গুলার ভেক্টর u1 = (1/sigma1) A v1: {[round(x,6) for x in u1]}")
print(f"u1-এর নর্ম (~1 হওয়া উচিত): {vec_norm(u1):.6f}")
# rank-1 রিকনস্ট্রাকশন sigma1 * u1 * v1^T
recon = [[sigma1*u1[i]*v1[j] for j in range(2)] for i in range(3)]
print()
print("Rank-1 রিকনস্ট্রাকশন sigma1*u1*v1^T:")
for row in recon:
print([round(x, 6) for x in row])
print("মূল A:")
for row in A:
print(row)
diff = [[A[i][j]-recon[i][j] for j in range(2)] for i in range(3)]
frob_err = math.sqrt(sum(x*x for row in diff for x in row))
print()
print(f"রেসিডুয়ালের Frobenius নর্ম (A - rank-1 reconstruction): {frob_err:.6f}")
lambda-এর মান ঠিক ১৮.০০-এ কনভার্জ করে যায় (কারণ
AᵀA = [[11,7],[7,11]]-এর আইগেনভ্যালু বিশুদ্ধ পাটিগণিতেই ১৮ ও ৪), তাই
σ₁ = √18 ≈ 4.242641, v1 ≈ [0.707107, 0.707107] (অর্থাৎ
1/√2 দিকে), এবং u1 ≈ [0.666667, 0.666667, 0.333333]। rank-1
রিকনস্ট্রাকশন σ1·u1·v1ᵀ দেয় [[2,2],[2,2],[1,1]] — মূল A =
[[3,1],[1,3],[1,1]]-এর সাথে তুলনা করলে রেসিডুয়ালের Frobenius নর্ম ঠিক ২.০ —
এই বাকি অংশটাই দ্বিতীয় সিঙ্গুলার ভ্যালু/ভেক্টর জোড়া প্রতিনিধিত্ব করে, যা এই সরলীকৃত ডেমো বের করেনি
(প্রোডাকশন SVD উভয় জোড়াই একসাথে বের করে ফেলত)।
SVD হলো ম্যাট্রিক্সকে "ঘূর্ণন-প্রসারণ-ঘূর্ণন"-এ ভাঙার সবচেয়ে সাধারণ পদ্ধতি — বর্গাকার হওয়ার প্রয়োজন
নেই, এবং সবসময় অস্তিত্ব থাকে। M8-এর পাওয়ার মেথড AᵀA-তে প্রয়োগ করে একটি সিঙ্গুলার
ভ্যালু/ভেক্টর জোড়া বের করা সম্ভব, যা SVD-এর কোর ধারণাটি স্পষ্ট করে — কিন্তু সব জোড়া দক্ষভাবে ও
সংখ্যাগতভাবে স্থিতিশীলভাবে বের করতে প্রোডাকশন লাইব্রেরি (যেমন LAPACK-ভিত্তিক রুটিন) প্রয়োজন, যা এই
কোর্সের সুযোগের বাইরে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
পাওয়ার মেথড AᵀA-এর উপর প্রয়োগ করলে কেন শুধু প্রথম (বৃহত্তম)
সিঙ্গুলার ভ্যালু/ভেক্টর জোড়া পাওয়া যায়, বাকি সব নয়?
M8/L38-এ দেখা গেছে পাওয়ার মেথড বারবার ম্যাট্রিক্স-ভেক্টর গুণ করলে যেকোনো শুরুর ভেক্টর ধীরে ধীরে ডমিনেন্ট (বৃহত্তম আইগেনভ্যালুর) দিকে ঝুঁকে পড়ে, কারণ প্রতিটি গুণে সেই দিকের উপাদান অন্য দিকগুলোর তুলনায় দ্রুত বৃদ্ধি পায়। তাই এই মেথড স্বভাবতই শুধু সবচেয়ে বড় আইগেনভ্যালু/আইগেনভেক্টর জোড়ায় কনভার্জ করে — বাকি (ছোট) সিঙ্গুলার ভ্যালু/ভেক্টর জোড়া বের করতে হলে ডিফ্লেশন (প্রথম জোড়ার অবদান বাদ দিয়ে আবার চালানো) বা সম্পূর্ণ ভিন্ন অ্যালগরিদম প্রয়োজন — যা এই সরলীকৃত ডেমো করেনি।
প্র ০২
AᵀA সবসময় সিমেট্রিক ও পজিটিভ সেমি-ডেফিনিট কেন, এবং এটি কেন গুরুত্বপূর্ণ যে
σ1 = √lambda1 গণনা করার আগে?
(AᵀA)ᵀ = AᵀAᵀᵀ = AᵀA, তাই এটি সবসময় সিমেট্রিক — আর যেকোনো ভেক্টর x-এর জন্য
xᵀ(AᵀA)x = (Ax)ᵀ(Ax) = ‖Ax‖² ≥ 0, তাই এটি সবসময় পজিটিভ সেমি-ডেফিনিট। এই দুটি বৈশিষ্ট্যই
গ্যারান্টি দেয় AᵀA-এর সব আইগেনভ্যালু বাস্তব ও অ-ঋণাত্মক — তাই
math.sqrt(lambda1) কখনো নেগেটিভ নাম্বার বা জটিল সংখ্যার সমস্যায় পড়বে না, যা এই ডেমোর
কোড সেলকে নিরাপদে চালানো নিশ্চিত করে।
প্র ০৩
rank-1 রিকনস্ট্রাকশনের পর রেসিডুয়াল Frobenius নর্ম ঠিক ২.০ এসেছে। এই সংখ্যাটি কী
প্রতিনিধিত্ব করে, এবং কীভাবে এটি কমানো যেত?
একটি সম্পূর্ণ SVD-তে A = σ1·u1·v1ᵀ + σ2·u2·v2ᵀ (এই 2×3 ম্যাট্রিক্সের জন্য
ঠিক দুটি সিঙ্গুলার ভ্যালু আছে)। রিকনস্ট্রাকশনে শুধু প্রথম টার্ম ব্যবহার করায়
σ2·u2·v2ᵀ অংশটাই "মিসিং" থেকে যায় — সেটাই রেসিডুয়াল ২.০-এর উৎস। দ্বিতীয় সিঙ্গুলার
ভ্যালু/ভেক্টর জোড়া যোগ করলে (যা এই ডেমো বের করেনি) রেসিডুয়াল একদম শূন্যে নেমে আসত, কারণ তখন পূর্ণ
A সঠিকভাবে পুনর্গঠিত হয়ে যেত।
অনুশীলন
-
চিন্তা করুন: উপরের কোড সেলে
A-এর প্রথম সারি[3.0, 1.0]-কে[5.0, 1.0]-এ পরিবর্তন করলেAᵀA-এর আইগেনভ্যালুগুলো (এবং তাইsigma1) কি আগের চেয়ে বড় হবে না ছোট, আপনার কী মনে হয়?A-এর একটি এন্ট্রি বড় করলে (৩ থেকে ৫) সাধারণত ম্যাট্রিক্সের সামগ্রিক "মাত্রা" বাড়ে (বড় সংখ্যাগুলো ম্যাট্রিক্স-ভেক্টর গুণে বেশি অবদান রাখে), তাইAᵀA-এর আইগেনভ্যালুও সাধারণত বাড়বে — অর্থাৎsigma1আগের4.2426-এর চেয়ে বড় হওয়ার কথা। -
পরীক্ষা করুন: উপরের কোড সেলে
A-এর প্রথম সারি[5.0, 1.0]-এ পরিবর্তন করে Run চেপেAᵀA,lambda1ওsigma1-এর নতুন মান দেখুন এবং আপনার অনুমান যাচাই করুন।এই পরিবর্তনে
AᵀA = [[27,7],[7,11]]হয়ে যায় (আগের[[11,7],[7,11]]-এর বদলে), এবং পাওয়ার মেথড একটি বড় ডমিনেন্ট আইগেনভ্যালুতে কনভার্জ করবে —sigma1স্পষ্টভাবে আগের4.2426-এর চেয়ে বড় হয়ে যাবে, যা নিশ্চিত করে বড় ম্যাট্রিক্স এন্ট্রি বৃহত্তর "স্ট্রেচিং" (সিঙ্গুলার ভ্যালু) নির্দেশ করে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- M8 · আইগেনভ্যালু সমস্যা ও পাওয়ার মেথড L38 এই পাঠের ভিত্তি — পাওয়ার মেথড কীভাবে কাজ করে তার বিস্তারিত ব্যাখ্যা ও ধাপে ধাপে কনভারজেন্স।
- M8 · আইগেনভেক্টর ও PCA-এর সংযোগ L41 আইগেনভ্যালু/আইগেনভেক্টর কীভাবে PCA-তে ব্যবহৃত হয় তার সংযোগ — SVD-এর সাথে একই মূল ধারণা।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ এরর অ্যানালাইসিস থেকে ক্যাপস্টোন পর্যন্ত — Numerical Methods কোর্সের সব পাঠ এক জায়গায়।