В результате тренировки автор добивается того, что модель начинает выдавать слова и фразы в стиле Шекспира, т. е. здесь явно находятся корреляции между буквами в текстах Шекспира. Вот тебе и все смыслы и зависимости между словами!
ВВЕДЕНИЕ В МАТЕМАТИКУ ИСКУССТВЕННОГО ИНТЕЛЛЕКТА
- ВВЕДЕНИЕ
Целью данной статьи является дать максимально упрощённое объяснение математических понятий, используемых в искусственном интеллекте (ИИ). Во второй главе мы, следуя традиции програмистских учебников “Hello World” приводим постановку популярной задачи ИИ о распозновании рукописных цифр. В третьей главe описывается программа решения этой задачи на языке Python. В четвёртой главе даётся объяснение ключевых методов оптимизации (обучения) ИИ — градиентного спуска и backpropagation. Cлова оптимизация и обучение будут использоваться как синонимы. Некоторые термины будем писать на английском так как не знаем русский эквивалент. В пятой главе вводится простой геометринеский смысл оптимизации и поясняется необходимость нелинейных элементов. В шестой главе вводится понятие достаточной схемы (ДС) и приводится краткое описание ДС в языковых моделях — Attention Mechanism, и в обработке изображений — Convolution Mechanism. Одним из важнейших математических аппаратов, приведших к созданию современных ИИ, является появившаяся возможность массивной параллельной обработки (ПО) данных. Автор не работал в области ИИ, но активно использовал ПО для разработки технологичеких процессов обработки металла. В седьмой главе приводится несколько примеров применения ПО в данной области. Целью главы является показать, что с появлением ПО революция происходит не только в ИИ. Седьмую главу можно спокойно пропустить без всякого ущерба пониманию основных понятий. В заключении пытаемся сделать некоторые общие выводы. Для чтения статьи необходимо минимальное понимание о производных и матрицах.
- РАСПОЗНОВАНИЕ РУКОПИСНЫХ ЦИФР
Американское почтовое ведомство накопило массив из 70 тысяч рукописных цифр MNIST, который регулярно используется для сравнения различных алгоритмов ИИ распознавания. Каждая цифра записана в виде чёрно-белого изображения 28*28 = 784 пикселей. Для каждого изображения в MNIST хранится соответствующая цифра от 0 до 9. Формально задачу распознавания можно поставить следующим образом. Имеется некоторая функция от 784 переменных (пиксели), выходное значение данной функции представляет собой 10-мерный вектор чисел. Если нулевая компонента больше остальных девяти, то выходной вектор соответствует цифре 0, если первая больше всех остальных, то цифра 1 и т.д. Обычно используется 60 тысяч изображений и их значений (labels)для аппроксимации такой функции и 10 тысяч для тестирования. Для аппроксимации будем использовать функцию, изображённую на рис. 1.

Входной 784-мерный вектор умножается на матрицу W1 размерности 784*512, далее каждая компонента 512-размерного результата умножения поступает на нелинейную функцию Rectified Linear Unit (ReLU), изображённую на рис.2. Как видно из рисунка если компонента отрицательная, то она превращается в 0, если положительная, то не меняется. Далее преобразованный 512-мерный вектор умножается на матрицу W2 размерности 512*10. Выходной 10-мерный вектор является значением нашей функции. На рис.1 каждый элемент матрицы изображён в виде сегмента, соединяющего каждую строчку с каждым столбцом соответствующей матрицы. Для решения поставленной задачи надо найти все элементы двух матриц, т. е. 784*512 + 512*10 = 40628 элементов (на самом деле надо ещё добавить 512+10 сдвигов, которые для упрощения опускаем).

Как в любой аппроксимационной задаче зададимся критериальной функцией:

