2. Bölüm: İstemci tarafında yapay zeka ile toksisite algılama özelliği oluşturma

Maud Nalpas
Maud Nalpas

Yayınlanma tarihi: 13 Kasım 2024

Nefret söylemi, taciz ve internette kötüye kullanım, internette yaygın bir sorun haline geldi. Kötü niyetli yorumlar önemli sesleri susturur ve kullanıcıları ve müşterileri uzaklaştırır. Zararlı içerik algılama özelliği, kullanıcılarınızı korur ve daha güvenli bir online ortam oluşturur.

İki bölümden oluşan bu seride, yapay zekayı kullanarak toksik içerikleri kaynağında (kullanıcıların klavyelerinde) nasıl tespit edip azaltacağımızı ele alıyoruz.

Birinci bölümde, bu yaklaşımın kullanım alanlarını ve avantajlarını ele aldık.

Bu ikinci bölümde, kod örnekleri ve kullanıcı deneyimi ipuçları da dahil olmak üzere uygulama konusunu ayrıntılı olarak ele alıyoruz.

Demo ve kod

Demomuzu inceleyin ve GitHub'daki kodu inceleyin.

Yorum yayınlama demosunu izleyin.
Kullanıcı yazmayı bıraktığında yorumunun zararlı olup olmadığını analiz ederiz. Yorum zararlı olarak sınıflandırılırsa anında uyarı gösterilir.

Tarayıcı desteği

Demomuz Safari, Chrome, Edge ve Firefox'un en son sürümlerinde çalışır.

Model ve kitaplık seçme

Tarayıcıda makine öğrenimi modelleriyle çalışmak için araçlar sağlayan Hugging Face'in Transformers.js kitaplığını kullanıyoruz. Demo kodumuz bu metin sınıflandırma örneğinden türetilmiştir.

Zararlı dil kalıplarını belirlemek için tasarlanmış, önceden eğitilmiş bir model olan toxic-bert modelini seçiyoruz. unitary/toxic-bert'ün web ile uyumlu bir sürümüdür. Modelin etiketleri ve kimlik saldırılarını sınıflandırması hakkında daha fazla bilgi için Hugging Face model sayfasına bakın.

toxic-bert'ün indirme boyutu 111 MB.

Model indirildikten sonra çıkarım hızlı bir şekilde yapılır.

Örneğin, test ettiğimiz orta seviye bir Android cihazda (daha yüksek performanslı Pro modeli değil, normal bir Pixel 7 telefonu) Chrome'da genellikle 500 milisaniyeden kısa sürer. Kullanıcı tabanınızı temsil eden kendi karşılaştırmalarınızı yapın.

Uygulama

Uygulamamızdaki temel adımlar şunlardır:

Zararlılık eşiği belirleme

Zararlılık sınıflandırıcımız, 0 ile 1 arasında zararlılık puanları sağlar. Bu aralıkta, neyin zararlı yorum olarak kabul edileceğini belirlemek için bir eşik belirlememiz gerekir. Yaygın olarak kullanılan eşik 0.9'dır. Bu sayede, aşırı hassasiyetten kaçınarak (bu durum, çok fazla yanlış pozitif sonuca yani zararsız yorumların toksik olarak sınıflandırılmasına yol açabilir) açıkça toksik yorumları yakalayabilirsiniz.

export const TOXICITY_THRESHOLD = 0.9

Bileşenleri içe aktarma

@xenova/transformers kitaplığından gerekli bileşenleri içe aktararak başlıyoruz. Ayrıca, toksisite eşiğimiz de dahil olmak üzere sabitleri ve yapılandırma değerlerini de içe aktarırız.

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

Modeli yükleme ve ana iş parçacığıyla iletişim kurma

Kötü niyetli davranış algılama modeli toxic-bert'ü yükleyip sınıflandırıcıyı hazırlamak için kullanırız. Bunun en az karmaşık sürümü const classifier = await pipeline('text-classification', MODEL_NAME);

Örnek koddaki gibi bir işlem hattı oluşturmak, çıkarım görevlerini çalıştırmanın ilk adımıdır.

Pipeline işlevi iki bağımsız değişken alır: görev ('text-classification') ve model (Xenova/toxic-bert).

Önemli terim: Transformers.js'de ardışık düzen, makine öğrenimi modellerini çalıştırma sürecini basitleştiren üst düzey bir API'dir. Model yükleme, belirteçleştirme ve işleme sonrası gibi görevleri yönetir.

Hesaplama açısından maliyetli olan model hazırlama adımlarını bir web çalışanı üzerinden gerçekleştirdiğimiz için demo kodumuz, modeli hazırlamaktan biraz daha fazlasını yapar. Bu sayede ana ileti dizisi yanıt vermeye devam edebilir. Maliyetli görevleri web worker'a aktarma hakkında daha fazla bilgi edinin.

Çalışanımızın, modelin durumunu ve uygunsuzluk değerlendirmesinin sonuçlarını belirtmek için mesajları kullanarak ana iş parçacığıyla iletişim kurması gerekir. Model hazırlama ve çıkarım yaşam döngüsünün farklı durumlarıyla eşleşen mesaj kodlarımıza göz atın.

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

