Перейти к содержанию

🧠 Слой 2: Modality Encoders (Сенсорная кора)

Подробное описание архитектуры и работы

Статус: 🟡 Частично реализовано (Этап E — Text Encoder) · 80/80 тестов ✅ text_encoder.py — TextEncoder (sentence-transformers 768d / navec 300d fallback, 4 режима) ✅ EncodedPercept dataclass — реализован в brain/core/contracts.pyVisionEncoder — Этап J (мультимодальное расширение) ⬜ AudioEncoder — Этап J (мультимодальное расширение) ⬜ TemporalEncoder — Этап J (мультимодальное расширение) ⬜ EmbeddingCache — Post-MVP


Что такое Сенсорная кора в биологии

В человеческом мозге Сенсорная кора — это набор специализированных зон: - Зрительная кора (затылочная доля) — обрабатывает визуальные сигналы - Слуховая кора (височная доля) — обрабатывает звуки и речь - Соматосенсорная кора — обрабатывает осязание, температуру, боль - Речевая зона Вернике — понимание языка

Каждая зона специализирована под свою модальность и преобразует сырые сигналы в нейронные представления (паттерны активации), которые можно сравнивать, ассоциировать и хранить.

Аналогично работают наши Modality Encoders — каждый преобразует сырой PerceptEvent в вектор фиксированной размерности (эмбеддинг).


Роль в искусственном мозге

PerceptEvent(s) от Таламуса
┌─────────────────────────────────────────────────────────┐
│                  MODALITY ENCODERS                      │
│                                                         │
│  ┌──────────────────┐                                   │
│  │   TextEncoder    │  PerceptEvent(modality="text")    │
│  │                  │  → вектор 768d                    │
│  │ sentence-        │  → ключевые слова                 │
│  │ transformers     │  → тип сообщения                  │
│  │ (paraphrase-     │  → язык                           │
│  │  multilingual)   │  → тональность                    │
│  └──────────────────┘                                   │
│                                                         │
│  ┌──────────────────┐                                   │
│  │  VisionEncoder   │  PerceptEvent(modality="image")   │
│  │                  │  → вектор 512d                    │
│  │  CLIP ViT-B/32   │  → объекты и сцены                │
│  │  (CPU-only)      │  → текстовое описание             │
│  │                  │  → spatial features               │
│  └──────────────────┘                                   │
│                                                         │
│  ┌──────────────────┐                                   │
│  │  AudioEncoder    │  PerceptEvent(modality="audio")   │
│  │                  │  → вектор 768d (из транскрипта)   │
│  │  Whisper →       │  → акустические признаки          │
│  │  TextEncoder     │  → эмоциональный тон              │
│  │                  │  → временные сегменты             │
│  └──────────────────┘                                   │
│                                                         │
│  ┌──────────────────┐                                   │
│  │ TemporalEncoder  │  PerceptEvent(modality="video")   │
│  │                  │  → последовательность векторов    │
│  │  кадры + аудио   │  → временные зависимости          │
│  │  → усреднение    │  → ключевые моменты               │
│  └──────────────────┘                                   │
│                                                         │
└──────────────────────┬──────────────────────────────────┘
              EncodedPercept(s)
    {vector, modality, metadata, keywords, ...}
            Cross-Modal Fusion (Слой 3)

Что такое эмбеддинг (вектор)

Эмбеддинг — это числовое представление смысла в многомерном пространстве.

"нейрон"  → [0.12, -0.34, 0.87, 0.05, ..., 0.23]  (768 чисел)
"клетка"  → [0.11, -0.31, 0.84, 0.07, ..., 0.21]  (768 чисел)
"автомобиль" → [-0.45, 0.67, -0.12, 0.89, ..., -0.34]

cosine_similarity("нейрон", "клетка")     = 0.94  ← близко по смыслу
cosine_similarity("нейрон", "автомобиль") = 0.12  ← далеко по смыслу

Ключевое свойство: похожие по смыслу объекты → близкие векторы.
Это позволяет сравнивать текст с изображением, аудио с текстом и т.д.


Компоненты Modality Encoders

1. TextEncoder — кодирование текста

Модель: sentence-transformers/paraphrase-multilingual-mpnet-base-v2

Параметр Значение
Размер вектора 768d
Поддержка языков 50+ (включая RU и EN)
Размер модели ~1.1 GB
Скорость (CPU) ~50–100 мс на предложение
Контекстное окно 512 токенов

Что делает: 1. Принимает текстовый чанк из PerceptEvent 2. Токенизирует (WordPiece/BPE) 3. Прогоняет через трансформер (12 слоёв, 768 hidden) 4. Mean pooling → вектор 768d 5. Нормализация (L2) → единичная длина 6. Дополнительно извлекает: - ключевые слова (TF-IDF или YAKE) - тип сообщения (вопрос / утверждение / команда) - тональность (позитив / нейтраль / негатив) - язык (ru / en / mixed)