Здесь выражение (1) представляет собой сумму ошибок по всем экземплярам изображений цифр. Выражение (2) — ошибка для i-ой цифры, i = 1 … 60000. Если Vi изображение нуля, то pij = (1,0,0,0,0,0,0,0,0,0), p̅ij (Vi,W1,W2) — вычисленное значение нашей аппроксимационной функции, когда на неё подаётся вектор Vi. Значение, например, может быть равно (0.8,0.01,0.01, …,0.1); 10 чисел. Легко показать, что выражение (2) тем меньше, чем ближе вектора pij и p̅ij. Такая критериальная функция называется Categorical Cross-Entropy. Если выходные значения задаются в виде числовых оценок (не дискретный выбор) то используется в качестве критерия метод наименьших квадратов. Теперь мы имеем чётко поставленную задачу. Имеем 60 тысяч векторов Vi и соответствующее множество чисел от 0 до 9. Надо найти такие матрицы W1, W2, чтобы выражение (1) было минимальным.
Процесс оптимизации выражения (1) называется обучением. Обучение (оптимизацию) будем проводить при помощи метода градиентного спуска (ГС) т. е. сначала заполним наши матрицы случайными цифрами, посчитаем выражение (1) найдем градиент, изменим наши матрицы, опять посчитаем и так будем продолжать пока (1) уменьшается. Подробное доступное объяснение ГС дадим в главе 4. В следующей главе рассмотрим простую программу на Python, решающую нашу задачу. Прежде чем переходить к следующей главе имеет смысл отметить две бросающиеся в глаза особенности.
Во-первых, наличие нелинейных элементов на рис 1 (кстати, схемы типа этого рисунка называются нейронными сетями (НС) а матрицы — каскадами). Если бы не было нелинейных элементов, то можно было перемножить матрицы и размерность задачи свелась бы к 784 *10 = 7840. Результат был бы при этом очень плохой. Таким образом нелинейные элементы играют существенную роль. В главе 5 попытаемся объяснить эту роль.
Во-вторых, во входном векторе Vi пиксели можно расположить в любом порядке. Мы не используем, казалось бы, существенную информацию о соседстве и связности пикселей. Тем не менее после обучения наша аппроксимация будет работать лучше, чем средний человек.
- PYTHON ПРОГРАММA
В этой главе рассмотрим программу на языке Python с использованием библиотеки TensorFlow. Язык Python является наиболее популярным для написания программ ИИ. Библиотека TensorFlow наряду с PyTorch, Scikit-learn тоже популярна. На самом деле будем использовать надстройку (wrapping) над TensorFlow называемую Keras.
Сначала загрузим все необходимые массивы:
###############**Loading the MNIST dataset **
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
################
train_images — массив состоящий из 60000 изображений 28* 28
train_labels — соответствующие 60000 цифр от 0 до 9
(test_images, test_labels) — то же самое по 10000 для последующего тестирования
Для иллюстрации напечатаем одну цифру:
################### plot image of first digit
import matplotlib.pyplot as plt
digit = train_images[0]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
########################

Теперь создадим нашу модель из Рис.1
################### creating model architecture
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Dense(512, activation=»relu»,name=’dense_layer_1′),
layers.Dense(10, activation=»softmax»,name=’output_layer’)
])
########################################
Модель состоит из двух каскадов (матриц), выход первого каскада 512-размерный вектор и нелинейная функция «ReLu», выход второго каскада — 10-мерный вектор. Здесь для удобства задаём функцию «softmax», которая превращает выходной вектор в вероятностное распределение, т.е. все 10 значений положительны и сумма равна 1. Так как на вход второго каскада подаётся 512-размерный вектор а выход 10-размерный то матица W1 задана.
Далее компилируем
#####################**The compilation of model**
model.compile(optimizer=»rmsprop»,
loss=»sparse_categorical_crossentropy»,
metrics=[«accuracy»])
#############################
Здесь говорим, что для оптимизации использовать разновидность ГС «rmsprop»,
Функция потерь (loss) совпадает с выражениями (1) (2)
Ещё просим выдавать в процессе обучения процент правильного угадывания цифр (metrics=[«accuracy»]).
Прежде чем приступить к обучению переведём все массивы в одномерные и в форме float32:
##################################
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype(«float32») / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype(«float32») / 255
###################################
Теперь приступаем к обучению:
###################################
history = model.fit(train_images, train_labels, epochs=5, batch_size=128)
###################################
Мы ввели в модель обучаемое множество train_images и его правильные значения train_labels. Так как размерность одного элемента в train_images равен 784, то определилась размерность матрицы W2 — (784 * 512). Параметры epochs=5, batch_size=128 определяют число итераций стохастической оптимизации. Здесь требуется некоторое пояснение. Выражение (1) представляет собой сумму 60000 слагаемых, а производная от суммы равна сумме производных от каждого слагаемого, то для нахождения градиента надо вычислить производные от каждого слагаемого. Каждое слагаемое зависит от (406528 + 5120 + 522) = 412 170 переменных. Всего для одного градиента надо вычислить 412170 * 60000 производных. Оказывается, задачу можно упростить при помощи стохастического градиента. Для многих функций типа (1) можно находить градиент не по всем слагаемым, а брать некоторое достаточное случайное число слагаемых, на следующем шаге оптимизации опять случайное из оставшихся и так повторять пока неисчерпаем всю сумму. Так вот, мы говорим 5 раз пройтись по всей сумме (epochs=5) и в каждой сумме вычислять 128 раз градиент (batch_size=128), т. е. каждый раз мы выбираем 60000/ 128 = 469 слагаемых. Грамотная программа должна проводить итерации до минимума (1), для упрощения мы задали заранее 5*128 = 640 итераций.
ВСЁ, система ИИ создана! После первой итерации мы имеем:
1/469 […………………………] — ETA: 4:15 — loss: 2.3852 — accuracy: 0.0547
Функция (1) равна 2.3852, процент угадывания 5.47.
После последней
469/469 [==============================] — 2s 3ms/step — loss: 0.0376 — accuracy: 0.9888
Функция (1) равна 0.0376 — наш предельный минимум.
Процент угадывания 98.88. Осталось только посмотреть, что происходит на тестовом множестве:
##########################
test_loss, test_acc = model.evaluate(test_images, test_labels)
############################
test_loss = 0.0669, test_acc = 0.9797
- ГРАДИЕНТНЫЙ СПУСК И BACKPROPAGATION
В этой главе объясним, что такое градиент и как он используется для оптимизации. Рассмотрим также очень важный метод нахождения градиента называемый backpropagation. Для упрощения возьмём функцию от двух переменных. Из анализа известна формула:

