Bagian 2: Membuat deteksi toksisitas AI sisi klien

Maud Nalpas
Maud Nalpas

Dipublikasikan: 13 November 2024

Ujaran kebencian, pelecehan, dan pelecehan online telah menjadi masalah yang meluas di internet. Komentar beracun membungkam suara penting dan mengusir pengguna dan pelanggan. Deteksi konten beracun melindungi pengguna Anda dan menciptakan lingkungan online yang lebih aman.

Dalam serial dua bagian ini, kita akan mempelajari cara menggunakan AI untuk mendeteksi dan mengurangi konten beracun di sumbernya: keyboard pengguna.

Di bagian satu, kita telah membahas kasus penggunaan dan manfaat pendekatan ini.

Di bagian kedua ini, kita akan membahas implementasi, termasuk contoh kode dan tips UX.

Demo dan kode

Coba demo kami dan pelajari kode di GitHub.

Demo memposting komentar.
Saat pengguna berhenti mengetik, kami menganalisis toksisitas komentar mereka. Kami menampilkan peringatan secara real-time jika komentar diklasifikasikan sebagai komentar negatif.

Dukungan browser

Demo kami berjalan di Safari, Chrome, Edge, dan Firefox versi terbaru.

Memilih model dan library

Kita menggunakan library Transformers.js Hugging Face, yang menyediakan alat untuk menggunakan model machine learning di browser. Kode demo kami berasal dari contoh klasifikasi teks ini.

Kami memilih model toxic-bert, yaitu model terlatih sebelumnya yang dirancang untuk mengidentifikasi pola bahasa negatif. Ini adalah versi unitary/toxic-bert yang kompatibel dengan web. Untuk mengetahui detail selengkapnya tentang label model dan klasifikasi serangan identitasnya, lihat halaman model Hugging Face.

Ukuran download toxic-bert adalah 111 MB.

Setelah model didownload, inferensi akan cepat.

Misalnya, biasanya diperlukan waktu kurang dari 500 milidetik di Chrome yang berjalan di perangkat Android kelas menengah yang telah kami uji (ponsel Pixel 7 biasa, bukan model Pro yang berperforma lebih tinggi). Jalankan benchmark Anda sendiri yang mewakili basis pengguna Anda.

Penerapan

Berikut adalah langkah-langkah utama dalam penerapan kami:

Menetapkan nilai minimum toksisitas

Pengklasifikasi toksisitas kami memberikan skor toksisitas antara 0 dan 1. Dalam rentang tersebut, kita perlu menetapkan nilai minimum untuk menentukan apa yang dimaksud dengan komentar toksik. Nilai minimum yang biasa digunakan adalah 0.9. Dengan begitu, Anda dapat menemukan komentar yang sangat bersifat toksik, sekaligus menghindari sensitivitas yang berlebihan yang dapat menyebabkan terlalu banyak hasil positif palsu (dengan kata lain, komentar tidak berbahaya yang dikategorikan sebagai toksik).

export const TOXICITY_THRESHOLD = 0.9

Mengimpor komponen

Kita mulai dengan mengimpor komponen yang diperlukan dari library @xenova/transformers. Kami juga mengimpor konstanta dan nilai konfigurasi, termasuk nilai ambang toksisitas.

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

Memuat model dan berkomunikasi dengan thread utama

Kita memuat model deteksi toksisitas toxic-bert, dan menggunakannya untuk menyiapkan klasifikasi. Versi yang paling tidak kompleks adalah const classifier = await pipeline('text-classification', MODEL_NAME);

Membuat pipeline, seperti dalam contoh kode, adalah langkah pertama untuk menjalankan tugas inferensi.

Fungsi pipeline menggunakan dua argumen: tugas ('text-classification') dan model (Xenova/toxic-bert).

Istilah penting: Di Transformers.js, pipeline adalah API tingkat tinggi yang menyederhanakan proses menjalankan model ML. API ini menangani tugas seperti pemuatan model, tokenisasi, dan pascapemrosesan.

Kode demo kita melakukan lebih dari sekadar menyiapkan model, karena kita mengalihkan langkah-langkah persiapan model yang mahal secara komputasi ke pekerja web. Hal ini memungkinkan thread utama tetap responsif. Pelajari lebih lanjut cara mengalihkan tugas yang mahal ke pekerja web.

Pekerja kita perlu berkomunikasi dengan thread utama, menggunakan pesan untuk menunjukkan status model dan hasil penilaian toksisitas. Lihat kode pesan yang telah kita buat yang dipetakan ke berbagai status siklus proses inferensi dan persiapan model.

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

