تاریخ انتشار: 13 نوامبر 2024
سخنان مشوق تنفر، آزار و اذیت و سوء استفاده آنلاین به یک موضوع فراگیر در فضای مجازی تبدیل شده است. نظرات سمی صداهای مهم را خاموش می کند و کاربران و مشتریان را دور می کند . تشخیص سمیت از کاربران شما محافظت می کند و محیط آنلاین امن تری ایجاد می کند.
در این سری دو قسمتی، نحوه استفاده از هوش مصنوعی برای شناسایی و کاهش سمیت در منبع آن: صفحه کلید کاربران را بررسی می کنیم.
در بخش اول ، موارد استفاده و مزایای این رویکرد را مورد بحث قرار دادیم.
در این بخش دوم، به پیاده سازی، از جمله نمونه کد و نکات UX می پردازیم.
نسخه ی نمایشی و کد
با نسخه نمایشی ما بازی کنید و کد را در GitHub بررسی کنید.
پشتیبانی از مرورگر
نسخه ی نمایشی ما در آخرین نسخه های Safari، Chrome، Edge و Firefox اجرا می شود.
مدل و کتابخانه را انتخاب کنید
ما از کتابخانه Transformers.js Hugging Face استفاده می کنیم که ابزارهایی را برای کار با مدل های یادگیری ماشین در مرورگر ارائه می دهد. کد آزمایشی ما از این مثال طبقه بندی متن مشتق شده است.
ما مدل سمی-برت را انتخاب می کنیم، یک مدل از پیش آموزش دیده طراحی شده برای شناسایی الگوهای زبان سمی. این یک نسخه سازگار با وب از unitary/toxic-bert است. برای جزئیات بیشتر در مورد برچسب های مدل و طبقه بندی آن از حملات هویتی، به صفحه مدل Hugging Face مراجعه کنید.
پس از دانلود مدل، استنتاج سریع است.
برای مثال، معمولاً کمتر از 500 میلیثانیه در Chrome اجرا میشود که روی دستگاه اندرویدی میانردهای که ما روی آن آزمایش کردهایم (یک گوشی معمولی پیکسل 7، نه مدل Pro با کاراییتر) اجرا میشود. معیارهای خود را اجرا کنید که معرف پایگاه کاربری شما هستند.
پیاده سازی
در اینجا مراحل کلیدی در اجرای ما آمده است:
یک آستانه سمیت تعیین کنید
طبقه بندی سمیت ما امتیازات سمیت را بین 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);
ایجاد خط لوله، مانند کد مثال، اولین گام برای اجرای وظایف استنتاج است.
تابع خط لوله دو آرگومان می گیرد: وظیفه ( 'text-classification'
) و مدل ( Xenova/toxic-bert
).
اصطلاح کلیدی: در Transformers.js، خط لوله یک API سطح بالا است که فرآیند اجرای مدلهای ML را ساده میکند. وظایفی مانند بارگذاری مدل، توکن سازی و پس پردازش را انجام می دهد.
کد آزمایشی ما کمی بیشتر از آمادهسازی مدل انجام میدهد، زیرا ما مراحل آمادهسازی مدل از لحاظ محاسباتی پرهزینه را برای یک وبکارگر بارگذاری میکنیم. این به موضوع اصلی اجازه می دهد تا پاسخگو باقی بماند. درباره بارگذاری وظایف گران قیمت به یک کارمند وب بیشتر بیاموزید.
کارگر ما باید با موضوع اصلی ارتباط برقرار کند و از پیام هایی برای نشان دادن وضعیت مدل و نتایج ارزیابی سمیت استفاده کند. به کدهای پیامی که برای وضعیت های مختلف چرخه حیات آماده سازی و استنتاج مدل ایجاد کرده ایم، نگاهی بیندازید.
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;
}
زمانی که thread اصلی از کارگر بخواهد، تابع طبقه بندی خود را فراخوانی می کنیم. در نسخه نمایشی خود، به محض اینکه کاربر تایپ را متوقف کرد، طبقهبندیکننده را فعال میکنیم (به 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 به طور موثر سمیت آشکار را تشخیص می دهد، ممکن است با موارد ظریف تر یا وابسته به زمینه (کنایه، کنایه) مبارزه کند. مسمومیت می تواند بسیار ذهنی و ظریف باشد. به عنوان مثال، ممکن است بخواهید برخی اصطلاحات یا حتی شکلکها به عنوان سمی طبقهبندی شوند. تنظیم دقیق می تواند به بهبود دقت در این زمینه ها کمک کند.
ما یک مقاله آینده در مورد تنظیم دقیق یک مدل سمیت داریم.
جایگزین ها
- MediaPipe برای طبقه بندی متن . مطمئن شوید که از مدلی استفاده میکنید که با وظایف طبقهبندی سازگار باشد.
طبقه بندی کننده سمیت TensorFlow.js . مدلی را ارائه میکند که کوچکتر و سریعتر واکشی میشود، اما مدتی است که بهینهسازی نشده است، بنابراین ممکن است متوجه شوید که استنتاج تا حدودی کندتر از Transformers.js است.
نتیجه گیری
تشخیص سمیت سمت مشتری ابزاری قدرتمند برای تقویت جوامع آنلاین است.
با استفاده از مدلهای هوش مصنوعی مانند toxic-bert که در مرورگر با Transformers.js اجرا میشوند، میتوانید مکانیسمهای بازخورد بلادرنگ را پیادهسازی کنید که رفتار سمی را کاهش میدهد و بار طبقهبندی سمیت را روی سرورهایتان کاهش میدهد.
این رویکرد سمت مشتری در حال حاضر در مرورگرها کار می کند. با این حال، محدودیت ها را به خاطر داشته باشید، به خصوص از نظر هزینه های سرویس مدل و اندازه دانلود. بهترین شیوه های عملکرد را برای هوش مصنوعی سمت سرویس گیرنده اعمال کنید و مدل را حافظه پنهان کنید .
برای تشخیص جامع سمیت، رویکردهای سمت مشتری و سمت سرور را ترکیب کنید.