Из формулы (3) видно, что если мы знаем значение функции и её производных в точке (x0, y0), то можно вычислить (на самом деле приблизительно) значение этой функции в следующей точке (x0 + Δx, y0 + Δy)

Формула (4) верна для любого числа переменных Большие системы ИИ состоят из огромного числа матриц (каскадов). Вернее сказать что каскад может состоять из нескольких матриц, которые иногда умножаются, складываются, объединяются (concatenate). Между каскадами почти всегда находятся нелинейные элементы (activation functions). Иногда многие элементы матриц заполнены нулями, так называемые разреженные матрицы. Все элементы этих матриц являются аргументами критериальной функции типа (1). Таким образом градиент может содержать миллиарды или даже триллионы компонент.
Обучение производится следующим образом. Сначала все матрицы заполняются случайным образом. Берётся случайное число слагаемых в сумме (1) (стохастическая оптимизация) далее для каждого слагаемого известен входной вектор. Он подаётся на нашу НС и вычисляется это слагаемое. После чего вычисляем градиент данного слагаемого и складываем его с накопленным градиентом предыдущих слагаемых (производная от суммы равна сумме производных). Так продолжаем по всей случайной выборке (batch). Теперь мы имеем полный градиент, умножаем его на α, называемое шагом и по формуле (4) находим приращение к каждому элементу всех матриц. После этого всё повторяется. Очень большое значение имеет выбор размера (длины) шага. Выражение (3) предполагает локальную линейность критериальной функции. Если взять большое значение α, то можно проскочить минимум, маленькое значение увеличивает время расчётов, а также может привести к локальному минимуму. Адаптирование шага для задач ИИ является предметом активного исследования. В статье [1] был предложен ставший наиболее популярным метод ADAM, наш параметр optimizer=»rmsprop» для компиляции модели является модификацией ADAM.
Для нахождения градиента (производных по всем элементам матриц) используется так называемый метод backpropagation. Сначала вспомним как находится производная от составной функции. Пусть:

Ясно что каждый последующий каскад является функцией от предыдущего и производные от переменных в i-ом каскаде вычисляется как производная в этом каскаде и умножения на соответствующие производные всех последующих i+1, i+2 … каскадов. Таким образом сначала находятся производные в последнем каскаде, далее в предпоследнем, и они умножаются на производные последнего каскада, далее переходим пред-предпоследнему и т. д. Всё это и есть backpropagation (ВР).
На самом деле вычисления во всех каскадах можно осуществлять параллельно, а потом производить умножения. Кроме того, все вычисления для всех входных данных одной серии (batch) могут проводиться параллельно, так как для одной серии матрицы не меняются (только после всей серии происходит коррекция матриц).
О параллельных вычислениях и их важности поговорим в главе 7.
В завершении этой главы сделаем некоторое лирическое отступление. Как это не кажется странным, но ГС и ВР являются основой всей математики ИИ. Вез ГС мы просто не знаем куда двигаться в гигантском многомерном пространстве. Представьте себе, что вы стоите на перекрёстке миллиарда дорог и совершенно не понятно какую выбрать для дальнейшего движения.
ГС — путеводная звезда, компас удачи (как не вспомнить “Гори, гори моя звезда”).
ВР — единственная возможность вычислить это направление в реальное время.
- ГЕОМЕТРИЧЕСКАЯ ИНТЕПРЕТАЦИЯ ОБУЧЕНИЯ
Для упрощения заменим энтропийный критерий (2) на метод наименьших квадратов:

Критерий (1), (8) обычно используется если оценка не дискретная, а непрерывная, на пример финансовая. Если выход не одномерный, то и как в (2) берётся сумма.
Геометрическую интерпретацию обучения рассмотрим на очень простом двухмерном примере. Сначала введём удобное определение прямой на рис. 4a. Здесь прямая задаётся при помощи нормального вектора W = (w1,w2) и некоторого значения b. Точку на плоскости (X, Y) определяем как вектор, соединяющий начало координат и данную точку. Тогда прямая — это геометрическое место точек проекция которых на W равна b, т. е.
![]()

