Veröffentlicht am 13. November 2024
Hassrede, Belästigung und Online-Missbrauch sind zu einem weitverbreiteten Problem im Internet geworden. Schädliche Kommentare unterdrücken wichtige Stimmen und vertreiben Nutzer und Kunden. Die Erkennung von toxischen Inhalten schützt Ihre Nutzer und sorgt für eine sicherere Onlineumgebung.
In dieser zweiteiligen Reihe erfahren Sie, wie Sie KI einsetzen können, um toxische Inhalte direkt an der Quelle zu erkennen und zu minimieren – also auf den Tastaturen der Nutzer.
Im ersten Teil haben wir die Anwendungsfälle und Vorteile dieses Ansatzes erläutert.
Im zweiten Teil geht es um die Implementierung, einschließlich Codebeispielen und UX-Tipps.
Demo und Code
Demo ausprobieren und Code auf GitHub ansehen
Unterstützte Browser
Unsere Demo wird in den neuesten Versionen von Safari, Chrome, Edge und Firefox ausgeführt.
Modell und Bibliothek auswählen
Wir verwenden die Transformers.js-Bibliothek von Hugging Face, die Tools für die Arbeit mit Modellen für maschinelles Lernen im Browser bietet. Unser Democode basiert auf diesem Beispiel für die Textklassifizierung.
Wir wählen das Modell toxic-bert aus, ein vortrainiertes Modell, das darauf ausgelegt ist, toxische Sprachmuster zu erkennen. Es handelt sich um eine webkompatible Version von unitary/toxic-bert. Weitere Informationen zu den Labels des Modells und seiner Klassifizierung von Identitätsangriffen finden Sie auf der Hugging Face-Modellseite.
Sobald das Modell heruntergeladen wurde, ist die Inferenz schnell.
In Chrome auf einem von uns getesteten Android-Mittelklassegerät (einem regulären Pixel 7, nicht dem leistungsstärkeren Pro-Modell) dauert das in der Regel weniger als 500 Millisekunden. Führen Sie eigene Benchmarks aus, die für Ihre Nutzer repräsentativ sind.
Implementierung
Dies sind die wichtigsten Schritte bei der Implementierung:
Grenzwert für Toxizität festlegen
Unser Klassifikator für unangemessene Äußerungen liefert Werte zwischen 0 und 1. Innerhalb dieses Bereichs müssen wir einen Schwellenwert festlegen, um zu bestimmen, was einen toxischen Kommentar ausmacht. Ein häufig verwendeter Grenzwert ist 0.9. So können Sie eindeutig unangemessene Kommentare erkennen und gleichzeitig eine übermäßige Sensibilität vermeiden, die zu zu vielen Falsch-Positiv-Ergebnissen führen könnte (d. h. harmlose Kommentare, die als unangemessen eingestuft werden).
export const TOXICITY_THRESHOLD = 0.9
Komponenten importieren
Zuerst importieren wir die erforderlichen Komponenten aus der @xenova/transformers-Bibliothek. Außerdem importieren wir Konstanten und Konfigurationswerte, einschließlich unseres Grenzwerts für toxische Inhalte.
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';
Modell laden und mit dem Haupt-Thread kommunizieren
Wir laden das Modell zur Erkennung von Toxizität toxic-bert und verwenden es, um unseren Klassifikator vorzubereiten. Die einfachste Version davon ist
const classifier = await pipeline('text-classification', MODEL_NAME);
Das Erstellen einer Pipeline, wie im Beispielcode, ist der erste Schritt zum Ausführen von Inferenzaufgaben.
Die Pipeline-Funktion verwendet zwei Argumente: die Aufgabe ('text-classification') und das Modell (Xenova/toxic-bert).
Schlüsselbegriff: In Transformers.js ist eine Pipeline eine API auf hoher Ebene, die das Ausführen von ML-Modellen vereinfacht. Es übernimmt Aufgaben wie das Laden von Modellen, die Tokenisierung und die Nachbearbeitung.
Unser Democode bereitet das Modell nicht nur vor, sondern lagert die rechenintensiven Schritte der Modellvorbereitung an einen Web-Worker aus. So bleibt der Hauptthread reaktionsfähig. Weitere Informationen zum Auslagern rechenintensiver Aufgaben an einen Web-Worker
Der Worker muss mit dem Hauptthread kommunizieren und Nachrichten verwenden, um den Status des Modells und die Ergebnisse der Toxizitätsbewertung anzugeben. Sehen Sie sich die von uns erstellten Nachrichtencodes an, die verschiedenen Status des Modellvorbereitungs- und Inferenzlebenszyklus zugeordnet sind.
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 });
}
})();
Nutzeranfrage klassifizieren
In unserer classify-Funktion verwenden wir den zuvor erstellten Klassifikator, um einen Nutzerkommentar zu analysieren. Wir geben die Rohausgabe des Toxizitätsklassifikators zurück: Labels und Bewertungen.
// 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;
}
Die Klassifizierungsfunktion wird aufgerufen, wenn der Hauptthread den Worker dazu auffordert. In unserer Demo wird die Klassifizierung ausgelöst, sobald der Nutzer mit der Eingabe fertig ist (siehe TYPING_DELAY). In diesem Fall sendet der Hauptthread eine Nachricht an den Worker, die die zu klassifizierende Nutzereingabe enthält.
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,
});
};
Ausgabe verarbeiten
Wir prüfen, ob die Ausgabewerte des Klassifikators unseren Schwellenwert überschreiten. In diesem Fall notieren wir uns das entsprechende Label.
Wenn eines der Labels für unangemessene Äußerungen aufgeführt ist, wird der Kommentar als potenziell unangemessen gekennzeichnet.
// 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,
});
};
Hinweis anzeigen
Wenn isToxic „true“ ist, wird dem Nutzer ein Hinweis angezeigt. In unserer Demo verwenden wir den detaillierteren Typ für schädliche Inhalte nicht, aber wir haben ihn bei Bedarf für den Hauptthread verfügbar gemacht (toxicityTypeList). Er kann für Ihren Anwendungsfall nützlich sein.
Nutzererfahrung
In unserer Demo haben wir folgende Entscheidungen getroffen:
- Beiträge immer zulassen: Unser clientseitiger Hinweis auf toxische Inhalte verhindert nicht, dass der Nutzer Inhalte postet. In unserer Demo kann der Nutzer einen Kommentar posten, auch wenn das Modell nicht geladen wurde (und daher keine Bewertung der Unangemessenheit bietet) und auch wenn der Kommentar als unangemessen erkannt wird. Wie empfohlen, sollten Sie ein zweites System zur Erkennung unangemessener Kommentare haben. Wenn es für Ihre Anwendung sinnvoll ist, können Sie den Nutzer darüber informieren, dass sein Kommentar auf dem Client durchgegangen, dann aber auf dem Server oder bei der manuellen Überprüfung gekennzeichnet wurde.
- Falsch negative Ergebnisse berücksichtigen: Wenn ein Kommentar nicht als unangemessen eingestuft wird, gibt unsere Demo kein Feedback (z. B. „Guter Kommentar!“). Abgesehen davon, dass es störend ist, kann positives Feedback das falsche Signal senden, da unser Klassifikator gelegentlich, aber unvermeidlich einige unangemessene Kommentare übersieht.
Verbesserungen und Alternativen
Einschränkungen und künftige Optimierungen
- Sprachen: Das von uns verwendete Modell unterstützt hauptsächlich Englisch. Für die mehrsprachige Unterstützung ist ein Fine-Tuning erforderlich. Mehrere Toxizitätsmodelle, die auf Hugging Face aufgeführt sind, unterstützen nicht englische Sprachen (Russisch, Niederländisch), sind aber derzeit nicht mit Transformers.js kompatibel.
- Nuance: Toxic-bert erkennt zwar effektiv offenkundige Toxizität, kann aber bei subtileren oder kontextabhängigen Fällen (Ironie, Sarkasmus) Schwierigkeiten haben. Toxizität kann sehr subjektiv und subtil sein. Sie möchten beispielsweise, dass bestimmte Begriffe oder sogar Emojis als schädlich eingestuft werden. Durch das Fine-Tuning kann die Genauigkeit in diesen Bereichen verbessert werden.
Wir werden demnächst einen Artikel zur Feinabstimmung eines Modells für die Erkennung von toxischen Inhalten veröffentlichen.
Alternativen
- MediaPipe für die Textklassifizierung Verwenden Sie ein Modell, das mit Klassifizierungsaufgaben kompatibel ist.
TensorFlow.js-Klassifikator für unangemessene Äußerungen. Es bietet ein kleineres Modell, das schneller abgerufen werden kann. Es wurde jedoch seit einiger Zeit nicht mehr optimiert, sodass die Inferenz möglicherweise etwas langsamer ist als bei Transformers.js.
Fazit
Die clientseitige Erkennung von toxischen Inhalten ist ein leistungsstarkes Tool zur Verbesserung von Online-Communities.
Durch die Nutzung von KI-Modellen wie toxic-bert, die mit Transformers.js im Browser ausgeführt werden, können Sie Feedbackmechanismen in Echtzeit implementieren, die toxisches Verhalten verhindern und die Belastung Ihrer Server durch die Klassifizierung von Toxizität reduzieren.
Dieser clientseitige Ansatz funktioniert bereits browserübergreifend. Beachten Sie jedoch die Einschränkungen, insbesondere in Bezug auf die Kosten für die Bereitstellung von Modellen und die Downloadgröße. Best Practices für die Leistung von clientseitiger KI anwenden und Modell im Cache speichern.
Für eine umfassende Erkennung von toxischen Inhalten sollten Sie clientseitige und serverseitige Ansätze kombinieren.