ส่วนที่ 2: สร้างการตรวจหาเนื้อหาที่เป็นพิษด้วย AI ฝั่งไคลเอ็นต์

Maud Nalpas
Maud Nalpas

เผยแพร่: 13 พฤศจิกายน 2024

วาจาสร้างความเกลียดชัง การคุกคาม และการละเมิดทางออนไลน์กลายเป็นปัญหาที่แพร่หลายบนโลกออนไลน์ ความคิดเห็นที่เป็นพิษปิดกั้นเสียงที่สำคัญ และทำให้ผู้ใช้และลูกค้าหนีหาย การตรวจหาความเป็นพิษจะช่วยปกป้องผู้ใช้และสร้างสภาพแวดล้อมออนไลน์ที่ปลอดภัยยิ่งขึ้น

ในซีรีส์ 2 ตอนนี้ เราจะมาดูวิธีใช้ AI เพื่อตรวจหาและลดความเป็นพิษ ที่ต้นทาง ซึ่งก็คือคีย์บอร์ดของผู้ใช้

ในส่วนที่ 1 เราได้พูดถึงกรณีการใช้งาน และประโยชน์ของแนวทางนี้

ในส่วนที่ 2 นี้ เราจะเจาะลึกถึงการใช้งาน รวมถึงตัวอย่างโค้ด และเคล็ดลับ UX

การสาธิตและโค้ด

ลองใช้เดโม และดูโค้ดใน GitHub

การสาธิตการโพสต์ความคิดเห็น
เมื่อผู้ใช้หยุดพิมพ์ เราจะวิเคราะห์ความเป็นพิษของความคิดเห็น ของผู้ใช้ เราจะแสดงคำเตือนแบบเรียลไทม์หากระบบจัดประเภทความคิดเห็นว่า เป็นพิษ

การสนับสนุนเบราว์เซอร์

เดโมของเราทำงานใน Safari, Chrome, Edge และ Firefox เวอร์ชันล่าสุด

เลือกรุ่นและคลัง

เราใช้ไลบรารี Transformers.js ของ Hugging Face ซึ่งมีเครื่องมือสำหรับทำงานกับโมเดลแมชชีนเลิร์นนิงใน เบราว์เซอร์ โค้ดเดโมของเราได้มาจากตัวอย่างการจัดประเภทข้อความนี้

เราเลือกโมเดล toxic-bert ซึ่งเป็นโมเดลที่ได้รับการฝึกมาก่อนและออกแบบมาเพื่อระบุรูปแบบภาษาที่เป็นพิษ ซึ่งเป็นเวอร์ชันที่ใช้กับเว็บได้ของ unitary/toxic-bert ดูรายละเอียดเพิ่มเติมเกี่ยวกับป้ายกำกับของโมเดลและการแยกประเภทการโจมตีเพื่อขโมยข้อมูลประจำตัวได้ที่หน้าโมเดล Hugging Face

ขนาดการดาวน์โหลดของ toxic-bert คือ 111 MB

เมื่อดาวน์โหลดโมเดลแล้ว การอนุมานจะรวดเร็ว

ตัวอย่างเช่น โดยปกติแล้วจะใช้เวลาน้อยกว่า 500 มิลลิวินาทีใน Chrome ที่ทำงานบน อุปกรณ์ Android ระดับกลางที่เราทดสอบ (โทรศัพท์ Pixel 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);

การสร้างไปป์ไลน์ เช่น ในโค้ดตัวอย่าง เป็นขั้นตอนแรกในการเรียกใช้ งานการอนุมาน

ฟังก์ชันไปป์ไลน์รับอาร์กิวเมนต์ 2 รายการ ได้แก่ งาน ('text-classification') และโมเดล (Xenova/toxic-bert)

คำสำคัญ: ใน Transformers.js ไปป์ไลน์คือ API ระดับสูงที่ช่วยลดความซับซ้อน ของกระบวนการเรียกใช้โมเดล ML โดยจะจัดการงานต่างๆ เช่น การโหลดโมเดล การแยกโทเค็น และการประมวลผลภายหลัง

โค้ดตัวอย่างของเราทำได้มากกว่าแค่การเตรียมโมเดล เนื่องจากเรา จะส่งต่อขั้นตอนการเตรียมโมเดลที่ใช้การคำนวณสูงไปยัง Web Worker ซึ่งจะช่วยให้เธรดหลักยังคงตอบสนองได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับ การส่งต่อภาระงานที่มีค่าใช้จ่ายสูงไปยัง Web Worker

Worker ของเราต้องสื่อสารกับเทรดหลักโดยใช้ข้อความเพื่อระบุสถานะของโมเดลและผลการประเมินความเป็นพิษ ดูรหัสข้อความ ที่เราสร้างขึ้นซึ่งเชื่อมโยงกับสถานะต่างๆ ของการเตรียมโมเดลและ วงจรการอนุมาน

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;
}

เราจะเรียกใช้ฟังก์ชันการจัดประเภทเมื่อเทรดหลักขอให้ Worker ทำเช่นนั้น ในการสาธิต เราจะทริกเกอร์ตัวแยกประเภททันทีที่ผู้ใช้หยุดพิมพ์ (ดู TYPING_DELAY) เมื่อเกิดเหตุการณ์นี้ขึ้น เทรดหลักจะส่งข้อความไปยัง Worker ซึ่งมีข้อมูลที่ผู้ใช้ป้อนเพื่อจัดประเภท

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) คุณอาจพบว่ามีประโยชน์สำหรับกรณีการใช้งานของคุณ

