ফরওয়ার্ড ও ব্যাকওয়ার্ড এরর অ্যানালাইসিস
এই পাঠে যা শিখবেন
- ফরওয়ার্ড এরর ও ব্যাকওয়ার্ড এররের সংজ্ঞা এবং এই দুইয়ের মধ্যে ধারণাগত পার্থক্য
- কেন বাস্তব-বিশ্বের অ্যালগরিদম যাচাইয়ে ব্যাকওয়ার্ড এরর প্রায়ই বেশি ব্যবহারযোগ্য
- একটি সত্যিকারের Newton-Raphson ডেমোতে উভয় এরর প্রতি ইটারেশনে গণনা করে পর্যবেক্ষণ করা
- ফাংশনের ডেরিভেটিভ কীভাবে ফরওয়ার্ড ও ব্যাকওয়ার্ড এররের মধ্যে একটি আনুমানিক গাণিতিক সেতু তৈরি করে (কন্ডিশনিং-এর সাথে সংযোগ, M1/L04-এ বিস্তারিত)
১ · ফরওয়ার্ড এরর — "আমার উত্তর কতটা ভুল?"
কোনো সমস্যার প্রকৃত (কিন্তু হয়তো অজানা) সমাধান x* এবং আমাদের অ্যালগরিদমের কম্পিউটেড উত্তর
x̂ হলে, ফরওয়ার্ড এররForward errorকম্পিউটেড উত্তর ও প্রকৃত উত্তরের মধ্যে সরাসরি দূরত্ব — |x̂ - x*|।
হলো সবচেয়ে স্বজ্ঞাত (intuitive) এরর ধারণা — সরাসরি দূরত্ব:
$$ e_{\text{forward}} = |\hat{x} - x^*| $$
এটি ঠিক সেই প্রশ্নের উত্তর দেয় যা আমরা সবচেয়ে বেশি জানতে চাই — "আমার উত্তর কতটা সঠিক?" — কিন্তু একটি বড়
সমস্যা আছে: এটি গণনা করতে x* জানা লাগে, যা বাস্তবে প্রায় কখনোই সরাসরি জানা থাকে না (যদি
জানা থাকত, তাহলে সমস্যাটা সমাধান করারই দরকার হতো না!)।
২ · ব্যাকওয়ার্ড এরর — "আমি আসলে কোন সমস্যাটা সমাধান করেছি?"
ব্যাকওয়ার্ড এররBackward errorকম্পিউটেড উত্তর x̂-কে ঠিক/নিখুঁত সমাধান বানাতে মূল সমস্যাটিকে কতটা পার্টার্ব (সামান্য পরিবর্তন) করতে হতো, তার পরিমাপ।
ভিন্ন প্রশ্ন করে — "আমার কম্পিউটেড উত্তর x̂-টা যদি সঠিক ধরে নিই, তাহলে সেটা ঠিক কোন
সমীকরণের নিখুঁত সমাধান?" রুট-ফাইন্ডিং সমস্যা f(x) = 0-এর ক্ষেত্রে, যদি
f(x̂) ≠ 0 হয়, তাহলে x̂ আসলে f(x) = δ সমীকরণের নিখুঁত সমাধান,
যেখানে δ = f(x̂)। তাই:
$$ e_{\text{backward}} = |f(\hat{x})| $$
এটাকে বলা যায় "মূল সমস্যাটাকে কতটা নাড়ালে আমার উত্তর নিখুঁত হয়ে যেত।" এর সবচেয়ে বড় সুবিধা —
f(x̂) গণনা করতে x* জানার দরকার নেই, শুধু x̂ ফাংশনে বসিয়ে দিলেই হয়।
এই কারণেই বাস্তব সংখ্যাসূচক সফটওয়্যার প্রায়ই ব্যাকওয়ার্ড এরর (residual) দেখেই "কনভার্জ করেছে" বলে
সিদ্ধান্ত নেয়।
"উত্তর কতটা ভুল" — সরাসরি স্বজ্ঞাত, কিন্তু
x* লাগে যা সাধারণত অজানা।"কোন সমস্যাটা ঠিক সমাধান হলো" —
x* ছাড়াই সরাসরি গণনাযোগ্য (residual)।৩ · একটি সত্যিকারের ডেমো — Newton-Raphson দিয়ে x³ - x - 2 = 0
নিচের কোড সেলে f(x) = x³ - x - 2 সমীকরণটি Newton-Raphson (M2/L07) দিয়ে সমাধান করা হয়েছে
x₀ = 1.2 থেকে শুরু করে। প্রথমে ১০০টি ইটারেশন চালিয়ে একটি অতি-নির্ভুল "রেফারেন্স" মূল বের করা
হয়েছে (এটাকেই আমরা x* ধরে নিচ্ছি), তারপর মাত্র কয়েকটি ইটারেশন চালিয়ে প্রতি ধাপে
উভয় এরর — ব্যাকওয়ার্ড (|f(x)|) ও ফরওয়ার্ড (|x - x*|) — সত্যিই
গণনা করে প্রিন্ট করা হয়েছে।
import math
def f(x):
return x**3 - x - 2
def fprime(x):
return 3 * x**2 - 1
# রেফারেন্স "প্রকৃত" মূল বের করতে ১০০টি Newton ইটারেশন চালাই (উচ্চ নির্ভুলতা)
x = 1.5
for _ in range(100):
x = x - f(x) / fprime(x)
true_root = x
print(f"রেফারেন্স মূল x* (১০০ ইটারেশন পর) = {true_root:.10f}")
print()
# এখন মাত্র কয়েকটি ইটারেশন চালিয়ে প্রতি ধাপে backward ও forward error দুটোই মাপি
x0 = 1.2
x = x0
print(f"{'ইটার':>4} | {'x (বর্তমান অনুমান)':>20} | {'backward |f(x)|':>18} | {'forward |x-x*|':>18}")
for i in range(1, 7):
fx = f(x)
backward_err = abs(fx)
forward_err = abs(x - true_root)
print(f"{i:>4} | {x:>20.10f} | {backward_err:>18.10f} | {forward_err:>18.10f}")
x = x - fx / fprime(x)
x* = 1.5213797068। প্রথম ইটারেশনে (x = 1.2) backward error
1.472 আর forward error 0.3214 — সম্পূর্ণ ভিন্ন মাত্রার সংখ্যা। ৩ নং ইটারেশনে
(x = 1.5314552593) backward error 0.0603513138, কিন্তু forward error মাত্র
0.0100755525 — লক্ষ্য করুন backward error, forward error-এর প্রায় ৬ গুণ!
৬ নং ইটারেশনে দুটো এররই 0-এ নেমে আসে — Newton-Raphson-এর কোয়াড্রেটিক কনভারজেন্সের কারণে
(M2/L07) মাত্র কয়েক ধাপেই ডাবল-প্রিসিশন ফ্লোটের সীমায় পৌঁছে যায় (L02-এ বিস্তারিত)।
৪ · ফরওয়ার্ড ও ব্যাকওয়ার্ড এররের সম্পর্ক — কন্ডিশনিং
লক্ষ্য করার মতো বিষয়, backward error আর forward error সরাসরি সমান নয় কেন? উত্তরটা ফাংশনের
ঢাল (derivative)-এর সাথে সম্পর্কিত। যদি রুটের কাছাকাছি ফাংশনটি খুব খাড়া হয়
(|f'(x*)| বড়), তাহলে ছোট একটা backward error-ও ছোট forward error-এ পরিণত হয় — কারণ x-অক্ষে
সামান্য নড়াচড়াতেই f(x)-এর মান অনেকখানি বদলে যায়। বিপরীতভাবে, ফাংশনটি যদি রুটের কাছে প্রায়
সমতল হয় (|f'(x*)| ছোট), একই backward error অনেক বড় forward error-এ পরিণত হতে পারে
— এটাই ইল-কন্ডিশনড (ill-conditioned) রুট (M1/L04-এ conditioning নিয়ে বিস্তারিত)। প্রথম
মাত্রার (linear) আনুমানিকতায়:
$$ e_{\text{forward}} \approx \frac{e_{\text{backward}}}{|f'(x^*)|} $$
নিচের কোড সেলে এই সম্পর্কটা সত্যিকারের সংখ্যা দিয়ে যাচাই করা হয়েছে।
import math
def f(x):
return x**3 - x - 2
def fprime(x):
return 3 * x**2 - 1
x = 1.5
for _ in range(100):
x = x - f(x) / fprime(x)
true_root = x
# ২টি Newton ইটারেশনের পর আমরা যেখানে পৌঁছাই
x0 = 1.2
x = x0
for _ in range(2):
x = x - f(x) / fprime(x)
computed = x
backward_err = abs(f(computed))
forward_err = abs(computed - true_root)
fprime_at_root = fprime(true_root)
predicted_forward = backward_err / abs(fprime_at_root)
print(f"২ ইটারেশন পর computed x = {computed:.10f}")
print(f"backward error |f(computed)| = {backward_err:.10f}")
print(f"প্রকৃত forward error |computed-x*| = {forward_err:.10f}")
print(f"f'(x*) = {fprime_at_root:.10f}")
print(f"পূর্বাভাসিত forward = backward/|f'(x*)| = {predicted_forward:.10f}")
0.0100755525, আর backward/|f'(x*)| সূত্র দিয়ে পূর্বাভাসিত
মান 0.0101536776 — দুটো প্রায় হুবহু কাছাকাছি (পার্থক্য মাত্র ~0.008-এর মধ্যে)।
এই আনুমানিক সূত্রটাই matrix condition number-এর ধারণার (M3/L14) মূল ভিত্তি — একই backward error, ভিন্ন
কন্ডিশনিং-এর সমস্যায়, সম্পূর্ণ ভিন্ন মাত্রার forward error তৈরি করতে পারে।
ফরওয়ার্ড এরর বলে "উত্তর কতটা ভুল," ব্যাকওয়ার্ড এরর বলে "কোন সমস্যাটা ঠিক সমাধান হলো" — আর এই দুইয়ের
মধ্যে সেতু হলো সমস্যার সেনসিটিভিটি/কন্ডিশনিং। বাস্তব সফটওয়্যারে যেহেতু x* সাধারণত অজানা,
ব্যাকওয়ার্ড এরর (residual) হলো সবচেয়ে ব্যবহারযোগ্য, সরাসরি-গণনাযোগ্য পরিমাপ — পরের পাঠ (L51) এই
সেনসিটিভিটির ধারণাকে মন্টে কার্লো সিমুলেশন দিয়ে আরও সাধারণভাবে প্রসারিত করবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
উপরের ডেমোতে ৩ নং ইটারেশনে backward error (0.0603513138), forward error
(0.0100755525)-এর প্রায় ৬ গুণ ছিল। এটা কেন ঘটল?
কারণ রুটের কাছে f'(x*) ≈ 5.9438 — অর্থাৎ ফাংশনটি বেশ খাড়া। যেহেতু
e_forward ≈ e_backward / |f'(x*)|, আর |f'(x*)| > 1, তাই forward error
backward error-এর চেয়ে ছোট হয়ে যায়। যদি ফাংশনটি রুটের কাছে সমতল হতো (|f'(x*)| < 1),
সম্পর্কটা উল্টো হতো — forward error backward error-এর চেয়ে বড় হতো।
প্র ০২ ব্যাকওয়ার্ড এরর খুব ছোট হলেই কি নিশ্চিতভাবে ধরে নেওয়া যায় যে forward error-ও ছোট?
না, নিশ্চিতভাবে নয়। সম্পর্কটা নির্ভর করে |f'(x*)|-এর উপর — যদি রুটের কাছে ফাংশনটি প্রায়
সমতল হয় (|f'(x*)| খুবই ছোট, যেমন কোনো রুট যেখানে ফাংশন রুটকে "স্পর্শ" করে যায়), তাহলে
একটি অতি-ছোট backward error-ও বিশাল forward error-এ পরিণত হতে পারে। এটাই একটি ইল-কন্ডিশনড রুট-ফাইন্ডিং
সমস্যার লক্ষণ (M1/L04)।
প্র ০৩ বাস্তব সংখ্যাসূচক সফটওয়্যার (যেমন লিনিয়ার-সিস্টেম সলভার) প্রায়ই "কনভার্জ করেছে" বলে সিদ্ধান্ত নেয় শুধু residual (backward error) দেখে, forward error নয় কেন?
কারণ forward error গণনা করতে প্রকৃত উত্তর x* জানা লাগে — যা সমাধান করার আগেই জানা থাকলে
সমস্যাটা সমাধান করারই দরকার হতো না। কিন্তু backward error (|f(x̂)| বা
|Ax̂ - b|) সবসময় সরাসরি, সহজে গণনাযোগ্য — তাই এটাই ব্যবহারিক থামার শর্ত (stopping
criterion) হিসেবে ব্যবহৃত হয়।
অনুশীলন
-
চিন্তা করুন: উপরের প্রথম কোড সেলে দেখা গেছে Newton-Raphson কোয়াড্রেটিক্যালি কনভার্জ
করে — প্রতি ইটারেশনে forward error মোটামুটি বর্গ (square) হয়ে যায়। ৫ নং ইটারেশনের forward error
0.0000000046হলে, যদি আরও একটি ইটারেশন চালানো হতো, নতুন forward error মোটামুটি কত মাত্রার হবে বলে আপনার ধারণা?কোয়াড্রেটিক কনভারজেন্স মানে নতুন error ≈ পুরনো error² (একটি ধ্রুবক গুণক সহ) — তাই
(0.0000000046)² ≈ 2 × 10⁻¹⁷মাত্রার, যা ইতিমধ্যে ডাবল-প্রিসিশন ফ্লোটের নির্ভুলতা সীমার (মেশিন এপসিলন, L02-এ বিস্তারিত) কাছাকাছি বা তার চেয়ে ছোট — তাই ব্যবহারিকভাবে error0-এ নেমে যাবে। -
পরীক্ষা করুন: উপরের প্রথম কোড সেলে
for i in range(1, 7):-কেfor i in range(1, 8):-এ পরিবর্তন করে Run চেপে দেখুন ৭ নং ইটারেশনে backward ও forward error সত্যিই কী মান দেখায় — আপনার অনুমান মিলল কিনা যাচাই করুন।৬ নং ইটারেশনেই
xডাবল-প্রিসিশন ফ্লোটে সম্পূর্ণ নির্ভুল রেফারেন্স মূলের সমান হয়ে যায় (backward ও forward error উভয়ই0.0000000000) — তাই ৭ নং ইটারেশনেও একই ফলাফল দেখাবে। এটাই দেখায় floating-point নির্ভুলতার একটি বাস্তব সীমা আছে — এরপর আর কোনো ইটারেশন প্রকৃত উন্নতি আনতে পারে না, যতই "কোয়াড্রেটিক কনভারজেন্স" থিওরিটিক্যালি প্রতিশ্রুতি দিক না কেন।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ এরর প্রোপাগেশন ও সেনসিটিভিটি অ্যানালাইসিস মডিউল (M11) থেকে বিজ্ঞান ও ইঞ্জিনিয়ারিং প্রয়োগ ও ক্যাপস্টোন পর্যন্ত — কোর্সের সব পাঠ এখানে।
- M1/L04 · অ্যালগরিদম স্ট্যাবিলিটি, কন্ডিশনিং ও কনভারজেন্স পূর্বজ্ঞান কন্ডিশনিং-এর মূল ধারণা — এই পাঠের ফরওয়ার্ড/ব্যাকওয়ার্ড এরর সম্পর্ক সরাসরি এই ধারণার উপর ভিত্তি করে তৈরি।
- L51 · সেনসিটিভিটি অ্যানালাইসিস ও মন্টে কার্লো এরর এস্টিমেশন পরবর্তী পাঠ একটি ইনপুটের অনিশ্চয়তা কীভাবে আউটপুটে প্রোপাগেট হয় তা মন্টে কার্লো সিমুলেশন দিয়ে সাধারণভাবে পরিমাপ করা।