Files
blog/docs/maths/type-pred.md
Basyrov Rustam b71d1d4809 new stage
2025-05-11 20:11:03 +03:00

6.4 KiB
Raw Blame History

Немного про работу с файлами, numpy и предсказаниях

Введение / Мотивация

Известно, что файлы в памяти представлены последовательностью байтов. Структурно, эта последовательность может быть разной. Она может содержать только ASCII-текст, текст с любой кодировкой, сжатый архив, mp3, etc. При взаимодействии с файлом (например, открыть файл текстовым редактором), операционная система не смотрит на т.н. расширение файла, её интересует побайтовое содержание файла.

В Unix для определения типа файла есть утилита file. Как она определяет тип я точно не знаю, но могу сказать, что частично метод основан на "заголовке" файла (первых байтах).

Пример работы file на исполняемом файле:

./program: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, ...

Шестнадцатеричное представление (первые несколько строк) с помощью xxd:

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0300 3e00 0100 0000 6010 0000 0000 0000  ..>.....`.......
00000020: 4000 0000 0000 0000 c036 0000 0000 0000  @........6......
00000030: 0000 0000 4000 3800 0d00 4000 1f00 1e00  ....@.8...@.....

В начале видно последовательность ELF -- формат исполняемых файлов в Unix[1].

Возникает вопрос: есть какой-то паттерн для различных типов файлов, который можно увидеть, не считая специальных симвовол в заголовке?

Можно усложнить вопрос: можно ли по какому-то обобщению (сигнатуре) файла предсказать его тип? Попробуем это выяснить.

Для этого нужно решить следующие задачи:

  1. Написать модуль (на Си), который по имени файла просчитывает сигнатуру и возвращает её;
  2. Посмотреть, как выглядят эти сигнатуры;
  3. Попробовать обучить простую нейросеть.

Как считать сигнатуру файла

Возьмем нулевую матрицу M размера 256х256, так как один байт это число от 0 до 255. Считаем файл в память в виде последовательности байтов. Теперь будем двигаться по последовательности с окном размера 2. В этом окне первый элемент будет отвечать за номер строки, а второй за номер столбца. И каждый раз с окном (x, y) будем увеличивать элемент матрицы M[x][y] на единицу.

Причины использования Си

Если кратко: python очень медленный. Например, средний wav-файл занимает около 10 мегабайт. Это порядка десяти миллионов байт, по которым нужно пробежать и заполнить матрицу. А для обучения нейросети, таких файлов должно быть много.

Отдельный интерес, также, представляет возможность написать модуль для python на C, который умеет взаимодействовать с API библиотеки NumPy.

Чтение файлов в память

Для чтения файла в память, я написал модуль на Си, доступный репозитории[2]. Здесь кратко опишу, как он работает.

В нем реализована функция signature_from_filepath_by2, которая получает на вход два параметра: имя файла и уровень verbose. by_2 в названии обусловлено тем, что работа не с матрицами, а n-мерными eтензорами улучшает качество предсказания.

Функция read_file считывает файл в структуру raw_data, которая представляет собой просто последовательность байтов и размер этой последовательности. После этого функция build_matrix считывает по этой струтуре сигнатуру и записывает в matrix.

Далее создается объект PyObject *result, представляющий собой указатель на массив NumPy типа uint32. На его основе создается динамический массив result_data.

Так как matrix лежит в памяти последовательно (ввиду того, что она аллоцирована на стеке), то её можно просто скопировать в result_data. После всего этого возвращается указатель *result.

Помимо этого в коде много второстепенных действий, которые требует API Python для работы. Эти подробности я опустил, их можно увидеть в коде, все достаточно предсказуемо.

Пайплайн обучения нейросети

Результаты и картинки

Источники

  1. https://ru.wikipedia.org/wiki/Executable_and_Linkable_Format
  2. https://github.com/rustbas/filetype-prediction