ประสบการณ์ของผู้ใช้

ในเดโม เราได้เลือกตัวเลือกต่อไปนี้

  • อนุญาตให้โพสต์เสมอ คำแนะนำเกี่ยวกับความเป็นพิษฝั่งไคลเอ็นต์ของเราไม่ได้ป้องกันไม่ให้ ผู้ใช้โพสต์ ในการสาธิตของเรา ผู้ใช้จะโพสต์ความคิดเห็นได้แม้ว่าโมเดลจะยังโหลดไม่เสร็จ (และไม่ได้เสนอการประเมินความเป็นพิษ) และแม้ว่าระบบจะตรวจพบว่าความคิดเห็นนั้นเป็นพิษก็ตาม ตามที่แนะนำ คุณควรมีระบบที่ 2 เพื่อตรวจหาความคิดเห็นที่เป็นพิษ หากเหมาะสมกับแอปพลิเคชันของคุณ ให้พิจารณาแจ้งให้ผู้ใช้ทราบว่าความคิดเห็นของตนผ่านการตรวจสอบที่ฝั่งไคลเอ็นต์แล้ว แต่ถูกแจ้งว่าไม่เหมาะสมในเซิร์ฟเวอร์หรือระหว่างการตรวจสอบโดยเจ้าหน้าที่
  • ระวังผลลบลวง เมื่อระบบไม่จัดประเภทความคิดเห็นว่าเป็นการคุกคาม เดโมของเราจะไม่แสดงความคิดเห็น (เช่น "ความคิดเห็นดีมาก!") นอกเหนือจากจะทำให้เกิดเสียงรบกวนแล้ว การให้ความคิดเห็นเชิงบวกอาจส่งสัญญาณที่ไม่ถูกต้อง เนื่องจากเครื่องมือจัดประเภทของเรา อาจพลาดความคิดเห็นที่เป็นพิษบางรายการเป็นครั้งคราว
การสาธิตการโพสต์ความคิดเห็น
ปุ่มโพสต์จะเปิดใช้เสมอ ในการสาธิตของเรา ผู้ใช้จะยังคงตัดสินใจโพสต์ความคิดเห็นได้แม้ว่าระบบจะจัดประเภทความคิดเห็นนั้นว่าไม่เหมาะสมก็ตาม และแม้ว่าระบบจะไม่จัดประเภทความคิดเห็นว่าไม่เหมาะสม เราก็จะไม่แสดงความคิดเห็นเชิงบวก

การเพิ่มประสิทธิภาพและทางเลือกอื่นๆ

ข้อจำกัดและการปรับปรุงในอนาคต

  • ภาษา: โมเดลที่เราใช้รองรับภาษาอังกฤษเป็นหลัก หากต้องการ การรองรับหลายภาษา คุณต้องปรับแต่ง โมเดลความเป็นพิษหลายรายการ ที่แสดงใน Hugging Face รองรับภาษาที่ไม่ใช่ภาษาอังกฤษ (รัสเซีย ดัตช์) แม้ว่าจะไม่สามารถใช้ร่วมกับ Transformers.js ได้ในขณะนี้
  • ความแตกต่างเล็กๆ น้อยๆ: แม้ว่า Toxic-BERT จะตรวจจับความเป็นพิษที่โจ่งแจ้งได้อย่างมีประสิทธิภาพ แต่ก็อาจ มีปัญหาในกรณีที่ซับซ้อนกว่าหรือขึ้นอยู่กับบริบท (การประชดประชัน การเสียดสี) ความเป็นพิษอาจเป็นเรื่องที่ขึ้นอยู่กับแต่ละบุคคลและอาจเกิดขึ้นอย่างแนบเนียน เช่น คุณอาจต้องการให้ระบบจัดประเภทคำบางคำหรือแม้แต่อีโมจิเป็นคำที่เป็นพิษ การปรับแต่งจะช่วยปรับปรุงความแม่นยำในด้านต่างๆ เหล่านี้ได้

เรากำลังจะมีบทความเกี่ยวกับการปรับแต่งโมเดลความเป็นพิษ

ตัวเลือกอื่นๆ

บทสรุป

การตรวจหาความเป็นพิษฝั่งไคลเอ็นต์เป็นเครื่องมือที่มีประสิทธิภาพในการปรับปรุงชุมชนออนไลน์

การใช้ประโยชน์จากโมเดล AI เช่น Toxic-BERT ที่ทำงานในเบราว์เซอร์ด้วย Transformers.js จะช่วยให้คุณใช้กลไกความคิดเห็นแบบเรียลไทม์ที่ยับยั้ง พฤติกรรมที่เป็นพิษและลดภาระการจัดประเภทความเป็นพิษในเซิร์ฟเวอร์ได้

แนวทางฝั่งไคลเอ็นต์นี้ใช้ได้กับเบราว์เซอร์ต่างๆ อยู่แล้ว อย่างไรก็ตาม โปรดคำนึงถึงข้อจำกัด โดยเฉพาะในแง่ของต้นทุนการแสดงโมเดลและขนาดการดาวน์โหลด ใช้แนวทางปฏิบัติแนะนำด้านประสิทธิภาพสำหรับ AI ฝั่งไคลเอ็นต์ และแคชโมเดล

รวมแนวทางฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์เพื่อตรวจหาความเป็นพิษอย่างครอบคลุม