Skip to content

16. Анатомия многомерных тензоров (3D+) в компьютерном зрении и NLP ​

Структуры данных в Computer Vision и NLP ​

Переход к N-мерным пространствам (Тензорам) ​

В реальных задачах глубокого обучения (Deep Learning) данных в виде одномерных векторов или двумерных матриц часто недостаточно. Объекты реального мира обладают большей вложенностью структур. В NumPy многомерные массивы размерностью N≥3 называются тензорами.

Принцип их устройства «под капотом» остается прежним: это все тот же линейный непрерывный блок памяти на C-уровне, но метаданные заголовка описывают сложную геометрию из 3, 4 и более осей (ndim >= 3), переходы между которыми контролируются многомерными шагами (strides).

Структуры данных в Компьютерном Зрении (Computer Vision) ​

Для обработки изображений нейросетями используются строго фиксированные стандарты размерностей:

  1. Одиночное цветное изображение (3D-тензор): Описывается формой [Height, Width, Channels].
  • Height — высота в пикселях,
  • Width — ширина,
  • Channels — цветовые каналы (обычно 3 канала для RGB: красный, зеленый, синий).
  1. Батч (порция) изображений для сверточных сетей (4D-тензор): Компьютер обрабатывает картинки пачками. Такая структура кодируется как [Batch, Height, Width, Channels]. Например, тензор формы (32, 224, 224, 3) означает пакет из 32 картинок размером 224x224 пикселя с 3 RGB-каналами.

Структуры данных в обработке текста (NLP) и Трансформерах ​

В текстовых моделях (например, GPT, BERT) данные организуются совершенно иначе:

  • Батч (порции) текстовых последовательностей (3D-тензор): Описывается формой [Batch, Seq_Len, Hidden_Dim].
    • Batch — количество предложений (текстов) в обрабатываемой пачке.
    • Seq_Len (Sequence Length) — длина предложения в токенах (словах или подсловах).
    • Hidden_Dim (Hidden Dimension) — размерность вектора эмбеддинга. Каждый токен кодируется плотным вектором чисел, отражающим его семантический смысл (например, 768 или 1024 числа на один токен).
python
import numpy

# Simulating an NLP Transformer input batch: 2 sentences, 4 tokens each, vector size 5
# Shape contract: [Batch, Seq_Len, Hidden_Dim]
nlp_tensor = numpy.ones((2, 4, 5), dtype=numpy.float32)

print("Tensors dimension count:", nlp_tensor.ndim)  # Outputs: 3
print("Tensor structural shape:", nlp_tensor.shape)  # Outputs: (2, 4, 5)

Понятие эмбеддингов (Embeddings) и их размерности ​

При работе с текстом, аудио или графикой в искусственном интеллекте компьютеры не могут напрямую оперировать словами или абстрактными образами. Для этого используется технология эмбеддингов (Embeddings).

Эмбеддинг — это способ представления объекта (например, слова или токена текста) в виде плотного вектора вещественных чисел, который отражает его скрытый смысл и контекст. В отличие от старых методов кодирования (вроде One-Hot Encoding), эмбеддинги позволяют математически вычислять схожесть понятий. Слова «кошка» и «собака» в пространстве эмбеддингов будут находиться близко друг к другу, а слово «небоскреб» — далеко от них.

Что значит «Плотный вектор чисел» (Dense Vector)? ​

В NumPy плотный вектор — это классический одномерный массив ndarray типа float32 или float64, в котором каждая ячейка заполнена значимым числом (обычно в диапазоне от -1.0 до 1.0).

  • Разреженный вектор (Sparse Vector): Огромный массив из тысяч нулей, где лишь в одном месте стоит единица ([0, 0, 0, 1, 0, 0, ...]). Неэффективно расходует память.
  • Плотный вектор (Dense Vector): Компактный массив, где каждое число кодирует определенный микро-признак слова ([-0.12, 0.45, 0.89, -0.31, ...]).

Размерность вектора эмбеддинга (Embedding Dimension) ​

Размерность (длина вектора) определяет, сколько именно чисел выделяется на кодирование смысла одного токена. В коде это обозначается как embedding_dim или d_model.

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

  • В простых моделях (например, Word2Vec) размерность обычно равна 300.
  • В современных трансформерах (BERT) размерность составляет 768.
  • В мощных LLM (GPT-4, LLaMA) размерность одного токена может достигать 4096 чисел и более.