Прямая А на рис 4а разделяет плоскость на две полуплоскости. Будем называть правой стороной прямой А полуплоскость куда направлен вектор W и соответственно левой другую полуплоскость. Левая часть равенства (9) для всех точек с правой стороны от прямой будет положительной и равной расстоянию от прямой до данной точки, для точек с левой стороны от прямой соответственно отрицательной. Причём абсолютное значение левой части выражения (9) равно расстоянию от точки до прямой.
Рассмотрим простейшую систему ИИ. Пусть нам надо создать НС, на вход которой подаётся два двухмерных вектора (Y, X), т. е. точки О1 и О2 на рис 1b. Если подаётся точка О1, то ИИ выдаёт значение -1, а если точка О2, то +1. НС для такой системы изображена на рис. 5a.

Здесь надо отметить, что матрица каскада имеет дополнительную строчку b — сдвиг, о которой мы раньше не упоминали. Теперь, рассматривая геометрический смысл, это стало необходимым. Кроме того, соответственно необходимо увеличить и размерность входного вектора на единицу. Всё это отражено на рис 5a. Обычно такой же приём используется в механике. Если кто-то знаком с рациональными сплайнами, то там тоже используется подобное расширение матрицы.
B качестве критерия обучения используем формулы (1) и (8). Мы имеем всего две ошибки для точек О1 и О2. Ясно что минимум, равный нулю, мы достигнем на прямой А на рис. 4в. Прямая А (или В) касается две окружности единичного радиуса с центрами в О1 и О2 и проходит так что точка О1 лежит по левую сторону а точка О2 — по правую. Мы имеем даже в таком простом случае два дискретных решения. Посмотрим, как работает градиентный метод. Сначала задаём произвольное положение прямой, далeе изменяя b будем сдвигать прямую пока она не пересечёт точку Р (середина отрезка О1-О2). Одновременно вращаем, изменяя вектор (w1,w2).
Размер и направление сдвига и вращения определяется градиентом и его шагом (4).
Как видно даже в таком простом случае в зависимости от начального положения можно попасть в разные минимумы. В реальном случае столбцы матриц многомерные векторы, и мы будем называть их гиперплоскости. При обучении каждый итерационный шаг осуществляется одновременным сдвигом и поворотом всех гиперплоскостей в направлении градиента причём синхронизирующим фактором является общее единственное значение шага (4). В этом и состоит геометрический смысл обучения.
Теперь посмотрим зачем нам нужны нелинейные элементы. Будем решать ту же самую задачу, но с использованием ReLu. Возможная НС нарисована на рис 5b. Здесь первая матрица имеет два столбца которые соответствуют двум прямым С и D на рис 4с. Оптимум можно достичь если прямая С касается единичной окружности с центром О1 и О1 справа а О2 слева от прямой С и соответственное положение у прямой D. Мы видим положения обоих прямых в минимуме независимо и минимум можно достичь при многих конфигурациях, двигая прямые так чтобы они касались окружностей и сохраняли стороны для точек О1 и О2. Используя нелинейные элементы, мы имеем две полноценные степени свободы в нашем локальном случае, а без нелинейных элементов только две дискретные возможности. В реальном многомерном случае, когда перемещаются все гиперплоскости и оптимизируется общая сумма отдельная гиперплоскость редко достигает своего минимума (её минимум может противоречить общему минимуму). Имея нелинейные элементы и большее число степеней свободы можно достигнуть значительно более глубокого минимума. Алгебраический подход тоже подтверждает, что без нелинейных элементов мы будем иметь значительно меньшее количество степеней свободы так как после умножений и сложений матриц останется одна или несколько матриц (хорошо было бы ввести какую-то формализацию на умножение матриц с промежуточным нелинейным оператором).
Рассмотрим вид нелинейного элемента. Как ни странно, после многих проб и ошибок теперь почти повсеместно используется ReLu (рис. 2). В более ранних моделях была популярна функция релейного типа, изображённая на рис 6.

ГС с такой функцией невозможно осуществить, так как производная везде равна 0.
Используются и другие непрерывные функции (рис 7), но та же проблема — производные на концах исчезают. Пользуясь электрической аналогией функцию ReLu можно назвать диодом — в одну сторону пропускает в другую закрыта.
В завершении скажем, математик заметил бы, что просто линейной функцией нельзя аппроксимировать произвольную функцию, нужны линейные куски а отсюда и промежуточные нелинейности, т. е. мы имеем сплайны первой степени. Всё правильно, но мы предпочитаем своё более интуитивное объяснение.

