Фаза 01 · урок 19
Комплексные числа для AI
Цель урока: Вы открываете статью о преобразованиях Фурье — и повсюду видите i . Смотрите на позиционные кодировки трансформеров и находите sin и cos на разных частотах: действительную и мнимую части комплексных экспонент. Читаете о квантовых…
Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.
Содержание урока
- Цели обучения
- Проблема
- Концепция
- Что такое комплексное число?
- Арифметика комплексных чисел
- Комплексная плоскость
- Полярная форма
- Формула Эйлера
- Почему формула Эйлера важна для ML
- Связь с двумерными вращениями
- Фазоры и вращающиеся сигналы
- Корни из единицы
- Связь с DFT
- Почему i — не «мнимая»
- Комплексные экспоненты и тригонометрические функции
- Связь с трансформерами
- Соберите это
- Шаг 1: класс Complex
- Шаг 2: переход к полярной форме и формула Эйлера
- Шаг 3: вращение
- Шаг 4: DFT из комплексной арифметики
- Шаг 5: обратное DFT
- Шаг 6: корни из единицы
- Используйте это
- Выпустите это
- Упражнения
- Ключевые термины
- Дополнительное чтение
Квадратный корень из -1 — не мнимая величина. Это ключ к вращениям, частотам и половине обработки сигналов.
Тип: Изучение Язык: Python Предварительные требования: Фаза 1, уроки 01–04 (линейная алгебра, математический анализ) Время: ~60 минут
Цели обучения
- Выполнять арифметические операции с комплексными числами (сложение, умножение, деление, сопряжение) как в алгебраической, так и в полярной форме.
- Применять формулу Эйлера для перехода между комплексными экспонентами и тригонометрическими функциями.
- Реализовать дискретное преобразование Фурье (Discrete Fourier Transform, DFT) с помощью комплексных корней из единицы.
- Объяснять, как комплексные вращения лежат в основе RoPE и синусоидальных позиционных кодировок в трансформерах.
Проблема
Вы открываете статью о преобразованиях Фурье — и повсюду видите i. Смотрите на позиционные кодировки трансформеров и находите sin и cos на разных частотах: действительную и мнимую части комплексных экспонент. Читаете о квантовых вычислениях — и всё выражено в комплексных векторных пространствах.
Комплексные числа кажутся абстрактными. Система чисел, построенная на квадратном корне из -1, выглядит математической уловкой. Но это не уловка. Это естественный язык вращений и колебаний. Всякий раз, когда что-то вращается, вибрирует или колеблется, комплексные числа — подходящий инструмент.
Не понимая комплексных чисел, нельзя понять дискретное преобразование Фурье. Нельзя понять FFT. Нельзя понять, как работает RoPE (Rotary Position Embedding) в современных языковых моделях. Нельзя понять, почему синусоидальные позиционные кодировки из исходной статьи о Transformer используют именно такие частоты.
Этот урок строит арифметику комплексных чисел с нуля, связывает её с геометрией и точно показывает, где комплексные числа возникают в машинном обучении.
Концепция
Что такое комплексное число?
Комплексное число имеет две части: действительную и мнимую.
z = a + bi
где:
a — действительная часть
b — мнимая часть
i — мнимая единица, определяемая как i^2 = -1
Вот и всё. Вы расширяете числовую прямую до плоскости. Действительные числа располагаются на одной оси, мнимые — на другой. Каждое комплексное число является точкой этой плоскости.
Арифметика комплексных чисел
Сложение. Сложите действительные части и сложите мнимые части.
(a + bi) + (c + di) = (a + c) + (b + d)i
Пример: (3 + 2i) + (1 + 4i) = 4 + 6i
Умножение. Используйте распределительный закон и помните, что i^2 = -1.
(a + bi)(c + di) = ac + adi + bci + bdi^2
= ac + adi + bci - bd
= (ac - bd) + (ad + bc)i
Пример: (3 + 2i)(1 + 4i) = 3 + 12i + 2i + 8i^2
= 3 + 14i - 8
= -5 + 14i
Сопряжение. Поменяйте знак мнимой части.
сопряжённое к (a + bi) = a - bi
Произведение комплексного числа на сопряжённое всегда действительно:
(a + bi)(a - bi) = a^2 + b^2
Деление. Умножьте числитель и знаменатель на сопряжённое к знаменателю.
(a + bi) / (c + di) = (a + bi)(c - di) / (c^2 + d^2)
Так мнимая часть устраняется из знаменателя и получается обычное комплексное число.
Комплексная плоскость
Комплексная плоскость сопоставляет каждому комплексному числу двумерную точку. Горизонтальная ось — действительная, вертикальная — мнимая.
z = 3 + 2i соответствует точке (3, 2)
z = -1 + 0i соответствует точке (-1, 0) на действительной оси
z = 0 + 4i соответствует точке (0, 4) на мнимой оси
Комплексное число одновременно является точкой и вектором из начала координат. Именно эта двойственная интерпретация делает комплексные числа полезными в геометрии.
Полярная форма
Любую точку на плоскости можно описать расстоянием от начала координат и углом относительно положительной действительной оси.
z = r * (cos(theta) + i*sin(theta))
где:
r = |z| = sqrt(a^2 + b^2) (модуль, или величина)
theta = atan2(b, a) (фаза, или аргумент)
Алгебраическая форма (a + bi) удобна для сложения. Полярная форма (r, theta) удобна для умножения.
Умножение в полярной форме. Перемножьте модули и сложите углы.
z1 = r1 * e^(i*theta1)
z2 = r2 * e^(i*theta2)
z1 * z2 = (r1 * r2) * e^(i*(theta1 + theta2))
Вот почему комплексные числа идеально подходят для вращений. Умножение на комплексное число с модулем 1 является чистым вращением.
Формула Эйлера
Мост между комплексными экспонентами и тригонометрией:
e^(i*theta) = cos(theta) + i*sin(theta)
Это важнейшая формула урока. Когда theta = pi:
e^(i*pi) = cos(pi) + i*sin(pi) = -1 + 0i = -1
Следовательно: e^(i*pi) + 1 = 0
Пять фундаментальных констант (e, i, pi, 1, 0) связаны одним уравнением.
Почему формула Эйлера важна для ML
Формула Эйлера говорит, что e^(i*theta) описывает единичную окружность при изменении theta. При theta = 0 вы находитесь в (1, 0); при theta = pi/2 — в (0, 1); при theta = pi — в (-1, 0); при theta = 3pi/2 — в (0, -1). Полный оборот соответствует theta = 2pi.
Значит, комплексные экспоненты являются вращениями. А вращения встречаются повсюду в обработке сигналов и ML.
Связь с двумерными вращениями
Умножение комплексного числа (x + yi) на e^(i*theta) поворачивает точку (x, y) на угол theta вокруг начала координат.
Вращение через комплексное умножение:
(x + yi) * (cos(theta) + i*sin(theta))
= (x*cos(theta) - y*sin(theta)) + (x*sin(theta) + y*cos(theta))i
Вращение через умножение матриц:
[cos(theta) -sin(theta)] [x] [x*cos(theta) - y*sin(theta)]
[sin(theta) cos(theta)] [y] = [x*sin(theta) + y*cos(theta)]
Результаты совпадают. Комплексное умножение есть двумерное вращение. Матрица вращения — это просто комплексное умножение, записанное в матричной форме.
Фазоры и вращающиеся сигналы
Комплексная экспонента e^(i*omega*t) — это точка, вращающаяся по единичной окружности с угловой частотой omega. По мере роста t точка описывает окружность.
Действительная часть этой вращающейся точки — cos(omega*t). Мнимая часть — sin(omega*t). Синусоидальный сигнал — это тень вращающегося комплексного числа.
e^(i*omega*t) = cos(omega*t) + i*sin(omega*t)
Действительная часть: cos(omega*t) -- косинусоидальная волна
Мнимая часть: sin(omega*t) -- синусоидальная волна
Это фазорное представление. Вместо отслеживания извивающейся синусоиды вы отслеживаете плавно вращающуюся стрелку. Сдвиги фазы становятся смещениями угла, изменения амплитуды — изменениями модуля, а сложение сигналов — сложением векторов.
Корни из единицы
N-е корни из единицы — это N точек, равномерно расположенных на единичной окружности:
w_k = e^(2*pi*i*k/N) для k = 0, 1, 2, ..., N-1
При N = 4 корни равны 1, i, -1, -i (четыре стороны света). При N = 8 к ним добавляются четыре диагональных направления.
Корни из единицы — основа дискретного преобразования Фурье. DFT разлагает сигнал на компоненты на этих N равномерно распределённых частотах.
Связь с DFT
Дискретное преобразование Фурье сигнала x[0], x[1], ..., x[N-1]:
X[k] = sum_{n=0}^{N-1} x[n] * e^(-2*pi*i*k*n/N)
Каждый X[k] измеряет, насколько сигнал коррелирует с k-м корнем из единицы — комплексной синусоидой на частоте k. DFT раскладывает сигнал на N вращающихся фазоров и сообщает амплитуду и фазу каждого из них.
Почему i — не «мнимая»
Слово «мнимая» — историческая случайность. Декарт употребил его пренебрежительно. Но i не более мнимая, чем отрицательные числа, когда люди впервые их отвергли. Отрицательные числа отвечают на вопрос: «Что нужно вычесть из 3, чтобы получить 5?» Мнимая единица отвечает на вопрос: «Что нужно возвести в квадрат, чтобы получить -1?»
Полезнее рассматривать i как оператор поворота на 90 градусов. Умножив действительное число на i один раз, вы поворачиваете его на 90 градусов к мнимой оси. Умножив на i снова (i^2), вы поворачиваете ещё на 90 градусов — теперь направление указывает по отрицательной действительной оси. Поэтому i^2 = -1. Здесь нет тайны: это разворот на пол-оборота, составленный из двух четвертей оборота.
Вот почему комплексные числа повсюду в инженерии. Всё, что вращается — электромагнитные волны, квантовые состояния, колебания сигналов, позиционные кодировки, — естественно описывается комплексными числами.
Комплексные экспоненты и тригонометрические функции
До формулы Эйлера инженеры записывали сигналы как A*cos(omega*t + phi) — амплитуда A, частота omega, фаза phi. Это работает, но усложняет арифметику. Сложение двух косинусов с разными фазами требует тригонометрических тождеств.
С комплексными экспонентами тот же сигнал имеет вид A*e^(i*(omega*t + phi)). Сложить два сигнала — значит просто сложить два комплексных числа. Умножить (модулировать) — значит перемножить модули и сложить углы. Сдвиги фазы становятся сложением углов, а частотные сдвиги — умножением на фазоры.
Вся обработка сигналов перешла к комплексно-экспоненциальной записи, потому что математика стала чище. «Действительный сигнал» всегда является лишь действительной частью комплексного представления. Мнимая часть сохраняется как вспомогательная величина, естественно обеспечивающая всю алгебру.
Связь с трансформерами
Синусоидальные позиционные кодировки (исходная статья о Transformer):
PE(pos, 2i) = sin(pos / 10000^(2i/d))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d))
Пары sin и cos — действительная и мнимая части комплексных экспонент на разных частотах. Каждая частота задаёт своё «разрешение» кодирования позиции. Низкие частоты меняются медленно (грубая позиция), высокие — быстро (точная позиция). Вместе они дают каждой позиции уникальный частотный отпечаток.
RoPE (Rotary Position Embedding) идёт дальше. Она явно умножает векторы запросов и ключей на комплексные матрицы вращения. Относительное положение двух токенов становится углом поворота. Внимание вычисляется с этими повёрнутыми векторами, поэтому модель становится чувствительной к относительному положению через комплексное умножение.
| Операция | Алгебраическая форма | Геометрический смысл |
|---|---|---|
| Сложение | (a+c) + (b+d)i | Сложение векторов на плоскости |
| Умножение | (ac-bd) + (ad+bc)i | Поворот и масштабирование |
| Сопряжение | a - bi | Отражение относительно действительной оси |
| Модуль | sqrt(a^2 + b^2) | Расстояние от начала координат |
| Фаза | atan2(b, a) | Угол от положительной действительной оси |
| Деление | умножение на сопряжённое | Обратный поворот и масштабирование |
| Степень | r^n * e^(intheta) | Повернуть n раз, масштабировать на r^n |
roots-of-unity
Соберите это
Шаг 1: класс Complex
Создайте класс комплексного числа Complex, поддерживающий арифметику, модуль, фазу и переход между алгебраической и полярной формами.
import math
class Complex:
def __init__(self, real, imag=0.0):
self.real = real
self.imag = imag
def __add__(self, other):
return Complex(self.real + other.real, self.imag + other.imag)
def __mul__(self, other):
r = self.real * other.real - self.imag * other.imag
i = self.real * other.imag + self.imag * other.real
return Complex(r, i)
def __truediv__(self, other):
denom = other.real ** 2 + other.imag ** 2
r = (self.real * other.real + self.imag * other.imag) / denom
i = (self.imag * other.real - self.real * other.imag) / denom
return Complex(r, i)
def magnitude(self):
return math.sqrt(self.real ** 2 + self.imag ** 2)
def phase(self):
return math.atan2(self.imag, self.real)
def conjugate(self):
return Complex(self.real, -self.imag)
Шаг 2: переход к полярной форме и формула Эйлера
def to_polar(z):
return z.magnitude(), z.phase()
def from_polar(r, theta):
return Complex(r * math.cos(theta), r * math.sin(theta))
def euler(theta):
return Complex(math.cos(theta), math.sin(theta))
Проверьте: euler(theta).magnitude() всегда должен давать 1.0. euler(0) должен давать (1, 0), а euler(pi) — (-1, 0).
Шаг 3: вращение
Поворот точки (x, y) на угол theta — одно комплексное умножение:
point = Complex(3, 4)
rotated = point * euler(math.pi / 4)
Модуль остаётся тем же. Меняется только угол.
Шаг 4: DFT из комплексной арифметики
def dft(signal):
N = len(signal)
result = []
for k in range(N):
total = Complex(0, 0)
for n in range(N):
angle = -2 * math.pi * k * n / N
total = total + Complex(signal[n], 0) * euler(angle)
result.append(total)
return result
Это DFT сложности O(N^2). Каждый выход X[k] — сумма отсчётов сигнала, умноженных на корни из единицы.
Шаг 5: обратное DFT
Обратное DFT восстанавливает исходный сигнал из его спектра. По сравнению с прямым DFT меняются только две вещи: знак в экспоненте и деление на N.
def idft(spectrum):
N = len(spectrum)
result = []
for n in range(N):
total = Complex(0, 0)
for k in range(N):
angle = 2 * math.pi * k * n / N
total = total + spectrum[k] * euler(angle)
result.append(Complex(total.real / N, total.imag / N))
return result
Так получается точное восстановление. Примените DFT, затем IDFT — и получите исходный сигнал с точностью машинных вычислений. Информация не теряется.
Шаг 6: корни из единицы
def roots_of_unity(N):
return [euler(2 * math.pi * k / N) for k in range(N)]
Проверьте два свойства:
- Модуль каждого корня в точности равен 1.
- Сумма всех N корней равна нулю (они взаимно сокращаются благодаря симметрии).
Именно эти свойства делают DFT обратимым. Корни из единицы образуют ортогональный базис частотной области.
Используйте это
В Python есть встроенная поддержка комплексных чисел. Литерал j обозначает мнимую единицу.
z = 3 + 2j
w = 1 + 4j
print(z + w)
print(z * w)
print(abs(z))
import cmath
print(cmath.phase(z))
print(cmath.exp(1j * cmath.pi))
Для массивов numpy нативно обрабатывает комплексные числа:
import numpy as np
z = np.array([1+2j, 3+4j, 5+6j])
print(np.abs(z))
print(np.angle(z))
print(np.conj(z))
print(np.real(z))
print(np.imag(z))
signal = np.sin(2 * np.pi * 5 * np.linspace(0, 1, 128))
spectrum = np.fft.fft(signal)
freqs = np.fft.fftfreq(128, d=1/128)
Выпустите это
Запустите code/complex_numbers.py, чтобы создать outputs/skill-complex-arithmetic.md.
Упражнения
-
Комплексная арифметика вручную. Вычислите
(2 + 3i) * (4 - i)и проверьте результат кодом. Затем вычислите(5 + 2i) / (1 - 3i). Нарисуйте оба результата на комплексной плоскости и убедитесь, что умножение повернуло и масштабировало первое число. -
Последовательность вращений. Начните с точки
(1, 0). Двенадцать раз умножьте наe^(i*pi/6). Убедитесь, что после 12 умножений вы возвращаетесь в(1, 0). Выведите координаты на каждом шаге и подтвердите, что они образуют правильный 12-угольник. -
DFT известного сигнала. Создайте сигнал — сумму
sin(2*pi*3*t)и0.5*sin(2*pi*7*t), взятую в 32 точках. Запустите своё DFT. Убедитесь, что спектр модулей имеет пики на частотах 3 и 7, а пик на 7 вдвое ниже пика на 3. -
Визуализация корней из единицы. Вычислите корни восьмой степени из единицы. Убедитесь, что их сумма равна нулю. Убедитесь, что умножение любого корня на примитивный корень
e^(2*pi*i/8)даёт следующий корень. -
Эквивалентность матрицы вращения. Для 10 случайных углов и 10 случайных точек убедитесь, что комплексное умножение даёт тот же результат, что и умножение матрицы на вектор с матрицей вращения 2x2. Выведите максимальную численную разность.
Ключевые термины
| Термин | Значение |
|---|---|
| Комплексное число | Число a + bi, где a — действительная часть, b — мнимая часть, а i^2 = -1 |
| Мнимая единица | Число i, определяемое как i^2 = -1. Не мнимое в философском смысле — это оператор вращения |
| Комплексная плоскость | Двумерная плоскость, где ось x действительная, а ось y мнимая. Также называется плоскостью Аргана |
| Модуль (величина) | Расстояние от начала координат: sqrt(a^2 + b^2). Записывается как |z| |
| Фаза (аргумент) | Угол относительно положительной действительной оси: atan2(b, a). Записывается как arg(z) |
| Сопряжённое | Зеркальное отражение относительно действительной оси: сопряжённое к a + bi равно a - bi |
| Полярная форма | Представление z как r * e^(i*theta) вместо a + bi. Упрощает умножение |
| Формула Эйлера | e^(i*theta) = cos(theta) + i*sin(theta). Связывает экспоненты с тригонометрией |
| Фазор | Вращающееся комплексное число e^(i*omega*t), представляющее синусоидальный сигнал |
| Корни из единицы | N комплексных чисел e^(2*pi*i*k/N) для k от 0 до N-1: N равноотстоящих точек единичной окружности |
| DFT | Дискретное преобразование Фурье. Раскладывает сигнал на комплексные синусоидальные компоненты с помощью корней из единицы |
| RoPE | Rotary Position Embedding. Использует комплексное умножение для кодирования относительного положения во внимании трансформера |
Дополнительное чтение
- Наглядное введение в формулу Эйлера — геометрическая интуиция без тяжёлой нотации.
- Su et al.: RoFormer (2021) — статья, представившая Rotary Position Embedding на комплексных вращениях.
- Vaswani et al.: Attention Is All You Need (2017) — исходная статья о Transformer с синусоидальными позиционными кодировками.
- 3Blue1Brown: формула Эйлера с вводной теорией групп — визуальное объяснение того, почему
e^(i*pi) = -1. - Needham: Visual Complex Analysis — превосходное наглядное изложение комплексных чисел с богатой геометрической интуицией.
- Strang: Introduction to Linear Algebra, гл. 10 — комплексные числа в контексте линейной алгебры и собственных значений.
Источник: Complex Numbers for AI Навигация: 01.18 — Выпуклая оптимизация · Фаза 1 — Математические основы · Полный каталог · 01.20 — Преобразование Фурье