পাঠ ১৮ · ৫৭-এর মধ্যে · মডিউল ৪
Home / AI Courses / Human-Centered AI / এক্সপ্লেইনেবিলিটি

ব্যবহারকারীদের সাথে এক্সপ্লেনেশনের গুণমান যাচাই

Evaluating explanation quality with users
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন একটি "বিশ্বাসযোগ্য শোনানো" এক্সপ্লেনেশন এখনও বিভ্রান্তিকর হতে পারে
  • একটি সত্যিকারের পার্টার্বেশন-ভিত্তিক কনসিস্টেন্সি চেক কীভাবে কাজ করে
  • এই চেকটি একাধিক সিন্থেটিক কেসে স্কেল করলে কেমন সঠিকতা পাওয়া যায় তা প্রকৃতভাবে গণনা করা
  • স্বয়ংক্রিয় চেকের পাশাপাশি বাস্তব ব্যবহারকারীদের সাথে এক্সপ্লেনেশনের গুণমান যাচাইয়ের গবেষণা-পদ্ধতি

১ · "ভালো শোনানো" বনাম "সত্যিকারভাবে বিশ্বস্ত"

M4-এর আগের পাঠগুলোতে আমরা দেখেছি কীভাবে এক্সপ্লেনেশন উপস্থাপন করতে হয় — কোন ধরনের (L15), কোন ভাষায় (L14, L16), কোন স্তরে (L17)। কিন্তু একটি প্রশ্ন এখনও বাকি: এক্সপ্লেনেশনটি কি আসলেই ফেইথফুলফেইথফুল (Faithful)একটি এক্সপ্লেনেশন "ফেইথফুল" তখনই যখন এটি মডেলের সিদ্ধান্তের প্রকৃত অভ্যন্তরীণ কারণ বর্ণনা করে -- শুধু বিশ্বাসযোগ্য বা বোধগম্য শোনানো যথেষ্ট নয়। — অর্থাৎ এটি কি সত্যিই মডেলের সিদ্ধান্তের প্রকৃত কারণ বর্ণনা করছে, নাকি শুধু বিশ্বাসযোগ্য শোনাচ্ছে? একটি সুন্দরভাবে লেখা, আত্মবিশ্বাসী এক্সপ্লেনেশন সম্পূর্ণ ভুল ফিচারকে কারণ হিসেবে দাবি করতে পারে, অথচ ব্যবহারকারীর কাছে তা বিশ্বাসযোগ্য মনে হতে পারে — এটি বিশেষভাবে বিপজ্জনক, কারণ এটি একটি মিথ্যা অনুভূত স্বচ্ছতা তৈরি করে, যা ভুল-ক্যালিব্রেটেড ট্রাস্টের (M3) একটি বিশেষভাবে ক্ষতিকর রূপ।

২ · পার্টার্বেশন-ভিত্তিক কনসিস্টেন্সি চেক

একটি ব্যবহারিক উপায় হলো: এক্সপ্লেনেশন যে ফিচারকে "প্রধান কারণ" বলছে, সেটিকে সরিয়ে/পরিবর্তন করে দেখা প্রকৃত ফলাফল কতটা বদলায়। যদি দাবি করা "প্রধান কারণ" পরিবর্তন করলেও ফলাফল প্রায় অপরিবর্তিত থাকে, তাহলে এক্সপ্লেনেশনটি অসংগত। নিচের কোডে একটি স্প্যাম-ইমেইল স্কোরিং মডেলের জন্য একটি ফেইথফুল ও একটি ইচ্ছাকৃত বিভ্রান্তিকর ব্যাখ্যা তুলনা করা হয়েছে।

Python
weights = {
    "suspicious_links": 0.6,
    "sender_reputation": -0.5,
    "urgent_language": 0.3,
    "attachment_risk": 0.2,
}
bias = -0.1
baseline = {"suspicious_links": 0.1, "sender_reputation": 0.7, "urgent_language": 0.2, "attachment_risk": 0.1}
email_x = {"suspicious_links": 0.8, "sender_reputation": 0.3, "urgent_language": 0.75, "attachment_risk": 0.15}

def score(features):
    return bias + sum(weights[f] * features[f] for f in weights)

score_x = score(email_x)
verdict = "স্প্যাম" if score_x > 0 else "স্বাভাবিক"
print(f"ইমেইলের স্কোর: {score_x:.3f} -> সিদ্ধান্ত: {verdict}")