- ДОСТАТОЧНАЯ СХЕМА В НЕЙРОННОЙ СЕТИ
Пока мы считали, что каскад в НС и матрица синонимы. Теперь начнём уточнять. Каскад может состоять из нескольких матриц, причём они могут складываться умножаться соединяться (concatenate). Матрицы могут быть специальным образом разрежены.
Будем говорить, что некоторый каскад является достаточной схемой (ДС), если при достаточном его размножении, достаточном размере обучаемого множества можно получить достаточно хороший результат. Ясно что такое определение абсолютно не математическое, но вся наука ИИ находится на уровне экспериментального исследования. Появляется много статей и иногда находится ДС в той или иной области. Мы рассмотрим в качестве примера две наиболее удачные ДС — Convolution в области обработки изображений и Attention — в языковых моделях. Рассмотрение будет на принципиальном уровне без многих технических деталей.
Будем использовать общепринятое сокращение CNN для convolution neuron network. Сначала введём понятие блока — эта некое изображение или матрица пикселей. Далее, если ранее мы говорили, что каскад представлен матрицей размерности скажем (512 * 128), то теперь будем говорить что каскад имеет 512 входов и 128 выходов.
На рис. 1 первый каскад имеет 784 входа и 512 выходa. Число обучаемых параметров равно (784 * 512 + 512) (прибавленные 512 — это сдвиги). Таким образом каждому параметру соответствует сегмент на рисунке. Каскад CNN можно изображать также, но теперь каждый вход и выход — это блок, а не одно число. Соединяющий сегмент соответствует фильтру, переводящему входной блок на левом конце сегмента на выходной на правом конце. Всё остальное то же самое выходной блок формируется как сумма по всем входящим сегментам плюс сдвиг, а далее идёт нелинейный элемент. Повторим ещё раз, в обычном каскаде каждый отдельный вход это число, каждый отдельный выход тоже число, каждый сегмент — один оптимизируемый параметр. В каскаде CNN каждый вход — матрица, каждый выход — матрица, каждый сегмент — фильтр, который преобразует входную матрицу в выходную. Число обучаемых параметров равно числу сегментов, умноженное на размер фильтра плюс сдвиги по числу выходных блоков. Обычно фильтр имеет размер 3 * 3 = 9 или 5 * 5 = 25. Обычно размерность блоков (как матрицы) уменьшается oт предыдущего каскада к последующему, а на выходе всей сети имеем вектор результата (размерность 10 в задаче о рукописных цифрах).
Далее мы попробуем объяснить что такое фильтры и придётся немного отойти от нашего обещания что надо знать только производные и матрицы. Фильтр обычно задаётся так называемым окном вокруг пикселя. Если размерность 3*3, то берётся данный пиксель и всё его окружение, т. е. 9 пикселей. Фильтрация изображения заключается в том, что каждый пиксель заменяется некой взвешенной суммой входящих в окно пикселей. Получаемое новое изображение совпадает по размерности с оригинальным. Ясно что при фильтрации фильтры(окна) полностью пересекаются друг с другом (overlapped). Коэффициенты взвешенных сумм и являются параметрами фильтра. Теория фильтрации хорошо развита, её можно использовать для удаления шума, увеличения резкости или наоборот, выделения различных рёбер и т. д. Параметры фильтра можно находить как решение конкретной оптимизационной задачи.
Нам надо рассмотреть некоторые вопросы сжатия изображения. При сжатии (например JPEG) тоже накладываются окна на изображение, но они не пересекаются.
Так в JPEG используется окно 8*8, далее при помощи дискретного преобразования Фурье выделяются амплитуды основных гармоник, и только они запоминается или передаются. Очевидно, что это тоже фильтрация. В CNN осуществляется нечто среднее — окна перекрываются, но не по каждому пикселю, за счёт этого блоки сжимаются. Очевидно, что наибольшее сжатие будет если окна совсем не накладываются друг на друга.
Теперь рассмотрим наш пример c рукописными цифрами только уже с использованием CNN. Для краткости опишем общую схему и результат. Мы использовали 4 каскада.
Вход первого каскада было само изображение рукописной цифры, т. е. блок размера 28*28 и число входов 1, на выходе создали 32 блока размером 26 * 26. Фильтр 3*3=9. Общее число параметров 1 * 32 * 9 + 32 = 320. На втором каскаде вход равен выходу первого каскада, а выход 64 блока размерности 11 * 11, фильтр тот же. Число параметров 32 * 64 * 9 + 64 = 18496. Следующий каскад имел 128 блоков размерности 3 * 3, число параметров 64 * 128 * 9 + 128 = 73856. Последний каскад обычно представляется как полностью заполненная матрица, так как нам надо получить выходной вектор. Мы превращаем 128 входных блоков по 9 чисел каждый в один вектор размерности 128 * 9 и на выходе вектор размерности 10, т.е. число параметров 128 * 9 * 10 + 10 = 11530. Такое преобразование называется flattening.
Как видно число обучаемых параметров значительно меньше чем в первоначальной системе, а вероятность узнавания на тестовых примерах составила 99.1%. Любое улучшение такого результата только вредно, потому что неузнаваемые цифры просто написаны неправильно.
Aвтору удалось решить маленькую но нужную практическую задачу с использованием CNN. Дочь оставляет трёхлетнего внука с нами. Мальчик смышлёный, если его оставить во дворе, то на улицу не уйдёт. Во двор может пройти кошка или собака. Кошка не страшно, а собака опасна. Была разработана система распознающая кошка или собака на изображениях из камер наблюдения и если собака во дворе, то мой компьютер подаёт сигнал тревоги.
Трудно сказать кто первым предложил CNN, существует много обзоров истории CNN.
Можно сделать ссылку, например на review of convolutional neural networks in computer vision [2]. Там же можно найти другое более подробное объяснение работы CNN.
Теперь перейдём к Attention механизму (АМ). Сначала разберёмся что такое еmbedding (EM). Текст в языковых моделях подаётся в виде последовательности токенов. Токен это слово, фраза, знак препинания или даже отдельный слог. Проще всего закодировать каждый токен своим числом, например порядком расположения в словаре. Это не работает, так как мы сразу задаём иерархию или порядок слов. Так, например, стул будет больше стола так как он стоит в словаре позже. Поэтому вводится так называемая One-hot coding (OHC). Каждый токен является вектором размерности равной размеру входного словаря. Во всех компонентах вектора стоит 0 и только позиция, равная позиции данного слова в словаре, равна единице. Таким образом скалярное произведение любых двух токенов (слов) равно 0. Скалярное произведение нормальных векторов по смыслу очень близко к корреляции. Будем говорить OHC не имеет корреляции. На рис.8 дано упрощённое изображение первого каскада EM. Легко понять, что каждому токену будет соответствовать только одно выходное слово. Это слово и есть EM. На этом рисунке новая размерность слова равна 3. На самом деле размерность может быть десятки тысяч, но всё равно значительно меньше размерности OHC. Токены при кодировании EM уже имеют корреляцию. Такая корреляция часто объясняется смысловой близостью слов. Если слова близки, то их векторы EM почти параллельны. Разности между словами тоже приобретают смысловое объяснение. Рис. 9 является иллюстрацией подобного объяснения. В настоящее время созданы большие базы данных, в которых хранится ЕМ кодировка слов. Они используются в ИИ, а также для поиска слов по их семантической близости.
Перейдём к АМ. Впервые описание АМ было дано в статье [3] и это был гигантский прорыв в развитии языковых ИИ.