Пример. Анатомия токена и его размерности в NumPy ​

Рассмотрим, как один текстовый токен (слово «AI») превращается в плотный вектор с размерностью dim=8 (для наглядности размерность уменьшена):

python
import numpy as np

# A real token ID from a vocabulary (e.g., word "AI" equals token 2467)
token_id = 2467

# A dense embedding vector for this token (Embedding Dimension = 8)
# Each float value represents a hidden semantic feature learned by the AI
ai_token_embedding = np.array([0.15, -0.62, 0.88, 0.04, -0.11, 0.93, -0.42, 0.21], dtype=np.float32)

# Checking the dimensionality (length of the vector)
print(f"Token vector shape: {ai_token_embedding.shape}")  # Outputs: (8,)
print(f"Embedding dimension size: {len(ai_token_embedding)}")  # Outputs: 8

Визуализация смысла через геометрию ​

Благодаря тому, что токен становится вектором чисел, мы можем измерять расстояние между словами с помощью стандартных векторных ufuncs-операций NumPy. Например, если вычесть из эмбеддинга слова «Король» эмбеддинг слова «Мужчина» и прибавить эмбеддинг слова «Женщина», математический вектор результата окажется максимально близким к эмбеддингу слова «Королева».

Срезы многомерных пространств ​

Правила многомерных срезов ​

Логика срезов в N-мерных пространствах является прямым продолжением двумерного слайсинга. Внутри квадратных скобок параметры каждой оси перечисляются через запятую: tensor[batch_idx, height_idx, width_idx, channel_idx]

Если по какой-то оси требуется забрать элементы целиком, используется символ двоеточия :.

Практические сценарии извлечения подмассивов ​

При работе с изображениями и текстом многомерный слайсинг применяется для решения следующих задач:

  • Вычленение конкретного объекта из батча: Срез image_batch[0, :, :, :] (или сокращенно image_batch[0]) извлечет самую первую картинку из пакета, сохранив её 3D-структуру [Height, Width, Channels].
  • Изоляция цветового канала: Срез image_batch[:, :, :, 0] соберет только нулевой (Красный — R) канал для абсолютно всех картинок внутри батча.
  • Кроп (Cropping): Обрезание краев изображения по осям высоты и ширины: image[40:160, 40:160, :].
python
import numpy

# Simulating a mini-batch of 2 color images, 100x100 pixels each
# Shape layout: [Batch, Height, Width, Channels]
image_batch = numpy.zeros((2, 100, 100, 3), dtype=numpy.uint8)

# Extracting the second image from the batch
single_image = image_batch[1, :, :, :]
print("Single image shape:", single_image.shape)  # Outputs: (100, 100, 3)

# Extracting only the Green channel (index 1) for the first image
green_channel = image_batch[0, :, :, 1]
print("Green channel slice shape:", green_channel.shape)  # Outputs 2D grid: (100, 100)

Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию) ​

1. Конструирование 3D-тензора цветного изображения ​

Задача: Инициализируйте пустой 3D-тензор, имитирующий одиночное цветное RGB-изображение размером 480 пикселей по высоте и 640 пикселей по ширине, полностью заполненный нулями. Выведите его структуру .shape и вес в килобайтах.

Посмотреть решение
python
import numpy

