我是Tensorflow和机器学习的新手。
我的任务是预测给定字符串输入的类型。下面是训练数据的示例(输出已进行独热编码(:
const training = [
{ x: '622-49-7314', y: [1,0,0,0] }, // "ssn"
{ x: '1234 Elm Street', y: [0,1,0,0] }, // "street-address"
{ x: '(419) 555-5555', y: [0,0,1,0] }, // "phone-number"
{ x: 'Jane Doe', y: [0,0,0,1] }, // "full-name"
{ x: 'José García', y: [0,0,0,1] }, // "full-name"
// ... and millions more examples...
]
我的第一个问题是如何对输入进行编码,因为它不是一个典型的文本字典问题(单词序列(,而是一个可变大小的字母序列。
我已经为输入字符串尝试了 3 种编码方法:
编码1、标准文本嵌入:
async function encodeData(data) {
const sentences = data.map(str => str.toLowerCase());
const model = await use.load();
const embeddings = await model.embed(sentences);
return embeddings;
}
编码 2、填充的 unicode 缓冲区和规范化指数 (softmax(:
function encodeStr(str, pad = 512) {
let arr = Array.from(
new Int32Array(Buffer.from(str.padEnd(pad, ' '), 'utf16le'))
);
const sum = arr.reduce((t, v) => t + Math.exp(v), 0);
arr = arr.map(el => Math.exp(el) / sum);
return arr;
}
编码 3,一个局部哈希,分解为长度为 64 和规范化指数 (softmax( 的十六进制向量:
const { Nilsimsa } = require('nilsimsa');
function encodeHash(str) {
const hash = new Nilsimsa(str).digest('hex'),
vals = hash.split(/(?<=^(?:.{2})+)(?!$)/).map(el => parseInt(el, 16));
const sum = vals.reduce((t, v) => t + Math.exp(v), 0),
normArr = vals.map(el => Math.exp(el) / sum);
return normArr;
}
然后我使用了一个简单的模型:
const inputSz = 512; // or 128 for encodeStr, or 32 for encodeHash
const outputSz = 4; // [0,0,0,0] - the size of the one-hot encoding (potentially could be >1000)
model.add(
tf.layers.dense({
inputShape: [inputSz],
activation: 'softmax',
units: outputSz
})
);
model.add(
tf.layers.dense({
inputShape: [outputSz],
activation: 'softmax',
units: outputSz
})
);
model.add(
tf.layers.dense({
inputShape: [outputSz],
activation: 'softmax',
units: outputSz
})
);
model.compile({
loss: 'meanSquaredError',
optimizer: tf.train.adam(0.06)
});
这是这样训练的:
const trainingTensor = tf.tensor2d( data.map(_ => encodeInput(_.input)));
const [encodedOut, outputIndex, outSz] = encodeOutput(data.map(_ => _.output));
const outputData = tf.tensor2d(encodedOut);
const history = await model.fit(trainingTensor, outputData, { epochs: 50 });
但结果都非常差,平均损失 = 0.165。我使用上述方法尝试了不同的配置,即。"softmax"和"sigmoid"激活,或多或少的密集层,但我就是想不通。
- 对不仅仅是文本的字符串进行编码的最佳方法是什么?
- 此类分类的正确网络类型和模型配置是什么?
这里的任何帮助或一些指导将不胜感激,因为我找不到好的例子来作为我的解决方案的基础。
关于模型
softmax
激活返回一个概率(值介于 0 和 1 之间(,主要用作分类问题最后一层的激活。可以改用relu
激活。此外,对于损失函数,categoricalCrossEntropy
比meanSquaredError
更适合。
LSTM 和/或双向 LSTM 可以添加到模型中,以考虑数据的上下文。如果使用它们,它们将是模型的第一层,以免在传递到密集层之前破坏数据的上下文。
关于编码
由于Nilsimsa
是一种算法技术,可以将相似的输入项以很高的概率散列到相同的"桶"中,因此它也可以用于聚类和文本分类,尽管我自己没有使用它。
第一个编码在从句子创建标记时尝试保持单词之间的距离。
将数据编码为二进制在 NLP 中较少使用。但是,在这种情况下,由于分类需要确定文本之间有多少个数字才能找出标签,因此二进制编码可以创建张量,其中不同标签的输入之间的欧几里得距离将很高。
最后但并非最不重要的是比较编码是从输入字符串创建张量所花费的时间。