# --- ফেইথফুল লোকাল এক্সপ্লেনেশন (প্রকৃত অবদান) ---
contributions = {f: weights[f] * (email_x[f] - baseline[f]) for f in weights}
total_contribution = sum(contributions.values())
print("\nফেইথফুল লোকাল এক্সপ্লেনেশন (প্রকৃত অবদান):")
for f, c in sorted(contributions.items(), key=lambda kv: abs(kv[1]), reverse=True):
    share = c / total_contribution * 100
    print(f"  {f}: অবদান {c:+.3f}  (মোটের {share:.1f}%)")

# --- একটি ইচ্ছাকৃত বিভ্রান্তিকর দাবি ---
misleading_claim_feature = "attachment_risk"
misleading_claim_share = 70.0
print(f"\nবিভ্রান্তিকর দাবি: '{misleading_claim_feature}' এই সিদ্ধান্তের প্রায় {misleading_claim_share:.0f}% কারণ।")

# --- কনসিস্টেন্সি চেক: প্রতিটি ফিচার বেসলাইনে বসিয়ে প্রকৃত প্রভাব যাচাই ---
print("\nপার্টার্বেশন-ভিত্তিক কনসিস্টেন্সি চেক (ফিচারটি বেসলাইনে বসালে স্কোর কতটা বদলায়):")
actual_impacts = {}
for f in weights:
    perturbed = dict(email_x)
    perturbed[f] = baseline[f]
    score_perturbed = score(perturbed)
    impact = abs(score_x - score_perturbed)
    actual_impacts[f] = impact
    print(f"  {f} বেসলাইনে বসালে স্কোর {score_x:.3f} থেকে {score_perturbed:.3f}-এ যায় (প্রকৃত প্রভাব: {impact:.3f})")

claimed_feature_actual_share = actual_impacts[misleading_claim_feature] / sum(actual_impacts.values()) * 100
print(f"\n'{misleading_claim_feature}'-এর প্রকৃত প্রভাব-শেয়ার মাত্র {claimed_feature_actual_share:.1f}%"
      f" -- দাবি করা {misleading_claim_share:.0f}%-এর তুলনায় সম্পূর্ণ সামঞ্জস্যহীন।")
print("-> এই এক্সপ্লেনেশনটি কনসিস্টেন্সি চেকে ব্যর্থ, অর্থাৎ এটি বিভ্রান্তিকর।")

    
ফেইথফুল ব্যাখ্যা সঠিকভাবে চিহ্নিত করে যে suspicious_links-ই প্রধান কারণ (অবদান +০.৪২০, মোটের ~৫২.৮%)। কিন্তু বিভ্রান্তিকর ব্যাখ্যা দাবি করে attachment_risk-ই প্রধান কারণ (~৭০%) — অথচ পার্টার্বেশন টেস্ট দেখায় এই ফিচারটি বেসলাইনে বসালে স্কোর মাত্র ০.০১ বদলায় (প্রকৃত শেয়ার মাত্র ~১.৩%)। এটি স্পষ্টভাবে দেখায় দাবি ও বাস্তবতার মধ্যে বিশাল ফারাক — কনসিস্টেন্সি চেক সহজেই এই বিভ্রান্তিকর এক্সপ্লেনেশনটি ধরে ফেলে।

৩ · একাধিক কেসে স্কেল করা — একটি সত্যিকারের সঠিকতা-পরিমাপ

একটি একক উদাহরণে কনসিস্টেন্সি চেক কাজ করছে দেখা যথেষ্ট নয় — এটি নির্ভরযোগ্য কিনা যাচাই করতে হয় একাধিক সিন্থেটিক কেসে। নিচের কোডে চারটি ভিন্ন ইমেইল-কেসের জন্য (প্রতিটিতে ঠিক একটি ফিচার বেসলাইন থেকে সরানো হয়েছে) ফেইথফুল ও বিভ্রান্তিকর — দুই ধরনের ব্যাখ্যাই তৈরি করা হয়েছে, এবং একটি সহজ থ্রেশহোল্ড-ভিত্তিক নিয়ম দিয়ে সেগুলো সঠিকভাবে শনাক্ত হয় কিনা তার সঠিকতা গণনা করা হয়েছে।

Python
weights = {
    "suspicious_links": 0.6,
    "sender_reputation": -0.5,
    "urgent_language": 0.3,
    "attachment_risk": 0.2,
}
baseline = {"suspicious_links": 0.1, "sender_reputation": 0.7, "urgent_language": 0.2, "attachment_risk": 0.1}

