Классификатор строкового шаблона с Tensorflow - PullRequest
1 голос
/ 16 января 2020

Я новичок в 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, дополненные буферы Юникода и нормализованная экспонента (softmax):

function encodeStr(str, pad = 512) {
    let arr = Array.from(
        new Int32Array(Buffer.from(str.padEnd(pad, '\0'), 'utf16le'))
    );
    const sum = arr.reduce((t, v) => t + Math.exp(v), 0);
    arr = arr.map(el => Math.exp(el) / sum);
    return arr;
}

Кодировка 3, местность, га sh, разбитый на шестнадцатеричный вектор длины 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 . Я пробовал разные конфиги, используя подходы выше, ie. «softmax» и «sigmoid» активации, более или менее плотные слои, но я просто не могу понять это.

  • Какой лучший способ кодировать строки, которые не являются просто текстом?
  • Каков правильный тип сети и конфигурация модели для этого типа классификации?

Любая помощь или какое-либо направление здесь будут оценены, как я могу не могу найти хороших примеров для обоснования моего решения.

1 Ответ

1 голос
/ 16 января 2020

О модели

Активация softmax возвращает вероятность (значение от 0 до 1) и в основном используется в качестве активации для последнего слоя для задачи классификации. Вместо этого можно использовать активацию relu. В дополнение к функции потерь, categoricalCrossEntropy лучше подходит, чем meanSquaredError.

LSTM и / или двунаправленный LSTM могут быть добавлены в модели для учета контекста данных. Если они используются, они будут первыми слоями моделей, чтобы не нарушать контекст данных перед их передачей в плотные слои.

О кодировке

Поскольку Nilsimsa - это метод алгоритми c, который с высокой вероятностью хэширует аналогичные элементы ввода в одни и те же «корзины», его также можно использовать для кластеризации и классификации текста, хотя я сам не использовал его.

Первая кодировка пытается сохранить расстояние между словами при создании токенов из предложения.

Кодирование данных в двоичном виде менее используется в NLP. Однако в этом случае, поскольку классификация должна была бы выяснить, сколько чисел существует между текстом, чтобы найти метку, двоичное кодирование может создать тензоры, где евклидово расстояние будет большим между входами разных меток.

Последним, но не менее важным для сравнения кодировки будет время, необходимое для создания тензоров из входной строки.

...