Ngày phát hành: 13 tháng 11 năm 2024
Lời nói hận thù, hành vi quấy rối và hành vi sai trái trên mạng đã trở thành vấn đề phổ biến trên mạng. Bình luận độc hại làm mất tiếng nói quan trọng và đuổi người dùng và khách hàng đi. Tính năng phát hiện nội dung độc hại giúp bảo vệ người dùng và tạo ra một môi trường trực tuyến an toàn hơn.
Trong loạt bài viết gồm hai phần này, chúng ta sẽ khám phá cách sử dụng AI để phát hiện và giảm thiểu nội dung độc hại ngay từ nguồn: bàn phím của người dùng.
Trong phần một, chúng ta đã thảo luận về các trường hợp sử dụng và lợi ích của phương pháp này.
Trong phần thứ hai này, chúng ta sẽ tìm hiểu cách triển khai, bao gồm cả ví dụ về mã và các mẹo về trải nghiệm người dùng.
Bản minh hoạ và mã
Hãy thử nghiệm bản minh hoạ của chúng tôi và tìm hiểu mã trên GitHub.
Hỗ trợ trình duyệt
Bản minh hoạ của chúng tôi chạy trong các phiên bản mới nhất của Safari, Chrome, Edge và Firefox.
Chọn một mô hình và thư viện
Chúng ta sử dụng thư viện Transformers.js của Hugging Face. Thư viện này cung cấp các công cụ để làm việc với các mô hình học máy trong trình duyệt. Mã minh hoạ của chúng tôi được lấy từ ví dụ về việc phân loại văn bản này.
Chúng tôi chọn mô hình toxic-bert, một mô hình được huấn luyện trước được thiết kế để xác định các mẫu ngôn ngữ độc hại. Đây là phiên bản tương thích với web của unitary/toxic-bert. Để biết thêm thông tin chi tiết về nhãn của mô hình và cách phân loại các cuộc tấn công nhận dạng, hãy tham khảo trang mô hình Huggin Face.
Sau khi tải mô hình xuống, quá trình suy luận sẽ diễn ra nhanh chóng.
Ví dụ: Chrome thường mất chưa đến 500 mili giây để chạy trên một thiết bị Android tầm trung mà chúng tôi đã thử nghiệm (điện thoại Pixel 7 thông thường, không phải là mẫu Pro có hiệu suất cao hơn). Chạy điểm chuẩn của riêng bạn đại diện cho cơ sở người dùng.
Triển khai
Sau đây là các bước chính trong quá trình triển khai:
Đặt ngưỡng độc hại
Trình phân loại nội dung độc hại của chúng tôi cung cấp điểm độc hại từ 0
đến 1
. Trong phạm vi đó, chúng ta cần đặt một ngưỡng để xác định những gì cấu thành một bình luận độc hại. Một ngưỡng thường dùng là 0.9
. Điều này giúp bạn phát hiện những bình luận độc hại một cách rõ ràng, đồng thời tránh tình trạng nhạy cảm quá mức có thể dẫn đến quá nhiều kết quả dương tính giả (tức là những bình luận vô hại bị phân loại là độc hại).
export const TOXICITY_THRESHOLD = 0.9
Nhập các thành phần
Chúng ta bắt đầu bằng cách nhập các thành phần cần thiết từ thư viện @xenova/transformers
. Chúng ta cũng nhập các hằng số và giá trị cấu hình, bao gồm cả ngưỡng độc hại.
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';
Tải mô hình và giao tiếp với luồng chính
Chúng ta tải mô hình phát hiện nội dung độc hại toxic-bert và sử dụng mô hình này để chuẩn bị cho trình phân loại. Phiên bản ít phức tạp nhất của lớp này là const classifier = await pipeline('text-classification', MODEL_NAME);
Tạo quy trình, như trong mã ví dụ, là bước đầu tiên để chạy các tác vụ suy luận.
Hàm quy trình nhận hai đối số: tác vụ ('text-classification'
) và mô hình (Xenova/toxic-bert
).
Thuật ngữ chính: Trong Transformers.js, quy trình là một API cấp cao giúp đơn giản hoá quy trình chạy mô hình học máy. Lớp này xử lý các tác vụ như tải mô hình, mã hoá và xử lý sau.
Mã minh hoạ của chúng ta không chỉ chuẩn bị mô hình mà còn thực hiện một số thao tác khác, vì chúng ta giảm tải các bước chuẩn bị mô hình tốn kém về mặt tính toán cho một worker web. Điều này cho phép luồng chính vẫn có thể phản hồi. Tìm hiểu thêm về cách giảm tải các tác vụ tốn kém cho một worker web.
Worker của chúng ta cần giao tiếp với luồng chính, sử dụng thông báo để cho biết trạng thái của mô hình và kết quả của việc đánh giá độc tính. Hãy xem mã thông báo mà chúng ta đã tạo để liên kết với các trạng thái khác nhau của vòng đời dự đoán và chuẩn bị mô hình.
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 });
}
})();
Phân loại dữ liệu đầu vào của người dùng
Trong hàm classify
, chúng ta sử dụng trình phân loại đã tạo trước đó để phân tích bình luận của người dùng. Chúng ta trả về kết quả thô của bộ phân loại nội dung độc hại: nhãn và điểm số.
// 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;
}
Chúng ta gọi hàm phân loại khi luồng chính yêu cầu worker thực hiện việc này. Trong bản minh hoạ, chúng ta kích hoạt trình phân loại ngay khi người dùng ngừng nhập (xem TYPING_DELAY
). Khi điều này xảy ra, luồng chính sẽ gửi một thông báo đến worker chứa dữ liệu đầu vào của người dùng để phân loại.
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,
});
};
Xử lý đầu ra
Chúng ta kiểm tra xem điểm đầu ra của bộ phân loại có vượt quá ngưỡng hay không. Nếu có, chúng tôi sẽ ghi lại nhãn có liên quan.
Nếu có bất kỳ nhãn độc hại nào được liệt kê, bình luận đó sẽ được gắn cờ là có khả năng độc hại.
// 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,
});
};
Hiển thị gợi ý
Nếu isToxic
là true, chúng ta sẽ hiển thị gợi ý cho người dùng. Trong bản minh hoạ, chúng tôi không sử dụng loại độc hại chi tiết hơn, nhưng chúng tôi đã cung cấp loại này cho luồng chính nếu cần (toxicityTypeList
). Bạn có thể thấy loại này hữu ích cho trường hợp sử dụng của mình.
Trải nghiệm người dùng
Trong bản minh hoạ, chúng tôi đã đưa ra các lựa chọn sau:
- Luôn cho phép đăng. Gợi ý về nội dung độc hại phía máy khách của chúng tôi không ngăn người dùng đăng nội dung. Trong bản minh hoạ của chúng tôi, người dùng có thể đăng bình luận ngay cả khi mô hình chưa tải (và do đó không đưa ra kết quả đánh giá mức độ độc hại) và ngay cả khi bình luận được phát hiện là độc hại. Như đề xuất, bạn nên có một hệ thống thứ hai để phát hiện bình luận độc hại. Nếu phù hợp với ứng dụng của bạn, hãy cân nhắc thông báo cho người dùng rằng bình luận của họ đã được xử lý trên máy khách, nhưng sau đó bị gắn cờ trên máy chủ hoặc trong quá trình kiểm tra thủ công.
- Chú ý đến kết quả âm tính giả. Khi một bình luận không được phân loại là độc hại, bản minh hoạ của chúng tôi sẽ không đưa ra ý kiến phản hồi (ví dụ: "Bình luận hay!"). Ngoài việc gây nhiễu, việc đưa ra ý kiến phản hồi tích cực có thể gửi sai tín hiệu, vì trình phân loại của chúng tôi thỉnh thoảng nhưng không thể tránh khỏi việc bỏ lỡ một số bình luận độc hại.
Các tính năng nâng cao và giải pháp thay thế
Hạn chế và điểm cải tiến trong tương lai
- Ngôn ngữ: Mô hình chúng tôi đang sử dụng chủ yếu hỗ trợ tiếng Anh. Để hỗ trợ nhiều ngôn ngữ, bạn cần điều chỉnh. Nhiều mô hình độc hại được liệt kê trên Hugging Face hỗ trợ các ngôn ngữ không phải tiếng Anh (tiếng Nga, tiếng Hà Lan), mặc dù hiện tại các mô hình này không tương thích với Transformers.js.
- Nuance: Mặc dù toxic-bert phát hiện hiệu quả nội dung độc hại công khai, nhưng có thể gặp khó khăn với các trường hợp tinh tế hơn hoặc phụ thuộc vào ngữ cảnh (mỉa mai, châm biếm). Tính độc hại có thể rất chủ quan và tinh vi. Ví dụ: bạn có thể muốn một số cụm từ hoặc thậm chí là biểu tượng cảm xúc được phân loại là độc hại. Việc tinh chỉnh có thể giúp cải thiện độ chính xác trong những khu vực này.
Chúng tôi sẽ sớm ra mắt một bài viết về cách tinh chỉnh mô hình độc hại.
Phương án thay thế
- MediaPipe để phân loại văn bản. Hãy nhớ sử dụng một mô hình tương thích với các nhiệm vụ phân loại.
TensorFlow.js trình phân loại nội dung độc hại. Thư viện này cung cấp một mô hình nhỏ hơn và nhanh hơn để tìm nạp, nhưng chưa được tối ưu hoá trong một số thời điểm, vì vậy, bạn có thể nhận thấy quá trình suy luận chậm hơn một chút so với Transformers.js.
Kết luận
Tính năng phát hiện nội dung độc hại phía máy khách là một công cụ hiệu quả để nâng cao chất lượng cộng đồng trực tuyến.
Bằng cách tận dụng các mô hình AI như toxic-bert chạy trong trình duyệt bằng Transformers.js, bạn có thể triển khai các cơ chế phản hồi theo thời gian thực để ngăn chặn hành vi độc hại và giảm tải việc phân loại nội dung độc hại trên máy chủ.
Phương pháp phía máy khách này đã hoạt động trên các trình duyệt. Tuy nhiên, hãy lưu ý các giới hạn, đặc biệt là về chi phí phân phát mô hình và kích thước tải xuống. Áp dụng các phương pháp hay nhất về hiệu suất cho AI phía máy khách và lưu mô hình vào bộ nhớ đệm.
Để phát hiện nội dung độc hại một cách toàn diện, hãy kết hợp các phương pháp phía máy khách và phía máy chủ.