قسمت 2: ساخت تشخیص سمیت هوش مصنوعی در سمت مشتری

ماد نالپاس
Maud Nalpas

منتشر شده: ۱۳ نوامبر ۲۰۲۴

نفرت‌پراکنی، آزار و اذیت و سوءاستفاده آنلاین به یک مسئله فراگیر در فضای آنلاین تبدیل شده است. نظرات سمی ، صداهای مهم را ساکت کرده و کاربران و مشتریان را فراری می‌دهد . تشخیص سمیت از کاربران شما محافظت می‌کند و محیط آنلاین امن‌تری ایجاد می‌کند.

در این مجموعه دو قسمتی، ما بررسی می‌کنیم که چگونه از هوش مصنوعی برای شناسایی و کاهش سمیت در منبع آن استفاده کنیم: صفحه کلیدهای کاربران.

در بخش اول ، موارد استفاده و مزایای این رویکرد را مورد بحث قرار دادیم.

در بخش دوم، به پیاده‌سازی، از جمله مثال‌های کد و نکات UX، می‌پردازیم.

نسخه آزمایشی و کد

با نسخه آزمایشی ما کار کنید و کد موجود در گیت‌هاب را بررسی کنید.

نسخه آزمایشی ارسال نظر.
وقتی کاربر تایپ کردن را متوقف می‌کند، ما میزان سمی بودن نظر او را بررسی می‌کنیم. اگر نظر به عنوان سمی طبقه‌بندی شود، در لحظه هشداری نمایش می‌دهیم.

پشتیبانی مرورگر

نسخه آزمایشی ما در آخرین نسخه‌های سافاری، کروم، اج و فایرفاکس اجرا می‌شود.

انتخاب مدل و کتابخانه

ما از کتابخانه Transformers.js متعلق به Hugging Face استفاده می‌کنیم که ابزارهایی برای کار با مدل‌های یادگیری ماشین در مرورگر فراهم می‌کند. کد آزمایشی ما از این مثال طبقه‌بندی متن گرفته شده است.

ما مدل toxic-bert را انتخاب می‌کنیم، یک مدل از پیش آموزش‌دیده که برای شناسایی الگوهای زبانی سمی طراحی شده است. این مدل، نسخه‌ای سازگار با وب از unitary/toxic-bert است. برای جزئیات بیشتر در مورد برچسب‌های این مدل و طبقه‌بندی حملات هویتی آن، به صفحه مدل Hugging Face مراجعه کنید.

حجم دانلود toxic-bert 111 مگابایت است.

پس از دانلود مدل، استنتاج سریع انجام می‌شود.

برای مثال، معمولاً اجرای کروم روی یک دستگاه اندرویدی میان‌رده که ما روی آن آزمایش کرده‌ایم (یک گوشی معمولی پیکسل ۷، نه مدل پرو با عملکرد بهتر)، کمتر از ۵۰۰ میلی‌ثانیه طول می‌کشد. بنچمارک‌های خودتان را که نماینده‌ی پایگاه کاربری شما هستند، اجرا کنید.

پیاده‌سازی

در اینجا مراحل کلیدی در پیاده‌سازی ما آمده است:

تعیین آستانه سمیت

طبقه‌بندی‌کننده‌ی سمیت ما، امتیازهای سمیت بین 0 و 1 را ارائه می‌دهد. در این محدوده، باید آستانه‌ای برای تعیین اینکه چه چیزی یک نظر سمی محسوب می‌شود، تعیین کنیم. آستانه‌ی رایج 0.9 است. این به شما امکان می‌دهد نظرات آشکارا سمی را تشخیص دهید، در حالی که از حساسیت بیش از حد که می‌تواند منجر به مثبت‌های کاذب زیادی شود (به عبارت دیگر، نظرات بی‌ضرر که به عنوان سمی طبقه‌بندی می‌شوند) جلوگیری می‌کند.

export const TOXICITY_THRESHOLD = 0.9

