Фаза 01 · урок 19

Комплексные числа для AI

Цель урока: Вы открываете статью о преобразованиях Фурье — и повсюду видите i . Смотрите на позиционные кодировки трансформеров и находите sin и cos на разных частотах: действительную и мнимую части комплексных экспонент. Читаете о квантовых…

Текущий релиз AlexBred.com: первые 100 уроков русскоязычной программы.

Курс
AI Engineering from Scratch
Фаза
Математические основы
Чтение
16 мин.
Проверено
Содержание урока
  1. Цели обучения
  2. Проблема
  3. Концепция
  4. Что такое комплексное число?
  5. Арифметика комплексных чисел
  6. Комплексная плоскость
  7. Полярная форма
  8. Формула Эйлера
  9. Почему формула Эйлера важна для ML
  10. Связь с двумерными вращениями
  11. Фазоры и вращающиеся сигналы
  12. Корни из единицы
  13. Связь с DFT
  14. Почему i — не «мнимая»
  15. Комплексные экспоненты и тригонометрические функции
  16. Связь с трансформерами
  17. Соберите это
  18. Шаг 1: класс Complex
  19. Шаг 2: переход к полярной форме и формула Эйлера
  20. Шаг 3: вращение
  21. Шаг 4: DFT из комплексной арифметики
  22. Шаг 5: обратное DFT
  23. Шаг 6: корни из единицы
  24. Используйте это
  25. Выпустите это
  26. Упражнения
  27. Ключевые термины
  28. Дополнительное чтение

Квадратный корень из -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)]

Результаты совпадают. Комплексное умножение есть двумерное вращение. Матрица вращения — это просто комплексное умножение, записанное в матричной форме.

Диаграмма к уроку «Комплексные числа для AI»

Фазоры и вращающиеся сигналы

Комплексная экспонента 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

Диаграмма к уроку «Комплексные числа для AI»

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.

Упражнения

  1. Комплексная арифметика вручную. Вычислите (2 + 3i) * (4 - i) и проверьте результат кодом. Затем вычислите (5 + 2i) / (1 - 3i). Нарисуйте оба результата на комплексной плоскости и убедитесь, что умножение повернуло и масштабировало первое число.

  2. Последовательность вращений. Начните с точки (1, 0). Двенадцать раз умножьте на e^(i*pi/6). Убедитесь, что после 12 умножений вы возвращаетесь в (1, 0). Выведите координаты на каждом шаге и подтвердите, что они образуют правильный 12-угольник.

  3. DFT известного сигнала. Создайте сигнал — сумму sin(2*pi*3*t) и 0.5*sin(2*pi*7*t), взятую в 32 точках. Запустите своё DFT. Убедитесь, что спектр модулей имеет пики на частотах 3 и 7, а пик на 7 вдвое ниже пика на 3.

  4. Визуализация корней из единицы. Вычислите корни восьмой степени из единицы. Убедитесь, что их сумма равна нулю. Убедитесь, что умножение любого корня на примитивный корень e^(2*pi*i/8) даёт следующий корень.

  5. Эквивалентность матрицы вращения. Для 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. Использует комплексное умножение для кодирования относительного положения во внимании трансформера

Дополнительное чтение


Источник: Complex Numbers for AI Навигация: 01.18 — Выпуклая оптимизация · Фаза 1 — Математические основы · Полный каталог · 01.20 — Преобразование Фурье