Трюк с текстом дает разные результаты в 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.