Kullanıcı girişini sınıflandırma

classify işlevimizde, kullanıcı yorumunu analiz etmek için daha önce oluşturduğumuz sınıflandırıcıyı kullanıyoruz. Kötüye kullanım sınıflandırıcısının ham çıkışını (etiketler ve puanlar) döndürürüz.

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

Ana ileti dizisi, çalışandan bunu yapmasını istediğinde sınıflandırma işlevimizi çağırırız. Demomuzda, kullanıcı yazmayı bıraktığı anda sınıflandırıcıyı tetikleriz (TYPING_DELAY bölümüne bakın). Bu durumda, ana ileti dizimiz çalışana sınıflandırılacak kullanıcı girişini içeren bir mesaj gönderir.

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

Çıkışı işleme

Sınıflandırıcının çıkış puanlarının eşiğimizi aşıp aşmadığını kontrol ederiz. Bu durumda söz konusu etiketi not ederiz.

Kötüye kullanım etiketlerinden herhangi biri listeleniyorsa yorum, kötüye kullanım amaçlı olma ihtimali olan yorum olarak işaretlenir.

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

İpucu görüntüleme

isToxic doğruysa kullanıcıya bir ipucu gösteririz. Demomuzda daha ayrıntılı toksisite türünü kullanmıyoruz ancak gerekirse ana iş parçacığında kullanılabilir hale getirdik (toxicityTypeList). Bu tür, kullanım alanınız için faydalı olabilir.

Kullanıcı deneyimi

Demomuzda aşağıdaki seçimleri yaptık:

  • Her zaman yayınlamaya izin ver İstemci tarafındaki zararlılık ipucumuz, kullanıcının yayınlamasını engellemez. Demomuzda kullanıcı, model yüklenmemiş olsa (bu nedenle toksisite değerlendirmesi sunmuyor olsa) ve yorum toksik olarak algılansa bile yorum gönderebiliyor. Önerildiği gibi, zararlı yorumları tespit etmek için ikinci bir sisteminiz olmalıdır. Uygulamanız için uygunsa kullanıcıyı, yorumunun istemcide gönderildiğini ancak sunucuda veya insan incelemesi sırasında işaretlendiği konusunda bilgilendirebilirsiniz.
  • Yanlış negatiflere dikkat edin. Bir yorum zararlı olarak sınıflandırılmadığında demomuz geri bildirim sağlamaz (ör. "Güzel yorum!"). Olumlu geri bildirimler, gürültülü olmanın yanı sıra yanlış sinyal de gönderebilir. Çünkü sınıflandırıcımız, zaman zaman ancak kaçınılmaz olarak bazı zararlı yorumları gözden kaçırır.
Yorum yayınlama demosunu izleyin.
Yayınla düğmesi her zaman etkin: Demomuzda kullanıcı, yorumu zararlı olarak sınıflandırılsa bile yayınlamaya karar verebiliyor. Yorum zararlı olarak sınıflandırılmasa bile olumlu geri bildirim göstermiyoruz.

Geliştirmeler ve alternatifler

Sınırlamalar ve gelecekte yapılacak geliştirmeler

  • Diller: Kullandığımız model öncelikle İngilizceyi destekler. Çok dilli destek için ince ayar yapmanız gerekir. Hugging Face'te listelenen birden fazla zararlılık modeli, şu anda Transformers.js ile uyumlu olmasa da İngilizce dışındaki dilleri (Rusça, Felemenkçe) desteklemektedir.
  • İnce anlamlar: Toxic-bert, açıkça görülen toksik içerikleri etkili bir şekilde tespit etse de daha ince veya bağlama bağlı durumlarda (ör. ironi, alay) zorlanabilir. Zararlı içerik, son derece öznel ve ince bir konu olabilir. Örneğin, belirli terimlerin veya emojilerin zararlı olarak sınıflandırılmasını isteyebilirsiniz. İnce ayar, bu alanlardaki doğruluğu artırmaya yardımcı olabilir.

Yakında, toksisite modeline ince ayar yapma hakkında bir makale yayınlayacağız.

Alternatifler

Sonuç

İstemci tarafında zararlı içerik algılama, online toplulukları geliştirmek için kullanabileceğiniz güçlü bir araçtır.

Transformers.js ile tarayıcıda çalışan toxic-bert gibi yapay zeka modellerinden yararlanarak, zararlı davranışları engelleyen ve sunucularınızdaki zararlılık sınıflandırma yükünü azaltan anlık geri bildirim mekanizmaları uygulayabilirsiniz.

Bu istemci taraflı yaklaşım, tarayıcılar arasında zaten çalışmaktadır. Ancak özellikle model sunma maliyetleri ve indirme boyutu açısından sınırlamaları göz önünde bulundurun. İstemci tarafı yapay zeka için performansla ilgili en iyi uygulamaları uygulayın ve modeli önbelleğe alın.

Kapsamlı toksisite algılama için istemci tarafı ve sunucu tarafı yaklaşımlarını birleştirin.