def contribution_shares(features):
    contributions = {f: weights[f] * (features[f] - baseline[f]) for f in weights}
    total = sum(abs(c) for c in contributions.values())
    shares = {f: (abs(c) / total * 100 if total else 0) for f, c in contributions.items()}
    return shares

# চারটি সিন্থেটিক কেস -- প্রতিটিতে ঠিক একটি ফিচার বেসলাইন থেকে সরানো হয়েছে
synthetic_cases = {
    "case_suspicious": {**baseline, "suspicious_links": 0.9},
    "case_reputation": {**baseline, "sender_reputation": 0.1},
    "case_urgent": {**baseline, "urgent_language": 0.9},
    "case_attachment": {**baseline, "attachment_risk": 0.9},
}

FLAG_THRESHOLD = 15.0  # দাবি করা "প্রধান ফিচার"-এর প্রকৃত শেয়ার এর চেয়ে কম হলে "সন্দেহজনক" হিসেবে ফ্ল্যাগ হবে

correct = 0
total_checks = 0
for case_name, features in synthetic_cases.items():
    shares = contribution_shares(features)
    real_top = max(shares, key=shares.get)
    real_bottom = min(shares, key=shares.get)

    # ফেইথফুল এক্সপ্লেনেশন: প্রকৃত টপ ফিচার উল্লেখ করে -- ফ্ল্যাগ হওয়া উচিত নয়
    faithful_flagged = shares[real_top] < FLAG_THRESHOLD
    total_checks += 1
    if not faithful_flagged:
        correct += 1

    # বিভ্রান্তিকর এক্সপ্লেনেশন: প্রকৃত বটম ফিচারকে "প্রধান কারণ" বলে দাবি করে -- ফ্ল্যাগ হওয়া উচিত
    misleading_flagged = shares[real_bottom] < FLAG_THRESHOLD
    total_checks += 1
    if misleading_flagged:
        correct += 1

    print(f"{case_name}: প্রকৃত টপ ফিচার={real_top} ({shares[real_top]:.0f}%), "
          f"ফেইথফুল-চেক {'পাস' if not faithful_flagged else 'ফেইল'} | "
          f"মিসলিডিং দাবি={real_bottom} ({shares[real_bottom]:.0f}%), "
          f"মিসলিডিং-চেক {'ধরা পড়েছে' if misleading_flagged else 'ধরা পড়েনি'}")

accuracy = correct / total_checks * 100
print(f"\nমোট {total_checks}টি চেকের মধ্যে {correct}টি সঠিকভাবে শনাক্ত হয়েছে -- সঠিকতা {accuracy:.1f}%")

    
চারটি কেসেই — প্রতিটিতে ঠিক একটি ফিচার বেসলাইন থেকে সরানো হওয়ায় — ফেইথফুল ব্যাখ্যার দাবি করা ফিচারের প্রকৃত শেয়ার সবসময় ১০০% (থ্রেশহোল্ড ১৫%-এর অনেক উপরে, তাই ফ্ল্যাগ হয় না), আর বিভ্রান্তিকর ব্যাখ্যার দাবি করা ফিচারের প্রকৃত শেয়ার সবসময় ০% (থ্রেশহোল্ডের নিচে, তাই ফ্ল্যাগ হয়)। মোট ৮টি চেকের মধ্যে ৮টিই সঠিকভাবে শনাক্ত হয়, অর্থাৎ এই নির্মিত টেস্ট-সেটে সঠিকতা ১০০.০%। বাস্তব ডেটায় এই সঠিকতা কখনো নিখুঁত হবে না (ফিচারগুলো একসাথে মিশ্র প্রভাব ফেলে), কিন্তু পদ্ধতিটি একই থাকে — এবং এটি এমন একটি স্বয়ংক্রিয় "প্রাক-স্ক্রিনিং" যা বাস্তব ব্যবহারকারী-গবেষণা শুরুর আগেই স্পষ্টভাবে ভুল এক্সপ্লেনেশন বাতিল করতে সাহায্য করে।

৪ · বাস্তব ব্যবহারকারীদের সাথে গুণমান যাচাই

স্বয়ংক্রিয় কনসিস্টেন্সি চেক একটি প্রয়োজনীয় প্রথম ধাপ, কিন্তু এটি একা যথেষ্ট নয় — এটি শুধু "ব্যাখ্যাটি মডেলের সাথে সংগত কিনা" পরীক্ষা করে, "ব্যবহারকারী আসলে ব্যাখ্যাটি বুঝতে ও ব্যবহার করতে পারছেন কিনা" নয়। এর জন্য বাস্তব ব্যবহারকারীদের সাথে গবেষণা দরকার:

