ส่วนที่ 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

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

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

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

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

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

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

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

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

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

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

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

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

บทสรุป

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

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

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

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