کامپوننت‌ها را وارد کنید

ما با وارد کردن اجزای لازم از کتابخانه @xenova/transformers شروع می‌کنیم. همچنین ثابت‌ها و مقادیر پیکربندی، از جمله آستانه سمیت خود را وارد می‌کنیم.

import { env, pipeline } from '@xenova/transformers';
// Model name: 'Xenova/toxic-bert'
// Our threshold is set to 0.9
import { TOXICITY_THRESHOLD, MODEL_NAME } from './config.js';

مدل را بارگذاری کنید و با نخ اصلی ارتباط برقرار کنید

ما مدل تشخیص سمیت toxic-bert را بارگذاری می‌کنیم و از آن برای آماده‌سازی طبقه‌بندی‌کننده خود استفاده می‌کنیم. ساده‌ترین نسخه این روش const classifier = await pipeline('text-classification', MODEL_NAME);

ایجاد یک خط لوله، مانند کد مثال، اولین قدم برای اجرای وظایف استنتاج است.

تابع pipeline دو آرگومان می‌گیرد: وظیفه ( 'text-classification' ) و مدل ( Xenova/toxic-bert ).

اصطلاح کلیدی: در Transformers.js، پایپ‌لاین یک API سطح بالا است که فرآیند اجرای مدل‌های یادگیری ماشین را ساده می‌کند. این پایپ‌لاین وظایفی مانند بارگذاری مدل، توکن‌سازی و پس‌پردازش را مدیریت می‌کند.

کد آزمایشی ما کمی بیشتر از آماده‌سازی مدل انجام می‌دهد، زیرا ما مراحل آماده‌سازی مدل که از نظر محاسباتی پرهزینه است را به یک وب ورکر واگذار می‌کنیم. این کار به نخ اصلی اجازه می‌دهد تا پاسخگو باقی بماند. درباره واگذاری وظایف پرهزینه به یک وب ورکر بیشتر بدانید.

کارگر ما باید با نخ اصلی ارتباط برقرار کند و از پیام‌هایی برای نشان دادن وضعیت مدل و نتایج ارزیابی سمیت استفاده کند. به کدهای پیامی که ایجاد کرده‌ایم نگاهی بیندازید که وضعیت‌های مختلف چرخه حیات آماده‌سازی مدل و استنتاج را نگاشت می‌کنند.

let classifier = null;
(async function () {
  // Signal to the main thread that model preparation has started
  self.postMessage({ code: MESSAGE_CODE.PREPARING_MODEL, payload: null });
  try {
    // Prepare the model
    classifier = await pipeline('text-classification', MODEL_NAME);
    // Signal to the main thread that the model is ready
    self.postMessage({ code: MESSAGE_CODE.MODEL_READY, payload: null });
  } catch (error) {
    console.error('[Worker] Error preparing model:', error);
    self.postMessage({ code: MESSAGE_CODE.MODEL_ERROR, payload: null });
  }
})();

دسته‌بندی ورودی‌های کاربر

در تابع classify خود، از طبقه‌بندی‌کننده‌ی قبلی ایجاد شده برای تحلیل نظر کاربر استفاده می‌کنیم. خروجی خام طبقه‌بندی‌کننده‌ی سمیت را برمی‌گردانیم: برچسب‌ها و امتیازها.

// Asynchronous function to classify user input
// output: [{ label: 'toxic', score: 0.9243140482902527 },
// ... { label: 'insult', score: 0.96187334060668945 }
// { label: 'obscene', score: 0.03452680632472038 }, ...etc]
async function classify(text) {
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  let results = await classifier(text, { topk: null });
  return results;
}

ما تابع طبقه‌بندی خود را زمانی فراخوانی می‌کنیم که نخ اصلی از کارگر بخواهد این کار را انجام دهد. در نسخه آزمایشی ما، به محض اینکه کاربر تایپ کردن را متوقف کرد، طبقه‌بندی‌کننده را فعال می‌کنیم (به TYPING_DELAY مراجعه کنید). وقتی این اتفاق می‌افتد، نخ اصلی ما پیامی را به کارگر ارسال می‌کند که حاوی ورودی کاربر برای طبقه‌بندی است.