প্রেডিকশন টেস্ট
ব্যবহারকারীকে একটি এক্সপ্লেনেশন দেখিয়ে জিজ্ঞাসা করা "এই ইনপুট কিছুটা বদলালে ফলাফল কী হবে?" — সঠিক অনুমান করতে পারলে বোঝা যায় এক্সপ্লেনেশনটি প্রকৃতপক্ষে বোধগম্য মডেল তৈরি করেছে।
বিশ্বাস ও সন্তুষ্টি জরিপ
এক্সপ্লেনেশন দেখার পর ব্যবহারকারীর আস্থা ও সন্তুষ্টি Likert-স্কেলে পরিমাপ করা (M9-এ ইউজেবিলিটি ইভালুয়েশন বিস্তারিত)।
থিংক-অ্যালাউড ইন্টারভিউ
ব্যবহারকারীকে জোরে চিন্তা করতে বলে এক্সপ্লেনেশন পড়ার সময় তার প্রতিক্রিয়া, বিভ্রান্তি বা প্রশ্নগুলো সরাসরি পর্যবেক্ষণ করা।
সিদ্ধান্ত-গুণমান তুলনা
এক্সপ্লেনেশনসহ ও এক্সপ্লেনেশন ছাড়া ব্যবহারকারীরা একই কাজে কেমন সিদ্ধান্ত নেন তা তুলনা করা — একটি এক্সপ্লেনেশন সত্যিই সহায়ক কিনা তার চূড়ান্ত পরীক্ষা।
মূল কথা · Key takeaway

একটি এক্সপ্লেনেশনের গুণমান যাচাই করতে দুটো স্তরই দরকার: প্রথমে স্বয়ংক্রিয় কনসিস্টেন্সি চেক (এটি কি মডেলের সাথে সংগত?), তারপর বাস্তব ব্যবহারকারী-গবেষণা (এটি কি মানুষকে সাহায্য করে?)। একটি এক্সপ্লেনেশন প্রথম পরীক্ষায় পাস করেও দ্বিতীয়টিতে ব্যর্থ হতে পারে (টেকনিক্যালি সংগত কিন্তু বোধগম্য নয় — L14-এর মূল সমস্যা), তাই M4-এর কোনো একটি পাঠই একা যথেষ্ট নয় — সবগুলো একসাথে একটি সম্পূর্ণ এক্সপ্লেইনেবিলিটি UX প্র্যাকটিস তৈরি করে।

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

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

প্র ০১ প্রথম কোড সেলে পার্টার্বেশন-ভিত্তিক "প্রকৃত প্রভাব" এবং সরাসরি সূত্র থেকে গণনা করা "অবদান" — এই দুটো সংখ্যা কেন হুবহু মিলে গেল?

কারণ মডেলটি রৈখিক (linear) — প্রতিটি ফিচারের প্রভাব অন্য ফিচারের মান থেকে স্বাধীন। একটি রৈখিক মডেলে, একটি ফিচারকে বেসলাইনে বসিয়ে স্কোরের পরিবর্তন পরিমাপ করা গাণিতিকভাবে ঠিক সেই ফিচারের weight × (value − baseline) অবদানের সমান হবে। বাস্তব, অ-রৈখিক (nonlinear) মডেলে এই দুটো পদ্ধতি সবসময় হুবহু মিলবে না — ফিচারগুলোর মধ্যে ইন্টারঅ্যাকশন থাকলে পার্টার্বেশন-ভিত্তিক পরিমাপই বেশি নির্ভরযোগ্য, কারণ এটি প্রকৃত মডেল-আচরণ পরীক্ষা করে, শুধু একটি সরলীকৃত সূত্র নয়।

প্র ০২ দ্বিতীয় কোড সেলে সঠিকতা ১০০% এসেছে কারণ প্রতিটি সিন্থেটিক কেসে ঠিক একটি ফিচার পরিবর্তন করা হয়েছিল। বাস্তব ডেটায় এটি কেন এত পরিষ্কার হবে না?