В статье рассматривалось применение АМ к переводу с английского на французский, поэтому там вводится два понятия — self-attention и cross-attention. Мы будем рассматривать self-attention и будем использовать наше сокращение АМ. В конце кратко объясним разницу. АМ является каскадом в нейронной сети, на вход которой подаётся некая матрица, представляющая собой входное предложение (предложение может быть в несколько страниц). На выходе такая же матрица только уже перекодированная. Разобьём наш разбор на 3 этапа. На рис.10 изображён первый этап AМ. На вход подаётся входная матрица. Её размерность — размер входного предложения на размерность токенов после ЕМ. На рис 10 размер предложения 5, размерность токена 512. Обычно размер входного предложения фиксированный и неиспользуемые элементы заполняются специальными знаками (padding). Даже в ChatGPT2 максимальный размер предложения был 1012.


Ha рис 10 (слева на право) входная матрица размерности (5 * 512) умножается на 3 обучаемые матрицы. Они называются (сверху вниз) Query, Key, Value размерности (512 * 128). В результате умножения получаем три матрицы Q, K, V. Их размерности (5 * 128). Проверяем (5 * 512) * (512 * 128) = (5 * 128). Матрицы Q, K, V являются перекодированными входными матрицами только с размерностью токена 128.
Переходим к рис. 11.

На рис.11 матрица Q умножается на трансформированную матрицу K и получаем квадратную корреляционную матрицу Attention (A). Oнa чёрно-белая на рисунке.
Размерность матрицы А равна (5 * 128) * (128 * 5) = (5 * 5). Maтрица А получается в результате скалярного умножения каждого слова на каждое в предложении и поэтому она показывает зависимость между словами в предложении. Далее мы перемножаем матрицу А на матрицу V и получаем выходную матрицу С (зелёная) размерности (5 * 5) * (5 * 128) = (5 * 128). В этой матрице уже кодирование каждого слова учитывает смысл и важность слова непосредственно в данном предложении.
В нашем примере используется предложение «John recently bought Apple mobile». Слово «Apple» в первоначальном ЕМ может иметь значение фрукт, а после обработки в АМ превращается в мобильный телефон. На рис.12 изображена последняя стадия ЕМ. Обычно используется достаточно большое количество блоков AМ, работающих параллельно в одном каскаде. Кроме того, в языковых ИИ может быть несколько каскадов AМ. На рис. 12 обучаемые матрицы представлены в нашем обычном виде, каждая строка соединена с каждым столбцом отрезком и этому отрезку соответствует оптимизируемый параметр.