self.onmessage = async function (message) {
  // User input
  const textToClassify = message.data;
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  self.postMessage({ code: MESSAGE_CODE.GENERATING_RESPONSE, payload: null });

  // Inference: run the classifier
  let classificationResults = null;
  try {
    classificationResults = await classify(textToClassify);
  } catch (error) {
    console.error('[Worker] Error: ', error);
    self.postMessage({
      code: MESSAGE_CODE.INFERENCE_ERROR,
    });
    return;
  }
  const toxicityTypes = getToxicityTypes(classificationResults);
  const toxicityAssessement = {
    isToxic: toxicityTypes.length > 0,
    toxicityTypeList: toxicityTypes.length > 0 ? toxicityTypes.join(', ') : '',
  };
  console.info('[Worker] Toxicity assessed: ', toxicityAssessement);
  self.postMessage({
    code: MESSAGE_CODE.RESPONSE_READY,
    payload: toxicityAssessement,
  });
};

پردازش خروجی

ما بررسی می‌کنیم که آیا امتیازهای خروجی طبقه‌بندی‌کننده از آستانه ما فراتر رفته است یا خیر. در این صورت، برچسب مورد نظر را یادداشت می‌کنیم.

اگر هر یک از برچسب‌های سمیت ذکر شده باشد، نظر به عنوان بالقوه سمی علامت‌گذاری می‌شود.

// input: [{ label: 'toxic', score: 0.9243140482902527 }, ...
// { label: 'insult', score: 0.96187334060668945 },
// { label: 'obscene', score: 0.03452680632472038 }, ...etc]
// output: ['toxic', 'insult']
function getToxicityTypes(results) {
  const toxicityAssessment = [];
  for (let element of results) {
    // If a label's score > our threshold, save the label
    if (element.score > TOXICITY_THRESHOLD) {
      toxicityAssessment.push(element.label);
    }
  }
  return toxicityAssessment;
}

self.onmessage = async function (message) {
  // User input
  const textToClassify = message.data;
  if (!classifier) {
    throw new Error("Can't run inference, the model is not ready yet");
  }
  self.postMessage({ code: MESSAGE_CODE.GENERATING_RESPONSE, payload: null });

  // Inference: run the classifier
  let classificationResults = null;
  try {
    classificationResults = await classify(textToClassify);
  } catch (error) {
    self.postMessage({
      code: MESSAGE_CODE.INFERENCE_ERROR,
    });
    return;
  }
  const toxicityTypes = getToxicityTypes(classificationResults);
  const toxicityAssessement = {
    // If any toxicity label is listed, the comment is flagged as
    // potentially toxic (isToxic true)
    isToxic: toxicityTypes.length > 0,
    toxicityTypeList: toxicityTypes.length > 0 ? toxicityTypes.join(', ') : '',
  };
  self.postMessage({
    code: MESSAGE_CODE.RESPONSE_READY,
    payload: toxicityAssessement,
  });
};

نمایش یک راهنمایی

اگر isToxic درست باشد، یک راهنما به کاربر نمایش می‌دهیم. در نسخه آزمایشی ما، از نوع سمیت دقیق‌تر استفاده نمی‌کنیم، اما در صورت نیاز آن را در دسترس نخ اصلی قرار داده‌ایم ( toxicityTypeList ). ممکن است برای مورد استفاده شما مفید باشد.

تجربه کاربری