Пример:

text = "Нейрон — это основная клетка нервной системы"

encoded = TextEncoder.encode(text)
# encoded.vector:   [0.12, -0.34, 0.87, ...]  (768d)
# encoded.keywords: ["нейрон", "клетка", "нервная система"]
# encoded.msg_type: "statement"
# encoded.language: "ru"
# encoded.sentiment: 0.0  (нейтральный)

Fallback (если модель не загружена): - TF-IDF вектор (bag-of-words, ~10 000d sparse) - Работает без GPU и без интернета


2. VisionEncoder — кодирование изображений

Модель: openai/clip-vit-b-32 (CPU-only)

Параметр Значение
Размер вектора 512d
Входное разрешение 224×224 px
Размер модели ~0.6 GB
Скорость (CPU) ~200–500 мс на изображение
Особенность общее пространство с текстом

Что делает: 1. Принимает PIL.Image из PerceptEvent 2. Ресайзит до 224×224 3. Нормализует пиксели 4. Прогоняет через ViT-B/32 (Vision Transformer) 5. Проецирует в 512d пространство 6. Нормализация (L2) 7. Дополнительно: - OCR-текст → TextEncoder → 768d (отдельно) - Генерация caption (описания) через BLIP или простые правила - Детекция объектов (опционально, через YOLO nano)

Ключевое свойство CLIP:

TextEncoder("нейрон под микроскопом")  → вектор 512d
VisionEncoder(фото_нейрона.jpg)        → вектор 512d

cosine_similarity(текст_вектор, фото_вектор) = 0.89  ← CLIP умеет это!

CLIP обучен на парах (текст, изображение), поэтому его пространство уже выровнено между модальностями.

Пример:

image = PIL.Image.open("схема_нейрона.png")

encoded = VisionEncoder.encode(image)
# encoded.vector:      [0.45, -0.12, 0.78, ...]  (512d)
# encoded.ocr_text:    "Нейрон, Аксон, Дендрит"
# encoded.description: "Схематическое изображение нейрона"
# encoded.objects:     ["нейрон", "аксон", "дендрит"]

Fallback: - Только OCR → TextEncoder (без визуального понимания) - Работает если CLIP не загружен


3. AudioEncoder — кодирование аудио

Двухэтапный процесс:

Аудиофайл
[Этап 1] Whisper medium → транскрипт + временные метки
[Этап 2] TextEncoder → вектор 768d
EncodedPercept(vector=768d, transcript=..., time_segments=[...])

Модели:

Модель Размер Скорость (CPU) Точность
Whisper tiny 75 MB ~5x realtime 85% WER
Whisper base 145 MB ~3x realtime 90% WER
Whisper medium 1.5 GB ~1x realtime 96% WER
Whisper large 3 GB ~0.5x realtime 98% WER

Выбор: Whisper medium — оптимальный баланс качество/скорость для CPU.

Что делает: 1. Загружает аудио (wav/mp3/ogg) 2. Конвертирует в 16kHz mono float32 3. Whisper → транскрипт с временными метками по сегментам 4. Каждый сегмент → TextEncoder → вектор 768d 5. Дополнительно: - определение языка (Whisper встроенный) - confidence score для каждого сегмента - детекция тишины / шума

Пример:

audio_path = "лекция_нейробиология.mp3"

segments = AudioEncoder.encode(audio_path)
# segments[0]:
#   vector:     [0.23, -0.45, 0.67, ...]  (768d)
#   transcript: "Нейрон — это основная клетка..."
#   time_start: 0.0
#   time_end:   15.3
#   confidence: 0.94
#   language:   "ru"

Акустические признаки (опционально): - Темп речи (слов/мин) - Паузы и их длительность - Громкость (RMS) - Эмоциональный тон (через librosa)


4. TemporalEncoder — кодирование видео

Видео = последовательность кадров + аудиодорожка.

video.mp4
    ├──► Кадры (каждые N секунд) → VisionEncoder → [v1, v2, v3, ...]
    └──► Аудиодорожка → AudioEncoder → [a1, a2, a3, ...]
         Temporal Fusion:
         усреднение / attention pooling
         вектор 512d (видео-представление)

Стратегии семплирования кадров:

Стратегия Описание Когда использовать
Uniform каждые N секунд длинные видео
Scene-based при смене сцены динамичный контент
Keyframe I-кадры из кодека быстро, без анализа
Dense каждый кадр короткие клипы < 30с

Для CPU-only: Uniform (каждые 5 секунд) — оптимально.


Выходной формат: EncodedPercept