На рис. 12 мы видим 4 независимых блока AМ, называемые heads. Все 4 выходные матрицы ЕМ объединяются (concatenate) в oдну общую выходную данного каскада. Размерность входной и выходной матрицы обычно совпадают. Пoэтому выполняется соотношение:

В наши планы не входит подробное описание процесса обучения языковых ИИ. Мы формально указываем на матричные преобразования и скрупулёзно следим за размерностями. Проверка размерностей всегда является ключевым фактором понимания.
Отметим только, что при заданном входном предложении находится на выходе всей сети новое продолжающее это предложение слово. Далее оно добавляется к входному предложению и процесс повторяется. В качестве критерия при выборе нового слова используется функция (1), (2) при этом желаемое распределение уже не дискретное. Размерность его равна размерности словаря и наиболее подходящие слова имеют большие вероятности. В таблице 1 приводим характеристики разных модификаций GPT-3. B нижней строчке данные по наибольшей модели. Она содержит 175 миллиардов параметров (коэффициентов матриц), 96 каскадов (layers), размерность токена — 12288, число блоков АМ (heads) — 96, размерность токена в блоке равна 128 (128 * 96 = 12288), batch size равен 3.2 миллиона (наш размер в главе 3 был 128)

Рисунки 10–12 взяты из учебного ролика [4]. Таблица 1 приводится в статье [5].
Как мы обещали, приведём объяснение разницы между self-attention и cross-attention. Пока мы имели дело только с self-attention. При cross-attention матрица Query умножается на другое входное предложение (матрицу). Естественно, в этом случае матрица А будет представлять матрицу кросс-корреляции между словами двух различных предложений. Cross-attention используется при переводе с одного языка в другой. При этом на матрицу Query поступает предложение на языке, с которого мы переводим.
В этой статье мы описываем только принципиальный математический аппарат ИИ и не можем входить в детали работы языковой модели. Для более углублённого понимания работы языковой модели ИИ мы рекомендуем ролик [6]. В этом видео автор создаёт мелкомасштабную модель GPT-2. В качестве обучающего множества используются все тексты Шекспира. В качестве словаря токенов (внимание !!) используется 65 букв, больших и малых и знаки препинания. Наиболее важным токеном является просто пробел. В результате тренировки автор добивается того, что модель начинает выдавать слова и фразы в стиле Шекспира, т. е. здесь явно находятся корреляции между буквами в текстах Шекспира. Вот тебе и все смыслы и зависимости между словами! В ролике даются ссылки на весь созданный код. Можно загрузить на обычный игровой лэптоп и прокрутить самому.
- ПРИМЕНЕНИЕ ПАРАЛЛЕЛЬНЫХ АЛГОРИТМОВ В ИИ И ДРУГИХ ОБЛАСТЯХ
С начала предыдущего десятилетия резко увеличилась доля использования графических процессоров (GPU) в обычных программных приложениях. Мы не будем вдаваться в историю GPU, их архитектуру, языки программирования. Кратко отметим только математическую особенность, которая сделала GPU главным инструментом прорыва в области ИИ. При последовательных вычислениях (ПВ) быстродействие определяется суммой всех операций. При таком подходе для сложных случаев (сингулярностей) можно уделить больше времени, так как такие случаи редки. При ПО алгоритм разбивается на отдельные мелкие процессы, выполняемые как можно независимо. Общее время теперь определяется уже самым медленным процессом. Здесь удачно сравнение — скорость эскадры определяется скоростью самого медленного корабля. Таким образом искусство разработки ПО состоит в нахождении как можно одинаковых независимых операций, решающих поставленную задачу. Матричные операции, которые доминируют в ИИ, удачно приспособлены к ПО. Поэтому автор решил поделиться своим личным опытом применения GPU в, казалось бы, совсем богом забытой области — обработке металлов на фрезерных, токарных станках и 3Д принтерах.
Моделирование обработки детали на фрезерном станке. Программист CNC (computer numerical controller) сначала создаёт программу обработки детали с помощью системы CAD/CAM (computer aided design/computer aided manufacturing). Далее эта программа проверяется на специальной системе моделирования (СМ) на компьютере. CNC программист может видеть на экране процесс резки в реальном времени, может прервать моделирование и перейти к значительно более поздней операции и при этом заготовка будет уже иметь соответствующий вид, может разрезать заготовку любой плоскостью и посмотреть что внутри. При моделировании собирается много полезной информации — динамика инструмента, износ, зарезы, напуски. При большом количестве операций и сложных деталях скорость вычислений моделирования на CPU может не удовлетворять требованиям реального времени. Был разработан алгоритм моделирования на GPU. На рис. 13 показан блок двигателя после многих фрезерных операций.
Параметрическая операция. Поверхности механических деталей задаются в виде функций двух переменных u, v, называемых параметрами. Если u = const., то изменяя v мы получим параметрическую линию (например, меридианы или параллели). Если инструмент движется вдоль параметрической линии при определённом значении u, а потом увеличиваем u на заданную величину, называемую шагом, то такая стратегия обычно приводит к наилучшей обработке, так как шаг задаётся непосредственно по длине поверхности. К сожалению, часто необходимая область для обработки содержит много поверхностей. Поверхности на стыках имеют разные направления параметрических линий и разный масштаб и в таком случае параметрическая операция невозможна. Возникла идея соединить все поверхности определённой области в одну поверхность. Помимо математической сложности задача имеет большую размерность. Одна поверхность обычно сплайн, содержащий несколько сотен двухмерных полиномов. Область может содержать несколько сотен поверхностей. Использование GPU помогло решать данную задачу в реальном масштабе времени. На рис. 14 изображена головка бура и канал (засветлённая область) должен обрабатываться одной операцией. На рис.15 изображена полученная поверхность с её параметрическими линиями (зелёный цвет). На рис. 16 — моделирование полученной 5-осевой операции.