বাস্তব সিদ্ধান্তে সাধারণত একাধিক ফিচার একসাথে বেসলাইন থেকে সরে যায়, এবং তাদের প্রভাব প্রায়ই কাছাকাছি মাপের হতে পারে (যেমন দুটি ফিচারের শেয়ার ৪৫% ও ৪০%) — এই ক্ষেত্রে থ্রেশহোল্ড-ভিত্তিক নিয়ম কম নির্ভরযোগ্য হয়ে পড়ে, এবং "প্রধান কারণ" বলাটাই একটি সরলীকরণ হয়ে দাঁড়ায় (L15-এ আলোচিত লোকাল এক্সপ্লেনেশনের সীমাবদ্ধতা)। তাই বাস্তব প্রয়োগে এই চেককে একটি প্রাথমিক ফিল্টার হিসেবে দেখা উচিত, চূড়ান্ত রায় হিসেবে নয়।

প্র ০৩ কেন একটি প্রোডাক্ট টিমের জন্য স্বয়ংক্রিয় কনসিস্টেন্সি চেক থাকা সত্ত্বেও বাস্তব ব্যবহারকারী-গবেষণা এড়িয়ে যাওয়া উচিত নয়?

কারণ একটি এক্সপ্লেনেশন সম্পূর্ণ ফেইথফুল হয়েও (মডেলের সাথে সংগত) ব্যবহারকারীর কাছে বিভ্রান্তিকর, অতিরিক্ত টেকনিক্যাল, বা ভুল প্রশ্নের উত্তর দিতে পারে — এটাই L14-এর মূল বিষয় ছিল। কনসিস্টেন্সি চেক শুধু "সত্যতা" পরিমাপ করে, "উপযোগিতা" নয় — আর একটি ভালো UX-এর জন্য দুটোই দরকার। শুধু একটি স্বয়ংক্রিয় মেট্রিকের উপর নির্ভর করা নিজেই একটি ঝুঁকি, কারণ এটি প্রকৃত মানুষের বোঝাপড়া বাদ দিয়ে দেয়।

অনুশীলন

  1. চিন্তা করুন: প্রথম কোড সেলে যদি বিভ্রান্তিকর দাবিটি attachment_risk-এর বদলে sender_reputation-কে "প্রধান কারণ" বলত (যার প্রকৃত অবদান +০.২০০, মোটের ~২৫.২%), তাহলে কি কনসিস্টেন্সি চেক এটিকেও একইভাবে স্পষ্টভাবে ধরতে পারত?

    অনুমান করা যায় যে ধরা যেত, কিন্তু ততটা স্পষ্টভাবে নয় — কারণ sender_reputation-এর প্রকৃত শেয়ার (~২৫.২%) একেবারে শূন্যের কাছাকাছি নয়, বরং একটি প্রকৃত (যদিও দ্বিতীয়-সর্বোচ্চ) অবদানকারী। দাবি করা "প্রধান কারণ" (যেখানে সবচেয়ে বড় অবদানকারী suspicious_links, ~৫২.৮%) এর সাথে এখনও গরমিল থাকবে, তবে গ্যাপটি ৭০% বনাম ১.৩%-এর মতো নাটকীয় হবে না — এটি দেখায় থ্রেশহোল্ড-ভিত্তিক চেক আংশিকভাবে ভুল দাবির ক্ষেত্রে কম নিশ্চিতভাবে কাজ করে।

  2. পরীক্ষা করুন: প্রথম কোড সেলে misleading_claim_feature = "attachment_risk"-কে misleading_claim_feature = "sender_reputation"-এ পরিবর্তন করে Run চেপে আসল প্রকৃত-শেয়ার সংখ্যাটি দেখুন।

    যাচাই করলে দেখা যায় sender_reputation-এর প্রকৃত প্রভাব-শেয়ার ~২৫.২% — দাবি করা ৭০%-এর তুলনায় এখনও স্পষ্টভাবে কম, তাই কনসিস্টেন্সি চেক এটিকেও অসংগত হিসেবে চিহ্নিত করে। তবে পার্থক্যের মাত্রা (৭০% বনাম ২৫.২%, অর্থাৎ প্রায় ২.৮ গুণ) আগের কেসের (৭০% বনাম ১.৩%, প্রায় ৫৪ গুণ) তুলনায় অনেক কম নাটকীয় — এটি ঠিক অনুমান ১-কে নিশ্চিত করে: আংশিকভাবে ভুল ব্যাখ্যা শনাক্ত করা সম্পূর্ণ ভুল ব্যাখ্যা শনাক্ত করার চেয়ে কঠিন।

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

আগের পাঠ
প্রোগ্রেসিভ ডিসক্লোজার — ধাপে ধাপে এক্সপ্লেনেশন