@dataclass
class EncodedPercept:
    # Исходное событие
    percept_event: PerceptEvent

    # Основной вектор
    vector: np.ndarray          # 768d (текст/аудио) или 512d (изображение)
    vector_dim: int             # 768 или 512

    # Нормализованный вектор (для cosine similarity)
    vector_norm: np.ndarray     # L2-нормализованный

    # Текстовые признаки (для text/audio)
    keywords: List[str]         # ["нейрон", "клетка", "система"]
    message_type: str           # "question" | "statement" | "command"
    language: str               # "ru" | "en" | "mixed"
    sentiment: float            # -1.0 (негатив) ... +1.0 (позитив)

    # Визуальные признаки (для image/video)
    objects: List[str]          # ["нейрон", "аксон"]
    description: str            # "Схема нейрона с подписями"
    ocr_text: str               # "Нейрон, Аксон, Дендрит"

    # Аудио признаки (для audio/video)
    transcript: str             # полный транскрипт
    time_segments: List[dict]   # [{text, start, end, confidence}, ...]

    # Метаданные кодирования
    encoder_model: str          # "paraphrase-multilingual-mpnet-base-v2"
    encoding_time_ms: float     # время кодирования
    confidence: float           # уверенность энкодера 0.0–1.0

Сравнение векторов между модальностями

После кодирования можно сравнивать объекты разных модальностей:

Текст:      "нейрон под микроскопом"  → T_vec (768d)
Изображение: фото_нейрона.jpg         → I_vec (512d)
Аудио:      "...это нейрон..."        → A_vec (768d)

Для сравнения T_vec и I_vec нужна проекция в общее пространство:
  T_vec → Linear(768→512) → T_vec_proj (512d)
  cosine_similarity(T_vec_proj, I_vec) = 0.87  ← это задача Слоя 3

Слой 3 (Cross-Modal Fusion) занимается именно этим выравниванием.


Ресурсный бюджет (CPU-only, 32 GB RAM)

Энкодер RAM CPU потоки Время/запрос
TextEncoder (multilingual-mpnet) ~1.1 GB 2–4 50–100 мс
VisionEncoder (CLIP ViT-B/32) ~0.6 GB 2–4 200–500 мс
AudioEncoder (Whisper medium) ~1.5 GB 4–8 ~1x realtime
TemporalEncoder зависит от кадров 4–8 ~2–5с/мин видео
Итого ~3.2 GB 8–12

Стратегия при нехватке ресурсов:

CPU > 70%:  отложить VisionEncoder в очередь
CPU > 85%:  только TextEncoder (самый лёгкий)
RAM > 28GB: выгрузить AudioEncoder (Whisper) из памяти


Кэширование эмбеддингов

Кодирование — дорогая операция. Поэтому:

Запрос на кодирование файла X
Проверить кэш (SHA256 файла → вектор)
    ├── Кэш есть → вернуть кэшированный вектор (0 мс)
    └── Кэша нет → кодировать → сохранить в кэш → вернуть

Кэш хранится в:

brain/data/embeddings_cache/
    ├── text_cache.npz      (SHA256 → вектор 768d)
    ├── vision_cache.npz    (SHA256 → вектор 512d)
    └── audio_cache.npz     (SHA256 → вектор 768d)


Что Modality Encoders НЕ делают

Задача Кто делает
Чтение файлов с диска Perception Layer (Слой 1)
Выравнивание text↔image пространств Cross-Modal Fusion (Слой 3)
Сохранение в память Memory System (Слой 4)
Поиск по смыслу Memory System (Слой 4)
Рассуждение Cognitive Core (Слой 5)

Encoders только преобразуют сырые данные в векторы.


Статус реализации

Компонент Статус Файл
EncodedPercept dataclass ✅ Реализовано (Этап A) brain/core/contracts.py
TextEncoder ✅ Реализовано (Этап E, 80 тестов) brain/encoders/text_encoder.py
VisionEncoder ⬜ Этап J brain/encoders/vision_encoder.py
AudioEncoder ⬜ Этап J brain/encoders/audio_encoder.py
TemporalEncoder ⬜ Этап J brain/encoders/temporal_encoder.py
EmbeddingCache ⬜ Post-MVP brain/encoders/embedding_cache.py

Зависимости (Python пакеты)

sentence-transformers>=2.2.0   — TextEncoder (multilingual-mpnet)
torch>=2.0.0                   — базовый фреймворк (CPU-only)
transformers>=4.30.0           — CLIP, Whisper
openai-whisper>=20231117       — AudioEncoder
Pillow>=10.0.0                 — VisionEncoder (загрузка изображений)
numpy>=1.24.0                  — векторные операции

Итог: место Сенсорной коры в системе

Таламус → [СЕНСОРНАЯ КОРА] → Cross-Modal Fusion → Memory → Cognition
               ├── TextEncoder:    текст → 768d вектор
               ├── VisionEncoder:  изображение → 512d вектор
               ├── AudioEncoder:   аудио → 768d вектор
               └── TemporalEncoder: видео → 512d вектор
               └── Все векторы нормализованы (L2)
                   Все объекты в одном "языке" — числах
                   Готовы к сравнению и хранению

Сенсорная кора — это переводчик с языка данных на язык смысла (чисел).
После неё мозг работает только с векторами — независимо от исходной модальности.