Filter4J:一行代码,本地接入基于深度学习与神经网络的文本内容安全

230 阅读4分钟

0x00 TL;DR

Filter4J是一个基于深度学习与神经网络的文本内容安全库,可以被用于自动检查文本内容的合规安全性。它对于具备对拼音、谐音、拆字等违规变体具备识别能力。它由纯Java编写,不依赖任何第三方库,推论模块体积仅10kb(不含模型)且兼容Java8。本文介绍了它的使用方法、原理与微调方法。求Star

System.out.println(TextFilter.isIllegal(str) ?"异常":"正常");

0x01 编写背景

我们都知道,文本内容安全是互联网平台的重要痛点。对于用户生成的内容,进行恰当的检查是非常有必要的,以免文本中出现可能令人反感、不安全或不适宜的内容。传统上,我们可能会采用关键词法或调用第三方API。然而,这两者都存在很严重的问题:采用关键词法时,一方面,恶意用户可能通过增加干扰等方式绕过检查,有时哪怕检查没有被绕过,被替换成了*等字符的关键词仍然会使人不适。另一方面正如一个广为流传的笑话中提到的,j**ajava),关键词法可能会影响到用户体验。采用第三方API法时,一方面,用户内容作为企业核心资产,交给第三方平台事实上是一种资产外泄,带来不必要的风险。另一方面,第三方的API的稳定性、可用性、定价,甚至是否关停,都不可控,带来额外的成本。
与此同时,在某些细分领域中,用户可能有一些细分领域术语。对于通用的API而言,对这些术语的处理情况可能不甚好,或因为需要处理许多其他细分领域的术语而带来不必要的性能开支。自行微调可以解决以上问题。

0x02 代码架构

sequenceDiagram
    participant 原始文本
    participant Token
    participant 模型
    loop 训练阶段
        原始文本 ->> Token: 词频
        Token ->> 原始文本: 构造分词器
        原始文本 ->> Token: 分词
        Token ->> 模型: 训练
    end
    loop 预测阶段
        原始文本 ->> Token: 分词
        Token ->> 模型: 预测
        模型 ->> 原始文本: 分数
    end

本文聚焦于预测阶段进行详细的介绍。

0x03 分词

分词指的是将自然语句生成高维词向量。此处我们使用词频直接构造分词器。
传统的分词器体量较大,并且其实,因为内容检查是一个时序无关的应用。我们知道,文字的序顺往不往影响类人的读阅,而反而可能成为潜在的绕过点。因此,我们可以通过词频直接进行01分词,而不是调用传统的分词库。
具体代码摘选如下:

    public DataEntry tokenize(int type, String text) {
        double[] values = new double[vocab.length];
        for (int i = 0; i < values.length; i++) {
            if (text.contains(vocab[i])) {
                values[i] = 1;
            }
        }
        return new DataEntry(type, values);
    }

0x04 模型预测

使用预训练的人工智能模型对词向量进行预测。
MinRT是一个极小的神经网络运行时,核心方法实在是不舍得删除哪怕是一行代码。
核心方法代码如下:

    public static int doAi(double[] input, String[] script) {
        double[] current = new double[input.length];
        System.arraycopy(input, 0, current, 0, input.length);
        for (String str : script) {
            if (str.length() < 2) {
                continue;
            }
            String[] tokens = str.split(" ");
            switch (tokens[0]) {
                case "D":
                    int ic = Integer.parseInt(tokens[1]);
                    int oc = Integer.parseInt(tokens[2]);
                    if (current.length != ic) {
                        throw new RuntimeException("Wrong input size for Dense layer (expected " + ic + ", got " + current.length + ")");
                    }
                    double[] tmp = new double[oc];
                    for (int i = 0; i < oc; i++) {
                        double sum = 0;
                        for (int j = 0; j < ic; j++) {
                            sum += current[j] * Double.parseDouble(tokens[3 + i + j * oc]);
                        }
                        tmp[i] = sum;
                    }
                    current = tmp;
                    break;
                case "L":
                    int n = Integer.parseInt(tokens[1]);
                    if (current.length != n) {
                        throw new RuntimeException("Wrong input size for LeakyRelu layer (expected " + n + ", got " + current.length + ")");
                    }
                    for (int i = 0; i < n; i++) {
                        current[i] = current[i] > 0 ? current[i] : current[i] * 0.01;
                    }
                    break;
                case "J":
                    int m = Integer.parseInt(tokens[1]);
                    if (current.length != m) {
                        throw new RuntimeException("Wrong input size for Judge layer (expected " + m + ", got " + current.length + ")");
                    }
                    int idx = 0;
                    for (int i = 1; i < m; i++) {
                        if (current[i] > current[idx]) {
                            idx = i;
                        }
                    }
                    return idx;
                default:
                    throw new RuntimeException("Unknown layer type");
            }
        }
        throw new RuntimeException("No output layer");
    }

0x05 效果展示

声明:图中语句仅供技术演示,不代表本人观点。
图中语句构造规则为:
违规语句1 包含相同词语的正常语句1-1 包含相同词语的正常语句1-2 混淆了词语的变体违规1
违规语句2 两个能够包含违规语句2中全部词语的正常语句2-1 2-2
image.png 可以看到,本模型能够正常地处理违规与变体违规,且不会误伤正常语句。

0x06 致谢与声明

特别鸣谢

北京信息科学与技术国家研究中心 Jiawen Deng(清华大学) et,al. 提供的COLDataset。
此数据集为我们提供了无与伦比的帮助。

质量声明

基于机器的文本审核系统,无法完全替代人工审核。请在使用本库时,仍然保持对用户输入的警惕。
作者在此明示,本模型一定存在缺陷且会存在错误判断,其输出结果与实际情况一定存在偏差。
使用者不应该将其用于任何环境中,除非这种偏差不会对使用者造成任何损失。

0x07 相关链接

Filter4J 仅推理仓库。适合于只需要调用Filter4J的人。
Filter4Jx 推理与训练仓库。适合于需要训练或高速运行Filter4J的人。
COLDataset 最重要的训练集。