در نسخه آزمایشی ما، انتخاب‌های زیر را انجام داده‌ایم:

  • همیشه اجازه ارسال مطلب را بدهید. هشدار سمیت سمت کلاینت ما مانع از ارسال مطلب توسط کاربر نمی‌شود. در نسخه آزمایشی ما، کاربر می‌تواند حتی اگر مدل بارگذاری نشده باشد (و بنابراین ارزیابی سمیت ارائه نمی‌دهد) و حتی اگر نظر به عنوان سمی تشخیص داده شود، نظر ارسال کند. همانطور که توصیه شده است ، شما باید یک سیستم دوم برای تشخیص نظرات سمی داشته باشید. اگر برای برنامه شما منطقی است، به کاربر اطلاع دهید که نظر او در کلاینت ارسال شده است، اما سپس در سرور یا در حین بازرسی انسانی علامت‌گذاری شده است.
  • به منفی‌های کاذب توجه کنید . وقتی نظری به عنوان سمی طبقه‌بندی نشده باشد، نسخه آزمایشی ما بازخوردی ارائه نمی‌دهد (مثلاً «نظر خوبی بود!».) ارائه بازخورد مثبت، جدا از اینکه پر سر و صدا است، ممکن است سیگنال اشتباهی ارسال کند، زیرا طبقه‌بندی‌کننده ما گهگاه اما ناگزیر برخی از نظرات سمی را از دست می‌دهد.
نسخه آزمایشی ارسال نظر.
دکمه ارسال همیشه فعال است: در نسخه آزمایشی ما، کاربر همچنان می‌تواند تصمیم به ارسال نظر خود بگیرد، حتی اگر به عنوان سمی طبقه‌بندی شده باشد. حتی اگر نظری به عنوان سمی طبقه‌بندی نشده باشد، ما بازخورد مثبت نمایش نمی‌دهیم.

پیشرفت‌ها و جایگزین‌ها

محدودیت‌ها و پیشرفت‌های آینده

  • زبان‌ها : مدلی که ما استفاده می‌کنیم در درجه اول از انگلیسی پشتیبانی می‌کند. برای پشتیبانی چندزبانه، نیاز به تنظیم دقیق دارید. چندین مدل سمیت ذکر شده در Hugging Face از زبان‌های غیر انگلیسی (روسی، هلندی) پشتیبانی می‌کنند، اگرچه در حال حاضر با Transformers.js سازگار نیستند.
  • نکات ظریف : اگرچه toxic-bert به طور مؤثر سمیت آشکار را تشخیص می‌دهد، اما ممکن است در موارد ظریف‌تر یا وابسته به زمینه (طعنه، کنایه) مشکل داشته باشد. سمیت می‌تواند بسیار ذهنی و نامحسوس باشد. به عنوان مثال، ممکن است بخواهید اصطلاحات یا حتی ایموجی‌های خاصی به عنوان سمی طبقه‌بندی شوند. تنظیم دقیق می‌تواند به بهبود دقت در این زمینه‌ها کمک کند.

ما به زودی مقاله‌ای در مورد تنظیم دقیق مدل سمیت خواهیم داشت.

جایگزین‌ها

نتیجه‌گیری

تشخیص سمیت سمت کلاینت ابزاری قدرتمند برای بهبود جوامع آنلاین است.

با بهره‌گیری از مدل‌های هوش مصنوعی مانند toxic-bert که در مرورگر با Transformers.js اجرا می‌شوند، می‌توانید مکانیسم‌های بازخورد بلادرنگ را پیاده‌سازی کنید که رفتارهای سمی را کاهش داده و بار طبقه‌بندی سمیت را روی سرورهای شما کاهش می‌دهد.

این رویکرد سمت کلاینت از قبل در مرورگرها کار می‌کند. با این حال، محدودیت‌ها را در نظر داشته باشید، به خصوص از نظر هزینه‌های ارائه مدل و حجم دانلود. بهترین شیوه‌های عملکرد را برای هوش مصنوعی سمت کلاینت اعمال کنید و مدل را ذخیره کنید .

برای تشخیص جامع سمیت، رویکردهای سمت کلاینت و سمت سرور را با هم ترکیب کنید.