Mengklasifikasikan input pengguna

Dalam fungsi classify, kita menggunakan pengklasifikasi yang sebelumnya kita buat untuk menganalisis komentar pengguna. Kita menampilkan output mentah pengklasifikasi toksisitas: label dan skor.

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

Kita memanggil fungsi klasifikasi saat thread utama meminta pekerja untuk melakukannya. Dalam demo, kita memicu pengklasifikasi segera setelah pengguna berhenti mengetik (lihat TYPING_DELAY). Jika hal ini terjadi, thread utama kita akan mengirim pesan ke pekerja yang berisi input pengguna untuk diklasifikasikan.

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

Memproses output

Kita akan memeriksa apakah skor output pengklasifikasi melebihi nilai minimum. Jika ya, kita akan mencatat label yang dimaksud.

Jika ada label toksisitas yang tercantum, komentar akan ditandai sebagai berpotensi toksik.

// 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,
  });
};

Menampilkan petunjuk

Jika isToxic benar, kita akan menampilkan petunjuk kepada pengguna. Dalam demo, kami tidak menggunakan jenis toksisitas yang lebih terperinci, tetapi kami telah menyediakannya untuk thread utama jika diperlukan (toxicityTypeList). Anda mungkin menemukan jenis ini berguna untuk kasus penggunaan Anda.

Pengalaman pengguna

Dalam demo, kami telah membuat pilihan berikut:

  • Selalu izinkan postingan. Petunjuk toksisitas sisi klien kami tidak mencegah pengguna memposting. Dalam demo kami, pengguna dapat memposting komentar meskipun model belum dimuat (sehingga tidak menawarkan penilaian toksisitas), dan meskipun komentar terdeteksi sebagai negatif. Seperti yang direkomendasikan, Anda harus memiliki sistem kedua untuk mendeteksi komentar negatif. Jika sesuai untuk aplikasi Anda, pertimbangkan untuk memberi tahu pengguna bahwa komentar mereka telah diproses di klien, tetapi kemudian ditandai di server atau selama pemeriksaan manual.
  • Perhatikan negatif palsu. Jika komentar tidak diklasifikasikan sebagai negatif, demo kami tidak akan memberikan masukan (misalnya, "Komentar bagus!"). Selain berisi derau, memberikan masukan positif dapat mengirimkan sinyal yang salah, karena pengklasifikasi kami terkadang, tetapi pasti, melewatkan beberapa komentar negatif.
Demo memposting komentar.
Tombol Posting selalu diaktifkan: dalam demo kami, pengguna masih dapat memutuskan untuk memposting komentarnya, meskipun komentar tersebut diklasifikasikan sebagai beracun. Meskipun komentar tidak diklasifikasikan sebagai beracun, kami tidak akan menampilkan masukan positif.

Peningkatan dan alternatif

Batasan dan peningkatan mendatang

  • Bahasa: Model yang kami gunakan terutama mendukung bahasa Inggris. Untuk dukungan multibahasa, Anda perlu melakukan penyesuaian. Beberapa model toksisitas yang tercantum di Hugging Face mendukung bahasa non-Inggris (Rusia, Belanda), meskipun saat ini tidak kompatibel dengan Transformers.js.
  • Nuance: Meskipun toxic-bert secara efektif mendeteksi toksisitas yang jelas, model ini mungkin mengalami kesulitan dengan kasus yang lebih halus atau bergantung pada konteks (ironi, sarkasme). Toksisitas dapat bersifat sangat subjektif dan halus. Misalnya, Anda mungkin ingin istilah tertentu atau bahkan emoji diklasifikasikan sebagai beracun. Penyesuaian dapat membantu meningkatkan akurasi di area ini.

Kami akan menerbitkan artikel tentang cara menyesuaikan model toksisitas.

Alternatif

Kesimpulan

Deteksi konten beracun sisi klien adalah alat yang canggih untuk meningkatkan kualitas komunitas online.

Dengan memanfaatkan model AI seperti toxic-bert yang berjalan di browser dengan Transformers.js, Anda dapat menerapkan mekanisme masukan real-time yang mencegah perilaku beracun dan mengurangi beban klasifikasi toksisitas di server Anda.

Pendekatan sisi klien ini sudah berfungsi di seluruh browser. Namun, perhatikan batasannya, terutama dalam hal biaya penayangan model dan ukuran download. Terapkan praktik terbaik performa untuk AI sisi klien dan simpan model dalam cache.

Untuk deteksi toksisitas yang komprehensif, gabungkan pendekatan sisi klien dan sisi server.