Compare commits
19 Commits
9a36e5d7d2
...
457a1d397b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
457a1d397b | ||
|
|
96910eea02 | ||
|
|
f180169558 | ||
|
|
8456b95098 | ||
|
|
ac172c0357 | ||
|
|
d04ae45f10 | ||
|
|
9f012896d8 | ||
|
|
80a547df3b | ||
|
|
8af5a68a39 | ||
|
|
b71d1d4809 | ||
|
|
424e72f232 | ||
|
|
709bb61cf3 | ||
|
|
7d93ef9790 | ||
|
|
1bfac10d9a | ||
|
|
48d07c7d65 | ||
|
|
d21f1db4bf | ||
|
|
2ad1e0c48d | ||
|
|
b5d706683c | ||
|
|
344ee7a343 |
@@ -1,4 +1,4 @@
|
|||||||
# Немного о принятии решений и нейросетях
|
# Немного про принятие решений и нейросети
|
||||||
|
|
||||||
## Мотивация
|
## Мотивация
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# Общие заметки
|
# Общие заметки
|
||||||
|
|
||||||
## 2025-04-23 [Немного о принятии решений и нейросетях](ach.md)
|
## 2025-04-23 [Немного про принятие решений и нейросети](ach.md)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ box_name = "debian.jessie64.libvirt.box"
|
|||||||
|
|
||||||
Описание виртуальной машины, на которой будет основная компиляция:
|
Описание виртуальной машины, на которой будет основная компиляция:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
# Master
|
# Master
|
||||||
master_node = {
|
master_node = {
|
||||||
:hostname => "master", :ip => "10.200.1.2", :memory => 1024, :cpu => 1
|
:hostname => "master", :ip => "10.200.1.2", :memory => 1024, :cpu => 1
|
||||||
@@ -83,7 +83,7 @@ master_node = {
|
|||||||
|
|
||||||
Описание второстепенной виртуальной машины:
|
Описание второстепенной виртуальной машины:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
# List of slaves
|
# List of slaves
|
||||||
slaves = [
|
slaves = [
|
||||||
{ :memory => 4096, :cpu => 4 },
|
{ :memory => 4096, :cpu => 4 },
|
||||||
@@ -97,7 +97,7 @@ slaves = [
|
|||||||
|
|
||||||
Скрипт для автоматической установки зависимостей:
|
Скрипт для автоматической установки зависимостей:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
$distcc_install = <<-SCRIPT
|
$distcc_install = <<-SCRIPT
|
||||||
apt update
|
apt update
|
||||||
apt install -y make distcc gcc g++ tmux libz-dev git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison time neofetch
|
apt install -y make distcc gcc g++ tmux libz-dev git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison time neofetch
|
||||||
@@ -106,13 +106,13 @@ SCRIPT
|
|||||||
|
|
||||||
Старт конфигурации виртуальных машин:
|
Старт конфигурации виртуальных машин:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
```
|
```
|
||||||
|
|
||||||
Конфигурация основной машины:
|
Конфигурация основной машины:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
# Master node's config
|
# Master node's config
|
||||||
config.vm.box_check_update = false
|
config.vm.box_check_update = false
|
||||||
config.vm.define master_node[:hostname] do |nodeconfig|
|
config.vm.define master_node[:hostname] do |nodeconfig|
|
||||||
@@ -139,7 +139,7 @@ Vagrant.configure("2") do |config|
|
|||||||
|
|
||||||
Конфигурация второстепенных машин:
|
Конфигурация второстепенных машин:
|
||||||
|
|
||||||
```
|
```ruby
|
||||||
# Slaves configs
|
# Slaves configs
|
||||||
slaves.each_with_index do |slave, i|
|
slaves.each_with_index do |slave, i|
|
||||||
config.vm.box_check_update = false
|
config.vm.box_check_update = false
|
||||||
@@ -172,7 +172,7 @@ end
|
|||||||
|
|
||||||
Далее необходимо подключиться к главной машине и распаковать исходники ядра[^3]:
|
Далее необходимо подключиться к главной машине и распаковать исходники ядра[^3]:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
vagrant ssh master
|
vagrant ssh master
|
||||||
tar xvf linux-6.13.tar.gz
|
tar xvf linux-6.13.tar.gz
|
||||||
cd linux-6.13
|
cd linux-6.13
|
||||||
@@ -181,7 +181,7 @@ cd linux-6.13
|
|||||||
Создаем файл минимальной конфигурации
|
Создаем файл минимальной конфигурации
|
||||||
(с остальными вариантам можно ознакомиться командой `make help | less`):
|
(с остальными вариантам можно ознакомиться командой `make help | less`):
|
||||||
|
|
||||||
```
|
```shell
|
||||||
make tinyconfig
|
make tinyconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ make tinyconfig
|
|||||||
|
|
||||||
Запускаем компиляцию с замером времени:
|
Запускаем компиляцию с замером времени:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
time -p make CC=gcc
|
time -p make CC=gcc
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -199,13 +199,13 @@ time -p make CC=gcc
|
|||||||
По смыслу, все тоже самое, только нужно указать distcc, на каких хостах
|
По смыслу, все тоже самое, только нужно указать distcc, на каких хостах
|
||||||
можно компилировать:
|
можно компилировать:
|
||||||
|
|
||||||
```sh
|
```shell
|
||||||
export DISTCC_HOSTS="localhost"
|
export DISTCC_HOSTS="localhost"
|
||||||
```
|
```
|
||||||
|
|
||||||
Запускаем компиляцию с замером времени:
|
Запускаем компиляцию с замером времени:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
time -p make CC="distcc gcc"
|
time -p make CC="distcc gcc"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ time -p make CC="distcc gcc"
|
|||||||
Для запуска распределенной компиляции, нужно сначала запустить демон на
|
Для запуска распределенной компиляции, нужно сначала запустить демон на
|
||||||
второй виртуальной машине. Для этого подключаемся к ней и запускаем его:
|
второй виртуальной машине. Для этого подключаемся к ней и запускаем его:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
vagrant ssh slave-1
|
vagrant ssh slave-1
|
||||||
distccd --daemon --allow-private
|
distccd --daemon --allow-private
|
||||||
```
|
```
|
||||||
@@ -230,7 +230,7 @@ distccd --daemon --allow-private
|
|||||||
Теперь нужно добавить хост, чтобы на нем можно было удаленно компилировать.
|
Теперь нужно добавить хост, чтобы на нем можно было удаленно компилировать.
|
||||||
Для этого на основной машине:
|
Для этого на основной машине:
|
||||||
|
|
||||||
```
|
```shell
|
||||||
export DISTCC_HOSTS="localhost 10.200.1.3"
|
export DISTCC_HOSTS="localhost 10.200.1.3"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -238,13 +238,13 @@ export DISTCC_HOSTS="localhost 10.200.1.3"
|
|||||||
|
|
||||||
Запустим компиляцию на 5 потоках с замером времени:
|
Запустим компиляцию на 5 потоках с замером времени:
|
||||||
|
|
||||||
```sh
|
```shell
|
||||||
time -p make -j5 CC="distcc gcc"
|
time -p make -j5 CC="distcc gcc"
|
||||||
```
|
```
|
||||||
|
|
||||||
Мониторить компиляцию можно с помощью команды (на основной машине):
|
Мониторить компиляцию можно с помощью команды (на основной машине):
|
||||||
|
|
||||||
```
|
```shell
|
||||||
watch -n 1 distccmon-text
|
watch -n 1 distccmon-text
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
BIN
docs/maths/assets/type-pred/file_sig.png
Normal file
BIN
docs/maths/assets/type-pred/file_sig.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
BIN
docs/maths/assets/type-pred/heatmaps.png
Normal file
BIN
docs/maths/assets/type-pred/heatmaps.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 288 KiB |
BIN
docs/maths/assets/type-pred/stats.png
Normal file
BIN
docs/maths/assets/type-pred/stats.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
@@ -1,10 +1,9 @@
|
|||||||
# Математика
|
# Математика
|
||||||
|
|
||||||
# Статистика
|
|
||||||
|
|
||||||
## 2024-10-30 [Немного про производящие функции](gen_fun.md)
|
## 2024-10-30 [Немного про производящие функции](gen_fun.md)
|
||||||
|
|
||||||
## 2024-09-24 [Немного про Байесовскую статистику](baes.md)
|
## 2024-09-24 [Немного про Байесовскую статистику](baes.md)
|
||||||
|
|
||||||
## 2020-09-01 [Немного про проверку гипотез](stat-madness.md)
|
## 2020-09-01 [Немного про проверку гипотез](stat-madness.md)
|
||||||
|
|
||||||
|
## XXXX-XX-XX [Немного про работу с файлами, numpy и предсказаниях](type-pred.md)
|
||||||
|
|||||||
165
docs/maths/type-pred.md
Normal file
165
docs/maths/type-pred.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# Немного про работу с файлами, numpy и предсказаниях
|
||||||
|
|
||||||
|
## Введение / Мотивация
|
||||||
|
|
||||||
|
<!-- TODO: Попробовать нарисовать картинки? -->
|
||||||
|
|
||||||
|
Известно, что файлы в памяти представлены последовательностью байтов.
|
||||||
|
Структурно, эта последовательность может быть разной. Она может
|
||||||
|
содержать только ASCII-текст, текст с любой кодировкой, сжатый архив,
|
||||||
|
mp3, etc. При взаимодействии с файлом (например, открыть файл
|
||||||
|
текстовым редактором), операционная система не смотрит на
|
||||||
|
т.н. **расширение файла**, её интересует *побайтовое* содержание
|
||||||
|
файла.
|
||||||
|
|
||||||
|
В Unix для определения типа файла есть утилита `file`. Как она
|
||||||
|
определяет тип я точно не знаю, но могу сказать, что частично метод
|
||||||
|
основан на *"заголовке"* файла (первых байтах).
|
||||||
|
|
||||||
|
Пример работы `file` на исполняемом файле:
|
||||||
|
|
||||||
|
```
|
||||||
|
./program: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Шестнадцатеричное представление (первые несколько строк) с помощью
|
||||||
|
`xxd`:
|
||||||
|
|
||||||
|
```console
|
||||||
|
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`-мерными
|
||||||
|
тензорами улучшает качество предсказания.
|
||||||
|
|
||||||
|
Функция `read_file` считывает файл в структуру `raw_data`, которая
|
||||||
|
представляет собой просто последовательность байтов и размер этой
|
||||||
|
последовательности. После этого функция `build_matrix` считывает по
|
||||||
|
этой струтуре сигнатуру и записывает в `matrix`.
|
||||||
|
|
||||||
|
Далее создается объект `PyObject *result`, представляющий собой
|
||||||
|
указатель на массив `NumPy` типа `uint32`. На его основе создается
|
||||||
|
динамический массив `result_data`.
|
||||||
|
|
||||||
|
Так как `matrix` лежит в памяти последовательно (ввиду того, что
|
||||||
|
она аллоцирована на стеке), то её можно просто скопировать в
|
||||||
|
`result_data`. После всего этого возвращается указатель `*result`.
|
||||||
|
|
||||||
|
Помимо этого в коде много второстепенных действий, которые требует API
|
||||||
|
Python для работы. Эти подробности я опустил, их можно увидеть в коде,
|
||||||
|
все достаточно предсказуемо.
|
||||||
|
|
||||||
|
## Пайплайн обучения нейросети
|
||||||
|
|
||||||
|
**Нюанс обучения нейросети**: так как получившиеся матрицы вышли очень
|
||||||
|
неравномерными, дополнительно они были размыты [*методом
|
||||||
|
Гаусса*](https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D0%BC%D1%8B%D1%82%D0%B8%D0%B5_%D0%BF%D0%BE_%D0%93%D0%B0%D1%83%D1%81%D1%81%D1%83).
|
||||||
|
|
||||||
|
Для обучения нейросети необходимо создать матрицу меток. Так как
|
||||||
|
предполагается, что нейросеть будет предсказывать различные типы
|
||||||
|
файлов, то матрица меток будет иметь размер `M*NxM`, где:
|
||||||
|
|
||||||
|
- `M` -- количество типов файлов
|
||||||
|
- `N` -- количество файлов в одном типе (берется минимальное из всех,
|
||||||
|
чтобы обучение было равномерным)
|
||||||
|
|
||||||
|
Для разбиения на тренировочную и обучающию выборки отлично подходит
|
||||||
|
функция `train_test_split` из модуля `sklearn.model_selection`.
|
||||||
|
|
||||||
|
Сам перцептрон будет иметь следующую архитектуру:
|
||||||
|
|
||||||
|
1. На входном слое будет 65536 нейронов (`256х256`). Функцией активации
|
||||||
|
будет `ReLu`-функция.
|
||||||
|
2. Скрытый слой будет иметь 512 нейронов и `sigmoid`-функцию активации.
|
||||||
|
3. На выходе будет столько нейронов, сколько типов файлов нужно будет
|
||||||
|
предсказать.
|
||||||
|
|
||||||
|
Для для задания `loss`-функции и оптимизатора:
|
||||||
|
|
||||||
|
```python
|
||||||
|
loss_fn = nn.CrossEntropyLoss()
|
||||||
|
optimizer = t.optim.SGD(model.parameters(), lr=1e-3)
|
||||||
|
```
|
||||||
|
|
||||||
|
Цикл обучения в данном случае состоял из 250 эпох.
|
||||||
|
|
||||||
|
Пайплайн обучения можно будет найти в репозитории
|
||||||
|
[проекта](https://github.com/rustbas/filetype-prediction), вместе с
|
||||||
|
инструкцией по воспроизведению результатов (кроме того факта, что
|
||||||
|
файлы различных типов нужно будет скачать самому).
|
||||||
|
|
||||||
|
## Результаты и картинки
|
||||||
|
|
||||||
|
Усреденные сигнатуры различных типов файлов можно увидеть ниже.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Также, показатели обучения:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Выводы
|
||||||
|
|
||||||
|
По итогу, можно сказать, что в некоторых случаях, *сигнатура* файла
|
||||||
|
является неплохим предиктором его типа.
|
||||||
|
|
||||||
|
Гипотетически, это можно использовать для следующих идей:
|
||||||
|
|
||||||
|
1. Восстановление частично поврежденных файлов, так как можно попытаться
|
||||||
|
угадать его структуру и восстановить её.
|
||||||
|
2. Определение исполняемых файлов при анализе вредоносного ПО.
|
||||||
|
3. Обнаружение скрытых данных (когда сигнатура файла и его тип не
|
||||||
|
соответствуют друг другу).
|
||||||
|
|
||||||
|
## Источники
|
||||||
|
|
||||||
|
1. [Википедия про ELF-формат](https://ru.wikipedia.org/wiki/Executable_and_Linkable_Format)
|
||||||
|
2. [Репозиторий проекта](https://github.com/rustbas/filetype-prediction)
|
||||||
33
mkdocs.yml
33
mkdocs.yml
@@ -3,12 +3,33 @@ site_url: https://rustbas.github.io/blog
|
|||||||
repo_url: https://github.com/rustbas/blog
|
repo_url: https://github.com/rustbas/blog
|
||||||
edit_uri: edit/main/docs/
|
edit_uri: edit/main/docs/
|
||||||
theme:
|
theme:
|
||||||
name: terminal
|
name: material
|
||||||
palette: dark
|
palette:
|
||||||
|
- scheme: default
|
||||||
|
toggle:
|
||||||
|
icon: material/toggle-switch
|
||||||
|
name: Switch to dark mode
|
||||||
|
primary: green
|
||||||
|
|
||||||
|
- scheme: slate
|
||||||
|
toggle:
|
||||||
|
icon: material/toggle-switch-off-outline
|
||||||
|
name: Switch to light mode
|
||||||
|
primary: teal
|
||||||
|
|
||||||
features:
|
features:
|
||||||
- revision.date
|
- navigation.instant # TODO: check troubles with TeX loading
|
||||||
- revision.history
|
- navigation.instant.progress
|
||||||
- navigation.side.hide
|
- header.autohide
|
||||||
|
icon:
|
||||||
|
repo: fontawesome/brands/git
|
||||||
|
font:
|
||||||
|
# text: Roboto
|
||||||
|
code: JetBrains Mono
|
||||||
|
|
||||||
|
# - revision.date
|
||||||
|
# - revision.history
|
||||||
|
# - navigation.side.hide
|
||||||
nav:
|
nav:
|
||||||
# - "Обо мне": 'index.md'
|
# - "Обо мне": 'index.md'
|
||||||
- "Математика": 'maths/index.md'
|
- "Математика": 'maths/index.md'
|
||||||
@@ -20,7 +41,7 @@ plugins:
|
|||||||
lang: ["ru", "en"]
|
lang: ["ru", "en"]
|
||||||
indexing: 'full'
|
indexing: 'full'
|
||||||
- git-revision-date
|
- git-revision-date
|
||||||
|
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- pymdownx.arithmatex:
|
- pymdownx.arithmatex:
|
||||||
generic: true
|
generic: true
|
||||||
|
|||||||
Reference in New Issue
Block a user