# Allocation syntax for a 3D image tensor: [Height, Width, Channels]
rgb_image = numpy.zeros((480, 640, 3), dtype=numpy.uint8)
print("Image geometry shape:", rgb_image.shape)  # Outputs: (480, 640, 3)
print("Image weight kilobytes:", rgb_image.nbytes//1024, 'kB')  # Outputs: 900

2. Извлечение отдельного предложения из батча Трансформера ​

Задача: Дан 3D-тензор текстовых эмбеддингов nlp_batch = numpy.ones((4, 12, 768)), содержащий пакет из 4 предложений. Используя многомерный срез, извлеките из батча целиком третье предложение (индекс 2), включая все его токены и их эмбеддинги. Выведите форму (shape) полученного подмассива.

Посмотреть решение
python
import numpy

nlp_batch = numpy.ones((4, 12, 768))

# Extracting the 3rd sample while preserving all tokens and hidden dimensions
single_sentence = nlp_batch[2, :, :]
print("Extracted sentence shape:", single_sentence.shape)  # Outputs: (12, 768)

3. Изоляция Синего (Blue) канала в батче картинок ​

Задача: Сгенерируйте 4D-тензор батча изображений images_tensor = numpy.ones((8, 224, 224, 3)) (8 картинок формата 224x224x3). С помощью одного многомерного среза извлеките Синий цветовой канал (индекс 2) для всех картинок батча одновременно. Выведите форму полученного результата.

Посмотреть решение
python
import numpy

images_tensor = numpy.ones((8, 224, 224, 3))

# Using ':' to capture all items along Batch, Height, and Width axes
blue_channels_batch = images_tensor[:, :, :, 2]
print("Blue channels projection shape:", blue_channels_batch.shape)  # Outputs: (8, 224, 224)

4. Извлечение конкретного токена из структуры данных NLP ​

Задача: Дан 3D-тензор текстовой последовательности text_tensor = numpy.ones((2, 10, 512)) (2 предложения, по 10 токенов в каждом, размер эмбеддинга 512). Извлеките вектор эмбеддинга для самого первого токена (индекс 0) во втором предложении (индекс 1). Выведите геометрию полученного вектора.

Посмотреть решение
python
import numpy

text_tensor = numpy.ones((2, 10, 512))

# Pinpointing specific batch and token positions, capturing the whole embedding axis
token_embedding_vector = text_tensor[1, 0, :]
print("Token vector dimensions:", token_embedding_vector.shape)  # Outputs: (512,)

5. Обрезание краев изображения (Центральный кроп) ​

Задача: Имеется 3D-массив фотографии photo = numpy.ones((300, 300, 3)). Выполните операцию кроппинга — вырежьте центральный квадратный фрагмент с координатами по высоте от 100 до 200 (не включая верхнюю границу) и по ширине от 100 до 200, сохранив все цветовые каналы. Выведите форму кропнутого массива.

Посмотреть решение
python
import numpy

photo = numpy.ones((300, 300, 3))

# Slicing bounding regions on structural axes, keeping channels intact
cropped_photo = photo[100:200, 100:200, :]
print("Cropped image geometry shape:", cropped_photo.shape)  # Outputs: (100, 100, 3)

Упражнения смешанные (5 шт) (включают материал прошлых уроков) ​

6. Глобальный аудит характеристик и шагов многомерного тензора ​

Задача: Создайте 3D-тензор текстовых батчей размерностью (2, 3, 4) из целых чисел с явным указанием типа данных dtype=numpy.int32 (Урок 4 / Урок 16). Выведите на экран его базовые метаданные: общее число элементов .size, физический вес в байтах .nbytes (Урок 2) и шаг в памяти .strides (Урок 11). Прочитайте комментарий к решению, объясняющий физическое устройство 3D-шагов.

Посмотреть решение
python
import numpy

# Setting up a structured 3D coordinate block tensor (Lesson 4 & Lesson 16)
text_tensor = numpy.ones((2, 3, 4), dtype=numpy.int32)

print("Total items:", text_tensor.size)      # 2 * 3 * 4 = 24 elements
print("Byte size:", text_tensor.nbytes, "bytes")  # 24 elements * 4 bytes = 96 bytes

# Strides analysis in 3D block layouts (Lesson 2 & Lesson 11)
print("Tensor strides layout:", text_tensor.strides)  # Outputs: (48, 16, 4)
# Explanation: Each int32 is 4 bytes. Moving 1 item right takes 4 bytes.
# Moving 1 token down forces skipping an entire row of 4 items (4 * 4 = 16 bytes).
# Moving 1 batch block forces skipping 3 rows of tokens (3 * 16 = 48 bytes).

7. Поэлементная маска и in-place модификация канала батча изображений ​

Задача: Сгенерируйте 4D-тензор батча масок цветных картинок image_batch = numpy.ones((2, 10, 10, 3), dtype=numpy.float32) (Урок 11 / Урок 16). Выделите из него Синий канал (индекс 2) для первой картинки (индекс 0) через многомерный срез (Урок 16). Умножьте элементы этого канала на месте (in-place) на скаляр 0.0 через оператор *= (Урок 8). Выведите форму всего батча и убедитесь через проверку мутаций, что исходный тензор изменил значения в буфере памяти (Урок 6).

Посмотреть решение
python
import numpy

image_batch = numpy.ones((2, 10, 10, 3), dtype=numpy.float32)

# Extracting a specific 2D matrix channel view slice (Lesson 13 & Lesson 16)
blue_channel_view = image_batch[0, :, :, 2]

# Perform in-place multiplication optimization (Lesson 8)
blue_channel_view *= 0.0

# Verifying array states and metadata preservation (Lesson 6 & Lesson 11)
print("Original batch architecture remains:", image_batch.shape)  # (2, 10, 10, 3)
print("Check if changes propagated to root memory:", image_batch[0, 0, 0, 2])  # Outputs: 0.0

8. Матричная агрегация по осям внутри извлеченного NLP-батча ​

Задача: Дан 3D-тензор скрытых состояний Трансформера hidden_states = numpy.ones((2, 5, 3)) (Урок 16). Выделите из него срез, содержащий только первое предложение (индекс 0) (Урок 13). Для полученной 2D-матрицы посчитайте вектор средних значений вдоль столбцов (axis=0), то есть усредните скрытые фичи по всем токенам последовательности (Урок 15). Выведите форму результирующего вектора.

Посмотреть решение
python
import numpy

hidden_states = numpy.ones((2, 5, 3))

# Step 1: Extract flat matrix view from 3D block space (Lesson 13 & Lesson 16)
first_sample_matrix = hidden_states[0, :, :]  # Shape: (5, 3)

# Step 2: Perform feature reduction along columns axis (Lesson 15)
features_mean_vector = first_sample_matrix.mean(axis=0)

print("Averaged feature vector content:", features_mean_vector)  # Outputs: [1. 1. 1.]
print("Final vector geometry shape:", features_mean_vector.shape)  # Outputs: (3,)

9. Квантование и изолированное копирование текстового батча ​

Задача: Имеется 3D-тензор сырых распределений вероятностей символов text_scores = numpy.ones((2, 4, 3)) (Урок 16). Преобразуйте его в целочисленный квантованный формат numpy.int8 с помощью метода .astype() (Урок 4 / Урок 7). Чтобы защитить лог, сделайте полную изолированную копию полученного тензора через .copy() (Урок 6). С помощью numpy.isnan() докажите в комментарии, почему в целочисленных квантованных массивах поиск вещественных NaN не имеет практического смысла.

Посмотреть решение
python
import numpy

text_scores = numpy.ones((2, 4, 3))

# Explicit quantization and deep copying (Lesson 4, 6 & 7)
quantized_tensor_copy = text_scores.astype(numpy.int8).copy()

print("Is structural base None?", quantized_tensor_copy.base is None)  # True

# Note on engineering practices:
# Running numpy.isnan(quantized_tensor_copy) will work, but it will return ALL False.
# Integer data types (int8, int32) cannot physically store IEEE 754 NaN markers. 
# NaN is strictly a floating-point (float32/float64) feature component (Lesson 9).

10. Поиск предсказанных классов (Argmax) в многомерном выходном пространстве ​

Задача: Модель классификации пикселей (сегментация) выдала 3D-тензор прогнозов для одной картинки размером 2x2 пикселя по 3 классам: segmentation_logits = numpy.array([[[0.8, 0.1, 0.1], [0.2, 0.2, 0.6]], [[0.3, 0.4, 0.3], [0.1, 0.9, 0.0]]]) (Размерность 2x2x3) (Урок 16). С помощью метода .argmax() найдите индексы максимальных классов, указав в качестве оси последнюю размерность axis=2 (ось классов) (Урок 15). Выведите полученную 2D-карту сегментации пикселей на экран.

Посмотреть решение
python
import numpy

# 3D matrix pixel logs setup: Shape [Height=2, Width=2, Classes=3] (Lesson 16)
segmentation_logits = numpy.array([
    [[0.8, 0.1, 0.1], [0.2, 0.2, 0.6]],
    [[0.3, 0.4, 0.3], [0.1, 0.9, 0.0]]
])

# Reducing the classes dimension to extract single index label maps per pixel (Lesson 15)
segmentation_map = segmentation_logits.argmax(axis=2)

print("Extracted 2D segmentations pixels map:\n", segmentation_map)
# Outputs a clean 2D grid containing winning class index codes:
# [[0 2]
#  [1 1]]