Фаза 01 · урок 02
Векторы, матрицы и операции
Цель урока: Оператор @ означает умножение матриц. weights — это матрица. input — это вектор. Если вы не знаете, что делают эти операции, данная строка выглядит магией. Если знаете, то перед вами весь прямой проход слоя, выраженный тремя операциями.
Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.
Содержание урока
- Цели обучения
- Проблема
- Концепция
- Векторы: упорядоченные списки чисел
- Матрицы: сетки чисел
- Почему размеры имеют значение
- Карта операций
- Поэлементное умножение и умножение матриц
- Трансляция
- Соберите это
- Шаг 1. Класс Vector
- Шаг 2. Класс Matrix с основными операциями
- Шаг 3. Посмотрите, как это работает
- Шаг 4. Свяжите это с нейронными сетями
- Используйте это
- Подготовьте результат
- Упражнения
- Ключевые термины
- Дополнительные материалы
Любая нейронная сеть — это всего лишь умножение матриц с дополнительными шагами.
Тип: Практика Языки: Python, Julia Предварительные требования: Фаза 1, урок 01 («Интуитивное понимание линейной алгебры») Время: около 60 минут
Цели обучения
- Создать класс Matrix с поэлементными операциями, умножением матриц, транспонированием, определителем и обратной матрицей.
- Различать поэлементное умножение и умножение матриц и объяснять, когда применяется каждое из них.
- Реализовать один полносвязный слой нейронной сети (
relu(W @ x + b)), используя только созданный с нуля класс Matrix. - Объяснить правила трансляции (broadcasting) и то, как сложение со смещением работает во фреймворках нейронных сетей.
Проблема
Вы хотите создать нейронную сеть. Вы читаете код и видите следующее:
output = activation(weights @ input + bias)
Оператор @ означает умножение матриц. weights — это матрица. input — это вектор. Если вы не знаете, что делают эти операции, данная строка выглядит магией. Если знаете, то перед вами весь прямой проход слоя, выраженный тремя операциями.
Каждое изображение, обрабатываемое вашей моделью, — это матрица значений пикселей. Каждый эмбеддинг слова — это вектор. Каждый слой любой нейронной сети — это матричное преобразование. Нельзя создавать системы AI, не владея матричными операциями так же свободно, как нельзя писать код, не понимая переменных.
В этом уроке вы освоите эти навыки с нуля.
Концепция
Векторы: упорядоченные списки чисел
Вектор — это список чисел, обладающий направлением и величиной. В AI векторами представляют точки данных, признаки или параметры.
v = [3, 4] -- двумерный вектор
w = [1, 0, -2] -- трёхмерный вектор
Двумерный вектор [3, 4] указывает на координаты (3, 4) на плоскости. Его длина (величина) равна 5 (треугольник со сторонами 3, 4 и 5).
Матрицы: сетки чисел
Матрица — это двумерная сетка. Строки и столбцы. Матрица размера m x n имеет m строк и n столбцов.
A = | 1 2 3 | -- матрица 2x3 (2 строки, 3 столбца)
| 4 5 6 |
В нейронных сетях матрицы весов преобразуют входные векторы в выходные. Слой с 784 входами и 128 выходами использует матрицу весов размером 128x784.
Почему размеры имеют значение
У умножения матриц есть строгое правило: (m x n) @ (n x p) = (m x p). Внутренние размерности должны совпадать.
(128 x 784) @ (784 x 1) = (128 x 1)
веса вход выход
Внутренние размерности: 784 = 784 -- допустимо
Именно поэтому в PyTorch возникает ошибка несовпадения размеров.
Карта операций
| Операция | Что она делает | Применение в нейронной сети |
|---|---|---|
| Сложение | Поэлементно объединяет | Добавление смещения к выходу |
| Умножение на скаляр | Масштабирует каждый элемент | Скорость обучения * градиенты |
| Умножение матриц | Преобразует векторы | Прямой проход слоя |
| Транспонирование | Меняет местами строки и столбцы | Обратное распространение ошибки |
| Определитель | Даёт одно число, характеризующее матрицу | Проверка обратимости |
| Обратная матрица | Отменяет преобразование | Решение систем линейных уравнений |
| Единичная матрица | Матрица, которая ничего не меняет | Инициализация, остаточные связи |
Поэлементное умножение и умножение матриц
Это различие постоянно сбивает с толку начинающих.
Поэлементное умножение: перемножаются элементы на соответствующих позициях. Обе матрицы должны иметь одинаковый размер.
| 1 2 | | 5 6 | | 5 12 |
| 3 4 | * | 7 8 | = | 21 32 |
Умножение матриц: вычисляются скалярные произведения строк и столбцов. Внутренние размерности должны совпадать.
| 1 2 | | 5 6 | | 1*5+2*7 1*6+2*8 | | 19 22 |
| 3 4 | @ | 7 8 | = | 3*5+4*7 3*6+4*8 | = | 43 50 |
Разные операции, разные результаты, разные правила.
Трансляция
При добавлении вектора смещения к матрице выходов их размеры не совпадают. Трансляция (broadcasting) растягивает меньший массив до нужного размера.
| 1 2 3 | + [10, 20, 30]
| 4 5 6 |
Трансляция растягивает вектор по строкам:
| 1 2 3 | | 10 20 30 | | 11 22 33 |
| 4 5 6 | + | 10 20 30 | = | 14 25 36 |
Каждый современный фреймворк делает это автоматически. Понимание трансляции помогает избежать путаницы, когда размеры кажутся неправильными, но код выполняется.
vector-projection
Соберите это
Шаг 1. Класс Vector
class Vector:
def __init__(self, data):
self.data = list(data)
self.size = len(self.data)
def __repr__(self):
return f"Vector({self.data})"
def __add__(self, other):
return Vector([a + b for a, b in zip(self.data, other.data)])
def __sub__(self, other):
return Vector([a - b for a, b in zip(self.data, other.data)])
def __mul__(self, scalar):
return Vector([x * scalar for x in self.data])
def dot(self, other):
return sum(a * b for a, b in zip(self.data, other.data))
def magnitude(self):
return sum(x ** 2 for x in self.data) ** 0.5
Шаг 2. Класс Matrix с основными операциями
class Matrix:
def __init__(self, data):
self.data = [list(row) for row in data]
self.rows = len(self.data)
self.cols = len(self.data[0])
self.shape = (self.rows, self.cols)
def __repr__(self):
rows_str = "\n ".join(str(row) for row in self.data)
return f"Matrix({self.shape}):\n {rows_str}"
def __add__(self, other):
return Matrix([
[self.data[i][j] + other.data[i][j] for j in range(self.cols)]
for i in range(self.rows)
])
def __sub__(self, other):
return Matrix([
[self.data[i][j] - other.data[i][j] for j in range(self.cols)]
for i in range(self.rows)
])
def scalar_multiply(self, scalar):
return Matrix([
[self.data[i][j] * scalar for j in range(self.cols)]
for i in range(self.rows)
])
def element_wise_multiply(self, other):
return Matrix([
[self.data[i][j] * other.data[i][j] for j in range(self.cols)]
for i in range(self.rows)
])
def matmul(self, other):
return Matrix([
[
sum(self.data[i][k] * other.data[k][j] for k in range(self.cols))
for j in range(other.cols)
]
for i in range(self.rows)
])
def transpose(self):
return Matrix([
[self.data[j][i] for j in range(self.rows)]
for i in range(self.cols)
])
def determinant(self):
if self.shape == (1, 1):
return self.data[0][0]
if self.shape == (2, 2):
return self.data[0][0] * self.data[1][1] - self.data[0][1] * self.data[1][0]
det = 0
for j in range(self.cols):
minor = Matrix([
[self.data[i][k] for k in range(self.cols) if k != j]
for i in range(1, self.rows)
])
det += ((-1) ** j) * self.data[0][j] * minor.determinant()
return det
def inverse_2x2(self):
det = self.determinant()
if det == 0:
raise ValueError("Matrix is singular, no inverse exists")
return Matrix([
[self.data[1][1] / det, -self.data[0][1] / det],
[-self.data[1][0] / det, self.data[0][0] / det]
])
@staticmethod
def identity(n):
return Matrix([
[1 if i == j else 0 for j in range(n)]
for i in range(n)
])
Шаг 3. Посмотрите, как это работает
A = Matrix([[1, 2], [3, 4]])
B = Matrix([[5, 6], [7, 8]])
print("A + B =", (A + B).data)
print("A @ B =", A.matmul(B).data)
print("A^T =", A.transpose().data)
print("det(A) =", A.determinant())
print("A^-1 =", A.inverse_2x2().data)
I = Matrix.identity(2)
print("A @ A^-1 =", A.matmul(A.inverse_2x2()).data)
Шаг 4. Свяжите это с нейронными сетями
import random
inputs = Matrix([[0.5], [0.8], [0.2]])
weights = Matrix([
[random.uniform(-1, 1) for _ in range(3)]
for _ in range(2)
])
bias = Matrix([[0.1], [0.1]])
def relu_matrix(m):
return Matrix([[max(0, val) for val in row] for row in m.data])
pre_activation = weights.matmul(inputs) + bias
output = relu_matrix(pre_activation)
print(f"Input shape: {inputs.shape}")
print(f"Weight shape: {weights.shape}")
print(f"Output shape: {output.shape}")
print(f"Output: {output.data}")
Это один полносвязный слой: output = relu(W @ x + b). Каждый полносвязный слой в любой нейронной сети делает именно это.
Используйте это
NumPy делает всё перечисленное выше меньшим количеством строк и на порядки быстрее.
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print("A + B =\n", A + B)
print("A * B (element-wise) =\n", A * B)
print("A @ B (matrix multiply) =\n", A @ B)
print("A^T =\n", A.T)
print("det(A) =", np.linalg.det(A))
print("A^-1 =\n", np.linalg.inv(A))
print("I =\n", np.eye(2))
inputs = np.random.randn(3, 1)
weights = np.random.randn(2, 3)
bias = np.array([[0.1], [0.1]])
output = np.maximum(0, weights @ inputs + bias)
print(f"\nNeural network layer: {weights.shape} @ {inputs.shape} = {output.shape}")
print(f"Output:\n{output}")
Оператор @ в Python вызывает __matmul__. NumPy реализует его с помощью оптимизированных процедур BLAS, написанных на C и Fortran. Та же математика, но в 100 раз быстрее.
Трансляция в NumPy:
matrix = np.array([[1, 2, 3], [4, 5, 6]])
bias = np.array([10, 20, 30])
print(matrix + bias)
NumPy автоматически транслирует одномерный вектор смещения по обеим строкам. Именно так сложение со смещением работает в любом фреймворке нейронных сетей.
Подготовьте результат
В этом уроке создаётся промпт для обучения матричным операциям через геометрическую интуицию. См. outputs/prompt-matrix-operations.md.
Созданный здесь класс Matrix служит основой мини-фреймворка нейронной сети, который мы построим в фазе 3, уроке 10.
Упражнения
-
Проверьте обратную матрицу. Умножьте
A @ A.inverse_2x2()и убедитесь, что получили единичную матрицу. Попробуйте сделать это с тремя разными матрицами 2x2. Что происходит, когда определитель равен нулю? -
Реализуйте обратную матрицу 3x3. Расширьте класс Matrix так, чтобы он вычислял обратные матрицы 3x3 методом присоединённой матрицы. Сравните результат с
np.linalg.invиз NumPy. -
Создайте двухслойную сеть. Используя только свой класс Matrix (без NumPy), создайте двухслойную нейронную сеть: вход (3) -> скрытый слой (4) -> выход (2). Инициализируйте веса случайными значениями, выполните прямой проход и убедитесь, что все размеры верны.
Ключевые термины
| Термин | Что обычно говорят | Что это означает на самом деле |
|---|---|---|
| Вектор | «Стрелка» | Упорядоченный список чисел. В AI — точка в многомерном пространстве. |
| Матрица | «Таблица чисел» | Линейное преобразование. Оно отображает векторы из одного пространства в другое. |
| Умножение матриц | «Просто перемножить числа» | Скалярные произведения каждой строки первой матрицы и каждого столбца второй. Порядок имеет значение. |
| Транспонирование | «Перевернуть её» | Переставить местами строки и столбцы. Превратить матрицу m x n в матрицу n x m. Критически важно при обратном распространении ошибки. |
| Определитель | «Какое-то число из матрицы» | Показывает, во сколько раз матрица масштабирует площадь (в 2D) или объём (в 3D). Ноль означает, что преобразование сплющивает одно измерение. |
| Обратная матрица | «Отменить матрицу» | Матрица, которая обращает преобразование. Существует, только если определитель не равен нулю. |
| Единичная матрица | «Скучная матрица» | Матричный аналог умножения на 1. Используется в остаточных связях (ResNet). |
| Трансляция | «Магическое исправление размеров» | Растягивание меньшего массива до размера большего путём повторения вдоль отсутствующих измерений. |
| Поэлементная операция | «Обычное умножение» | Умножение элементов на соответствующих позициях. Оба массива должны иметь одинаковый размер или допускать трансляцию. |
Дополнительные материалы
- 3Blue1Brown: Essence of Linear Algebra — визуальное объяснение каждой рассмотренной здесь операции.
- Документация NumPy по трансляции — точные правила, которым следует NumPy.
- Stanford CS229 Linear Algebra Review — краткий справочник по линейной алгебре для машинного обучения.
Источник: Vectors, Matrices & Operations — оригинал Навигация: назад: 01.01 — Интуитивное понимание линейной алгебры · Фаза 1 — Математические основы · Полный каталог · далее: 01.03 — Матричные преобразования.