Трюк с текстом дает разные результаты в Python и С#

Я пытаюсь переместить обученную модель в производственную среду и столкнулся с проблемой, пытающейся воспроизвести поведение функции Keras hashing_trick() в С#. Когда я иду на кодирование предложения, мой вывод отличается от С#, чем в python:

Текст: "Информация - обработка конфигурации завершена".

Python: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 217 142 262 113 319 413]

С#: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 433, 426, 425, 461, 336, 146, 52]

(скопировано из отладчика, обе последовательности имеют длину 30)

Что я пробовал:

  1. изменение кодировки текстовых байтов в С# для соответствия функции python string.encode() по умолчанию (UTF8)
  2. Изменение заглавной буквы в нижнем и верхнем регистре
  3. Пробовал использовать Convert.******** вместо BitConverter (что привело к ошибке переполнения)

Мой код (ниже) - это моя реализация функции Keras hashing_trick. Дается одно входное предложение, после чего функция возвращает соответствующую кодированную последовательность.

public ****[] HashingTrick(string data) { const int VOCAB_SIZE = 534; //Determined through python debugging of model var filters = "!#$%&()*+,-./:;<=>?@[\\]^_'{|}~\t\n".ToCharArray().ToList(); filters.ForEach(x => { data = data.Replace(x, '\0'); }); string[] parts = data.Split(' '); var encoded = new List<****>(); parts.ToList().ForEach(x => { using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) { byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(x); byte[] hashBytes = md5.ComputeHash(inputBytes); **** val = BitConverter.********(hashBytes, 0); encoded.Add(val % (VOCAB_SIZE - 1) + 1); } }); return PadSequence(encoded, 30); } private ****[] PadSequence(List<****> seq, int maxLen) { if (seq.Count < maxLen) { while (seq.Count < maxLen) { seq.Insert(0, 0); } return seq.ToArray(); } else if (seq.Count > maxLen) { return seq.GetRange(seq.Count - maxLen - 1, maxLen).ToArray(); } else { return seq.ToArray(); } }
</****></****>

Реализацию хэширования тэгов keras можно найти здесь

Если это помогает, я использую ASP.NET Web API в качестве своего типа решения.

2 ответа

Самая большая проблема с вашим кодом заключается в том, что он не учитывает тот факт, что Python int представляет собой произвольное целое число точности, тогда как С# **** имеет только 32 бита. Это означает, что Python вычисляет по модулю все 128 бит хэша, а С# - нет (и BitConverter.******** - это не то, что нужно делать в любом случае, так как неверность неверна). Другая проблема, которая вас заводит, заключается в том, что \0 не прерывает строки в С#, а \0 нельзя просто добавить к хэшу MD5 без изменения результата.

Переводится как можно проще:

int[] hashingTrick(string text, int n, string filters, bool lower, string split) { var splitWords = String.Join("", text.Where(c => !filters.Contains(c))) .Split(new[] { split }, StringSplitOptions.******************); return ( from word in splitWords let bytes = Encoding.UTF8.GetBytes(lower ? word.ToLower() : word) let hash = MD5.Create().ComputeHash(bytes) // add a 0 byte to force a non-negative result, per the BigInteger docs let w = new BigInteger(hash.Reverse().Concat(new byte[] { 0 }).ToArray()) select (int) (w % (n - 1) + 1) ).ToArray();
}

Пример использования:

const int vocabSize = 534;
Console.WriteLine(String.Join(" ", hashingTrick( text: "Information - The configuration processing is completed.", n: vocabSize, filters: "!#$%&()*+,-./:;<=>?@[\\]^_'{|}~\t\n", lower: true, split: " " ).Select(i => i.ToString())
));
217 142 262 113 319 413

Этот код имеет различную неэффективность: фильтрация символов с помощью LINQ очень неэффективна по сравнению с использованием StringBuilder и нам здесь не нужен BigInteger так как MD5 всегда ровно 128 бит, но оптимизация (при необходимости) остается как упражнение для читателя, как и добавление результата (для которого у вас уже есть функция).


Вместо того, чтобы решить проблему попыток борьбы с С#, чтобы получить правильное хеширование, я применил другой подход к проблеме. Когда я собираю данные для обучения модели (это все-таки проект машинного обучения), я решил использовать реализацию функции хеширования @Jeron Mostert для пре-хэш-набора данных перед его загрузкой в модель.

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

licensed under cc by-sa 3.0 with attribution.