Профиль для токарной обработки. Обычно многие детали сначала обрабатываются на токарных станках, а потом уже на других. Таким образом, необходимо найти профиль для токарной обработки. Токарная обработка имеет очень высокую точность порядка 0.001 мм. Геометрия должна быть на порядок точнее. Данную задачу также удалось решить на GPU. На рис. 17 оранжевая кривая является профилем.
Создание текстуры на поверхности детали. Этот проект разрабатывался во время ковида (мой последний проект перед выходом на пенсию). Накладывание текстуры на определённую область детали необходимо иногда из эстетических соображений, иногда поверхность требует определённой шероховатости, иногда это просто единичная выпуклая эмблема. Очень часто нужно нанести некий выпуклый рельеф на штампе для последующего производства пластмассовых, бумажных или стеклянных изделий. Наша цель была упростить и ускорить проектирование таких деталей, а также сделать возможным то, что раньше было практически недоступно. Демо можно посмотреть на видео [7]. Здесь решались сразу 3 достаточно непростые математические задачи. Надо нанести некое изображение на сложную поверхность (иногда даже с острыми гранями) с минимальными искажениями, т. е. создавалось некое взаимно-однозначное отображение плоскость — поверхность как можно близкое к конформному. В этой задаче удалось использовать GPU. Вторая задача состояла в плотной упаковке копий изображения внутри сложного контура на плоскости. Здесь быстрого решения не нашлось. Последний этап состоял в создании выпуклого рельефа на поверхности. Эта последняя задача тоже была выполнена на GPU. Все вычисления на демо [7] идут в реальном масштабе времени. На рис. 18 изображена деталь с текстурой.


ЗАКЛЮЧЕНИЕ
В этой статье мы постарались дать максимально упрощённое описание ИИ. Просто, но не настолько чтобы выплеснуть ребёнка вместе с мутной водой. Статья является учебной, но приводимое объяснение необходимости нелинейных элементов не встречалось автором, также мы имеем некоторый свой взгляд на convolution механизм.
Надо сказать, что ИИ в настоящее время ещё является некой экспериментальной наукой. В предстоящей теории необходимо ответить, что такое достаточная схема, что такое её достаточное тиражирование, какое множество достаточно для обучения и что значит достаточный результат. Пока всё это решается эвристически.
Выражаю благодарность Евгению Михайловичу Берковичу за его настоятельную просьбу представить данные рассуждения в письменном виде.
Завершающий сентиментальный аккорд. История ИИ представляет собой непрерывный поиск вершин там, где их никто не ожидал, и позвольте кончить фотографией меня и жены. Мы находимся в верхней точке линии водораздела Северной Америки в Скалистых горах. Впереди все реки текут в Тихий океан, за нами двигаются к Атлантическому, а мы в состоянии неописуемого восторга от пронизывающего ветра и бескрайних просторов.

Литература
- Diederik P., Kingma Jimmy Lei Ba, ADAM: A METHOD FOR STOCHASTIC OPTIMIZATION
- https://link.springer.com/article/10.1007/s10462-024-10721-6
- Ashish Vaswani, at al. Attention Is All You Need
- https://www.youtube.com/watch?v=KMHkbXzHn7s&t=305s
- Tom B. Brown, at al. Language Models are Few-Shot Learners
- https://www.youtube.com/watch?v=kCc8FmEb1nY&t=1464s
- https://www.youtube.com/watch?v=6gFOYyZew24&t=2s
![]()

