Я обучаю LSTM некоторому спаму - у меня есть два класса: "спам" и "ветчина". Я предварительно обрабатываю данные, разбивая каждое сообщение на символы, а затем кодирую их одним нажатием. Затем я приписываю его соответствующему вектору - [0] для «ветчины» и [1] для «спама». Этот код предварительно обрабатывает данные:
const fs = require("fs");
const R = require("ramda");
const txt = fs.readFileSync("spam.txt").toString();
const encodeChars = string => {
const vecLength = 127;
const genVec = (char) => R.update(char.charCodeAt(0), 1, Array(vecLength).fill(0));
return string.split('').map(char => char.charCodeAt(0) < vecLength ? genVec(char) : "invalid");
}
const data = R.pipe(
R.split(",,,"),
R.map(
R.pipe(
x => [(x.split(",").slice(1).concat("")).reduce((t, v) => t.concat(v)), x.split(",")[0]],
R.adjust(1, R.replace(/\r|\n/g, "")),
R.adjust(0, encodeChars),
R.adjust(1, x => x === "ham" ? [0] : [1])
)
),
R.filter(R.pipe(
R.prop(0),
x => !R.contains("invalid", x)
))
)(txt);
fs.writeFileSync("data.json", JSON.stringify(data))
Затем, используя закодированные векторы из data.json
, я портирую данные в тензор потока:
const fs = require("fs");
const data = JSON.parse(fs.readFileSync("data.json").toString()).sort(() => Math.random() - 0.5)
const train = data.slice(0, Math.floor(data.length * 0.8));
const test = data.slice(Math.floor(data.length * 0.8));
const tf = require("@tensorflow/tfjs-node");
const model = tf.sequential({
layers: [
tf.layers.lstm({ inputShape: [null, 127], units: 16, activation: "relu", returnSequences: true }),
tf.layers.lstm({ units: 16, activation: "relu", returnSequences: true }),
tf.layers.lstm({ units: 16, activation: "relu", returnSequences: true }),
tf.layers.dense({ units: 1, activation: "softmax" }),
]
})
const tdata = tf.tensor3d(train.map(x => x[0]));
const tlabels = tf.tensor2d(train.map(x => x[1]));
model.compile({
optimizer: "adam",
loss: "categoricalCrossentropy",
metrics: ["accuracy"]
})
model.fit(tdata, tlabels, {
epochs: 1,
batchSize: 32,
callbacks: {
onBatchEnd(batch, logs) {
console.log(logs.acc)
}
}
})
tdata является трехмерным, и tlabels двумерный, поэтому все должно работать нормально. Однако, когда я запускаю код, я получаю следующую ошибку: Error when checking target: expected dense_Dense1 to have 3 dimension(s). but got array with shape 4032,1
Кто-нибудь знает, что здесь пошло не так - я не мог понять это. Thx!
Примечания. Я уже пытался нормализовать длину векторов, добавляя «ноль» в конце векторов сообщений, чтобы поместить их все в стандартизированную длину. Я все еще получил ту же ошибку.