AI для PHP-разработчиков. Часть 8: Свёрточные нейронные сети: ищем границы на изображениях с помощью чистого PHP

Часть 7: Экосистема AI-агентов в PHP – от вызовов OpenAI до мультиагентных платформ
Часть 6: Bag of Words и TF–IDF – как компьютер превращает текст в математику
Часть 5: От массивов к GPU: как PHP-экосистема приходит к настоящему ML
Часть 4: Практическое использование TransformersPHP
Часть 3: Практика без Python и data science
Часть 2: Собираем простейшую RAG-систему на PHP с Neuron AI за вечер
Часть 1: Как я пытался подружить PHP с NER – драма в 5 актах
Введение
В предыдущих статьях серии мы разбирались, как компьютер работает с текстом: превращает слова в числовые представления, вычисляет сходство между документами и извлекает полезную информацию из текстовых данных.
Но что насчёт изображений?
Компьютер не видит фотографию так, как её видит человек. Для него изображение – это набор чисел, описывающих яркость и цвет отдельных пикселей. И чтобы научиться распознавать объекты, находить границы или определять визуальные признаки, нужно научиться работать с этими числами.
Для решения таких задач используются свёрточные нейронные сети (Convolutional Neural Networks, CNN). Они широко применяются в компьютерном зрении – от распознавания объектов до анализа медицинских изображений.
Одна из основных операций таких сетей – свёртка (convolution). С её помощью сеть анализирует небольшие участки изображения и обнаруживает локальные признаки: границы, линии, текстуры и другие структуры.
Но как именно это работает?
В этой статье мы разберём механику свёртки и реализуем её самостоятельно на чистом PHP, без сторонних библиотек и готовых ML-алгоритмов.
Возьмём небольшое изображение в виде двумерной матрицы, создадим фильтр размером 3 × 3 и научимся находить с его помощью вертикальные границы. Затем изменим фильтр, проведём несколько экспериментов и посмотрим, как меняются результаты (все примеры кода в этой статье даны для PHP 8.1 или старше).
Наша цель – не построить полноценную нейронную сеть, а разобраться в одной из операций, которая лежит в основе CNN, и понять, что происходит внутри свёрточного слоя.
1. Как компьютер видит изображение
Когда мы смотрим на фотографию, мы видим объекты, формы, линии и цвета. Компьютер же работает с числами.
Любое цифровое изображение состоит из небольших элементов – пикселей (pixels). Каждый пиксель содержит информацию о цвете и яркости.
Например, в чёрно-белом изображении значение пикселя обычно находится в диапазоне от 0 до 255:
0– чёрный цвет;255– белый цвет;значения между ними – различные оттенки серого.
Таким образом, небольшое изображение можно представить в виде двумерной матрицы чисел.
Например:
В этом примере левая часть изображения тёмная, а правая – светлая.
Если представить эту матрицу визуально, получится простое изображение с вертикальной границей между двумя областями.

Теперь представим, что нам нужно найти границу между тёмной и светлой областями.
Для человека это очевидно: достаточно посмотреть на изображение. Но компьютер должен выполнить определённые вычисления, чтобы обнаружить такое изменение яркости.
Один из способов решить эту задачу – использовать небольшую матрицу весов, которую называют ядром свёртки (kernel).
Она перемещается по изображению, анализирует небольшие участки пикселей и вычисляет, насколько сильно они отличаются друг от друга.
Именно этот механизм мы рассмотрим дальше.
2. Что такое свёртка (Convolution)
Свёртка – это операция, при которой небольшая матрица весов перемещается по входной матрице. В каждой позиции соответствующие элементы двух матриц перемножаются, после чего результаты складываются.
Матрица весов называется ядром свёртки (kernel), а результат применения ядра ко всем допустимым позициям входа – картой признаков (feature map).
Давайте разберём, как это работает на практике.
Ядро свёртки
Предположим, что у нас есть изображение, представленное матрицей чисел. Чтобы найти на нём вертикальные границы, воспользуемся фильтром размером 3 × 3:
Отрицательные веса находятся слева, положительные – справа.
Такое расположение не случайно. Фильтр сравнивает яркость левой и правой частей небольшого участка изображения. Если значения справа заметно отличаются от значений слева, результат вычисления будет большим по абсолютной величине.
Если же обе части имеют примерно одинаковую яркость, положительные и отрицательные слагаемые будут компенсировать друг друга.
Скользящее окно (Sliding Window)
Теперь представим, что мы накладываем наше ядро на изображение.
Фильтр охватывает участок размером 3 × 3 и выполняет вычисление. Затем перемещается на одну позицию вправо и повторяет операцию.
Когда достигает правого края, переходит на следующую строку.
Таким образом фильтр последовательно обрабатывает все допустимые участки изображения.
Каждое вычисление даёт одно число. Собрав все полученные значения, мы получим новую матрицу – карту признаков (Feature Map).

Посмотрим на одно вычисление
Возьмём небольшой участок изображения:
И применим к нему наше ядро:
Перемножим элементы, расположенные на одинаковых позициях, и сложим результаты:
Получаем:
Результат равен 60.
Это число становится одним элементом выходной карты признаков. Затем фильтр перемещается на следующую позицию, и вычисление повторяется.
Свёртка или Cross-Correlation?
Здесь есть небольшая техническая особенность.
В математике операция свёртки предполагает, что ядро предварительно переворачивается на 180 градусов. Однако в большинстве реализаций свёрточных слоёв нейронных сетей используется другая операция – cross-correlation, при которой ядро применяется без переворота.
Именно такой вариант мы будем использовать в нашей PHP-программе.
В контексте глубокого обучения эту операцию обычно тоже называют свёрткой (convolution).
Что мы получаем?
После того как фильтр обработает всё изображение, мы получим новую матрицу – Feature Map.
Она показывает, насколько сильно выбранный фильтр реагирует на разные участки изображения.
Большие положительные или отрицательные значения указывают на сильный отклик фильтра, а значения, близкие к нулю, – на отсутствие выраженного признака, который он ищет.
Теперь, когда мы разобрались с принципом работы свёртки, можно перейти к реализации. Попробуем написать эту операцию самостоятельно на PHP и проверить, действительно ли наш фильтр способен находить вертикальные границы.
3. Реализуем свёртку на чистом PHP
Теперь, когда мы разобрались с принципом работы свёртки, попробуем реализовать её самостоятельно.
Для этого нам не понадобятся сторонние библиотеки, готовые ML-алгоритмы или специализированные инструменты для обработки изображений. Достаточно обычного PHP и нескольких вложенных циклов.
Подготовим входные данные
Для начала создадим небольшое изображение размером 5 × 5. Как и раньше, будем представлять его в виде двумерного массива чисел.
Левая часть изображения будет тёмной, а правая – светлой:
Между третьим и четвёртым столбцами находится вертикальная граница. Именно её мы хотим обнаружить.
Теперь определим ядро свёртки:
Отрицательные веса слева и положительные справа позволяют фильтру реагировать на разницу яркости между левой и правой частями обрабатываемого участка.
В нашей реализации будем использовать следующие настройки:
stride = 1– фильтр перемещается на один пиксель за раз;padding = 0– дополнительные пиксели по краям не добавляются;ядро не переворачивается;
значения результата не ограничиваются диапазоном от 0 до 255.
Последний пункт особенно важен. Значения Feature Map – это результаты математических вычислений, а не исходные значения пикселей. Поэтому они могут быть отрицательными или превышать 255.
Пишем функцию convolve()
Создадим файл convolution.php и реализуем функцию convolve().
Она будет принимать две двумерные матрицы: входные данные и ядро свёртки. На выходе мы получим новую матрицу – карту признаков.
Для начала сделаем реализацию универсальной: она будет поддерживать прямоугольные матрицы и ядра произвольного размера.
/**
* Apply a convolution-style filter to a 2D matrix.
*
* This implementation uses cross-correlation:
* the kernel is not flipped.
*
* @param array<array<int|float>> $input
* @param array<array<int|float>> $kernel
* @return array<array<int|float>>
*/
function convolve(array $input, array $kernel): array
{
if (!array_is_list($input) || !array_is_list($kernel)) {
throw new InvalidArgumentException(
'Input matrix and kernel must use sequential numeric indexes.'
);
}
$inputHeight = count($input);
$inputWidth = count($input[0] ?? []);
$kernelHeight = count($kernel);
$kernelWidth = count($kernel[0] ?? []);
if ($inputHeight === 0 || $inputWidth === 0) {
throw new InvalidArgumentException('Input matrix must not be empty.');
}
if ($kernelHeight === 0 || $kernelWidth === 0) {
throw new InvalidArgumentException('Kernel must not be empty.');
}
foreach ($input as $row) {
if (!array_is_list($row) || count($row) !== $inputWidth) {
throw new InvalidArgumentException(
'Input matrix must be rectangular.'
);
}
}
foreach ($kernel as $row) {
if (!array_is_list($row) || count($row) !== $kernelWidth) {
throw new InvalidArgumentException(
'Kernel must be rectangular.'
);
}
}
if ($kernelHeight > $inputHeight || $kernelWidth > $inputWidth) {
throw new InvalidArgumentException(
'Kernel must fit inside the input matrix.'
);
}
$outputHeight = $inputHeight - $kernelHeight + 1;
$outputWidth = $inputWidth - $kernelWidth + 1;
$output = [];
for ($y = 0; $y < $outputHeight; $y++) {
$outputRow = [];
for ($x = 0; $x < $outputWidth; $x++) {
$sum = 0;
for ($ky = 0; $ky < $kernelHeight; $ky++) {
for ($kx = 0; $kx < $kernelWidth; $kx++) {
$pixel = $input[$y + $ky][$x + $kx];
$weight = $kernel[$ky][$kx];
$sum += $pixel * $weight;
}
}
$outputRow[] = $sum;
}
$output[] = $outputRow;
}
return $output;
}
/**
* Print a matrix in a readable format.
*/
function printMatrix(array $matrix): void
{
foreach ($matrix as $row) {
echo implode("\t", array_map(
static fn (int|float $value): string => (string) $value,
$row
)) . "\n";
}
}Теперь добавим исходное изображение и ядро:
$image = [
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
[10, 10, 10, 200, 200],
];
$verticalEdgeKernel = [
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1],
];
echo "Input image:\n";
printMatrix($image);
echo "\nVertical edge kernel:\n";
printMatrix($verticalEdgeKernel);
echo "\nFeature map:\n";
$featureMap = convolve($image, $verticalEdgeKernel);
printMatrix($featureMap);Разберём, как работает функция
Теперь посмотрим на основные части реализации.
1. Вычисляем размер выходной матрицы
Поскольку мы не используем padding, фильтр может обрабатывать только те участки, которые полностью помещаются внутри исходного изображения.
Поэтому размеры результата определяются формулами:
Здесь:
(
и (
) – ширина и высота входной матрицы;
(
) и (
) – ширина и высота ядра.
В нашем примере входная матрица имеет размер 5 × 5, а ядро – 3 × 3.
Следовательно:
Результирующая матрица будет иметь размер 3 × 3.
2. Перемещаем фильтр по изображению
За это отвечают два внешних цикла:
for ($y = 0; $y < $outputHeight; $y++) {
for ($x = 0; $x < $outputWidth; $x++) {
// Process current image region
}
}Переменная $y определяет строку, а $x – столбец, в котором находится левый верхний угол фильтра.
На каждой позиции ядро обрабатывает участок изображения размером 3 × 3.
3. Перемножаем соответствующие элементы
Внутри внешних циклов находятся ещё два цикла:
for ($ky = 0; $ky < $kernelHeight; $ky++) {
for ($kx = 0; $kx < $kernelWidth; $kx++) {
$pixel = $input[$y + $ky][$x + $kx];
$weight = $kernel[$ky][$kx];
$sum += $pixel * $weight;
}
}Здесь происходит основная работа.
Мы берём очередной пиксель из текущего участка изображения, умножаем его на соответствующий вес ядра и прибавляем результат к переменной $sum.
После обработки всех элементов ядра в $sum находится итоговое значение для текущей позиции фильтра.
4. Сохраняем результат
Когда обработка текущего участка завершена, добавляем полученное значение в выходную строку:
$outputRow[] = $sum;После обработки всей строки добавляем её в результирующую матрицу:
$output[] = $outputRow;Когда фильтр обработает все допустимые позиции, функция вернёт готовую Feature Map.
Таким образом, вся операция свёртки реализована с помощью четырёх вложенных циклов: два отвечают за перемещение фильтра, а ещё два – за вычисления внутри текущего участка изображения.
4. Запускаем программу и анализируем результат
Функция convolve() готова. Теперь запустим программу и посмотрим, какую карту признаков она построит для нашего изображения.
Выполним команду:
php convolution.phpПолучим следующий результат:
Input image:
10 10 10 200 200
10 10 10 200 200
10 10 10 200 200
10 10 10 200 200
10 10 10 200 200
Vertical edge kernel:
-1 0 1
-1 0 1
-1 0 1
Feature map:
0 570 570
0 570 570
0 570 570В результате вместо исходной матрицы размером 5 × 5 мы получили новую матрицу размером 3 × 3.
Обратите внимание: первая колонка карты признаков содержит нули, а две следующие – большие положительные значения.
Это именно то поведение, которого мы ожидали от выбранного фильтра.
Но почему получилась именно такая карта признаков? Давайте разберём несколько позиций фильтра вручную.
Позиция 1. Однородная тёмная область
Начнём с первого участка изображения:
Применим к нему наше ядро:
Вычислим результат:
Все слагаемые взаимно компенсируются:
Фильтр не обнаруживает изменений яркости слева направо, поэтому результат равен нулю.
Позиция 2. Переход от тёмной области к светлой
Теперь переместим фильтр вправо. Он захватит участок:
Для каждой строки вычисление выглядит одинаково:
Поскольку в фильтре три одинаковые строки, складываем три результата:
Получаем:
Фильтр обнаруживает значительное изменение яркости слева направо.
Позиция 3. Следующий участок с переходом яркости
Переместим фильтр ещё на одну позицию вправо:
Для каждой строки:
Итоговое значение:
Результат снова равен 570.
Почему одна граница даёт два отклика?
Здесь есть интересный момент.
Может показаться, что два положительных значения в карте признаков означают наличие двух отдельных границ. Но это не так.
Оба результата возникают из-за одного и того же перехода между тёмной и светлой областями.
Дело в том, что фильтр реагирует на разницу между левым и правым столбцами своего окна. Поэтому сильный отклик сохраняется в двух соседних позициях: в обеих случаях окно захватывает пиксели из тёмной и светлой областей.
Это нормальное поведение выбранного ядра, а не ошибка реализации.
Таким образом, мы не просто получили новую матрицу чисел. Мы увидели, как фильтр реагирует на определённую структуру изображения и преобразует её в карту признаков.
В следующем эксперименте попробуем изменить ядро и посмотрим, как это повлияет на результат.
5. Экспериментируем с фильтрами
До этого момента мы использовали один фильтр, который обнаруживает изменения яркости слева направо. Но что произойдёт, если изменить его веса?
Давайте проведём несколько экспериментов на том же изображении.
5.1. Ищем горизонтальные границы
В предыдущем примере наше ядро реагировало на изменения яркости слева направо.
Теперь попробуем обнаруживать изменения сверху вниз.
Для этого изменим расположение весов:
Отрицательные веса находятся в верхней части ядра, а положительные – в нижней.
Теперь фильтр сравнивает верхнюю и нижнюю части каждого участка изображения.
Добавим новое ядро в программу:
$horizontalEdgeKernel = [
[-1, -1, -1],
[ 0, 0, 0],
[ 1, 1, 1],
];
$featureMap = convolve($image, $horizontalEdgeKernel);
echo "Horizontal edge feature map:\n";
printMatrix($featureMap);Запустим программу.
Результат:
0 0 0
0 0 0
0 0 0Почему все значения равны нулю?
Посмотрим на наше исходное изображение. Все его строки одинаковые: сверху вниз яркость не меняется.
Поэтому верхняя и нижняя части каждого участка содержат одинаковые значения. Положительные и отрицательные слагаемые взаимно компенсируются.
Это означает, что выбранный фильтр не обнаружил изменений яркости сверху вниз.
5.2. Изменяем направление фильтра
Вернёмся к поиску вертикальных границ.
В исходном ядре отрицательные веса находились слева, а положительные – справа:
Теперь поменяем знаки всех весов:
В PHP это выглядит так:
$reverseVerticalKernel = [
[ 1, 0, -1],
[ 1, 0, -1],
[ 1, 0, -1],
];
$featureMap = convolve($image, $reverseVerticalKernel);
echo "Reverse vertical edge feature map:\n";
printMatrix($featureMap);Теперь результат будет другим:
0 -570 -570
0 -570 -570
0 -570 -570Обратите внимание: абсолютные значения остались прежними, но знак изменился.
Почему?
Потому что теперь положительные веса находятся слева, а отрицательные – справа.
Таким образом, фильтр реагирует не просто на наличие границы, а также на направление изменения яркости.
В нашем примере:
положительный результат соответствует переходу от тёмной области к светлой слева направо;
отрицательный результат соответствует переходу от светлой области к тёмной слева направо.
Если нас интересует сила отклика независимо от направления, можно использовать абсолютное значение результата.
5.3. Что произойдёт, если уменьшить контраст?
Теперь проведём ещё один эксперимент.
До этого яркость тёмной области составляла 10, а светлой – 200.
Разница между ними была:
Попробуем уменьшить контраст изображения. Для этого заменим значения светлых пикселей с 200 на 100:
$image = [
[10, 10, 10, 100, 100],
[10, 10, 10, 100, 100],
[10, 10, 10, 100, 100],
[10, 10, 10, 100, 100],
[10, 10, 10, 100, 100],
];
$featureMap = convolve($image, $verticalEdgeKernel);
echo "Feature map with lower contrast:\n";
printMatrix($featureMap);Теперь разница яркости составляет:
Посмотрим на результат:
0 270 270
0 270 270
0 270 270Отклик уменьшился с 570 до 270.
Это ожидаемо: фильтр вычисляет взвешенную сумму значений пикселей. Когда разница между тёмной и светлой областями становится меньше, уменьшается и результат вычисления.
Таким образом, мы видим, что величина отклика зависит не только от расположения границы, но и от контраста между соседними областями.
Что показали наши эксперименты?
Мы использовали одно и то же изображение, но меняли ядра и значения пикселей.
В результате увидели несколько важных особенностей:
Разные фильтры реагируют на разные направления изменения яркости.
Изменение знаков весов меняет знак отклика.
Уменьшение контраста приводит к уменьшению абсолютной величины отклика.
Один и тот же фильтр может давать сильный отклик в нескольких соседних позициях.
Именно поэтому в свёрточных нейронных сетях используется множество фильтров. Каждый из них может реагировать на определённые особенности входного изображения.
Но в нашем примере все веса заданы вручную. В настоящей CNN сеть учится подбирать их самостоятельно в процессе обучения.
Давайте разберёмся, как наша реализация связана с работой свёрточных нейронных сетей.
6. Как это связано со свёрточными нейронными сетями?
На первый взгляд может показаться, что мы просто написали небольшой алгоритм обработки изображений. Но именно операция, которую мы реализовали, лежит в основе свёрточных слоёв CNN.
Разница заключается в том, откуда берутся веса фильтров.
В нашей программе мы задали ядро вручную:
$verticalEdgeKernel = [
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1],
];Мы заранее знали, какой признак хотим обнаружить, и самостоятельно подобрали подходящие значения.
В свёрточной нейронной сети всё происходит иначе.
Вместо одного заранее определённого фильтра сеть использует множество фильтров. Каждый из них имеет собственный набор весов и формирует свою карту признаков.
В процессе обучения значения этих весов корректируются так, чтобы сеть могла лучше решать поставленную задачу.
Например, один фильтр может научиться реагировать на вертикальные границы, другой – на горизонтальные, третий – на определённые текстуры или другие локальные структуры.
При этом нам не нужно заранее объяснять сети, какие именно признаки следует искать. Она учится находить полезные закономерности на основе обучающих данных.
Что происходит внутри свёрточного слоя?
Упрощённо процесс можно представить следующим образом:
На вход поступает изображение.
Свёрточный слой применяет к нему несколько фильтров.
Каждый фильтр формирует собственную карту признаков (Feature Map).
В процессе обучения сеть корректирует веса фильтров, уменьшая ошибку предсказания.
Несколько свёрточных слоёв могут последовательно извлекать всё более сложные признаки.
Например, первые слои могут реагировать на простые структуры: границы, линии и текстуры. Более глубокие слои могут объединять эти признаки в более сложные визуальные представления.

Почему это работает эффективнее полносвязных слоёв?
Одна из важных особенностей CNN – повторное использование одних и тех же весов фильтра на разных участках изображения. Этот принцип называется Weight Sharing (разделение весов).
Вместо того чтобы создавать отдельные веса для каждого пикселя и каждой позиции, сеть применяет одно и то же ядро ко всему изображению.
Это позволяет значительно сократить количество обучаемых параметров и использовать локальные зависимости между соседними пикселями.
Именно поэтому свёрточные сети хорошо подходят для работы с изображениями.
Что мы реализовали на самом деле?
Важно понимать разницу между нашим примером и полноценной CNN.
Мы реализовали саму операцию cross-correlation, которая используется внутри свёрточного слоя. Но мы не обучали фильтры, не применяли функцию активации и не строили последовательность слоёв.
Тем не менее теперь мы понимаем один из основных механизмов CNN не только на уровне теории, но и на уровне кода.
Мы увидели, как небольшое ядро перемещается по изображению, вычисляет локальные признаки и преобразует входную матрицу в карту признаков.
Это и есть основа работы свёрточного слоя.
7. Ограничения нашей реализации
Мы реализовали свёртку на чистом PHP и увидели, как с помощью небольшого фильтра можно обнаружить вертикальную границу между тёмной и светлой областями.
Но важно понимать: это учебный пример, который демонстрирует только одну из операций, используемых в свёрточных нейронных сетях. У него есть несколько ограничений.
1. Фильтр задан вручную
Мы сами определили веса ядра:
$verticalEdgeKernel = [
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1],
];В настоящей CNN фильтры не задаются разработчиком вручную. Их веса подбираются в процессе обучения на примерах данных.
2. Используется фиксированный шаг перемещения
В нашей реализации фильтр каждый раз сдвигается на один пиксель (stride = 1). Другие варианты шага мы не рассматриваем.
3. Не используется Padding
Фильтр обрабатывает только те участки, которые полностью помещаются во входную матрицу. Поэтому размер Feature Map получается меньше размера исходного изображения.
4. Нет дополнительных операций нейронной сети
Наша функция выполняет только умножение элементов матрицы на веса ядра и суммирование результатов. Мы не применяем функцию активации, нормализацию или другие операции, которые могут входить в состав свёрточного слоя.
5. Работаем с одной матрицей яркости
В примере каждый пиксель представлен одним числом. Реальные цветные изображения обычно содержат несколько каналов, например RGB. В таком случае свёрточный слой учитывает все каналы при вычислении отклика фильтра.
6. Используется один фильтр
Мы создали только одно ядро, которое реагирует на вертикальные границы. В настоящей CNN обычно применяется несколько фильтров. Каждый из них может обнаруживать свои признаки и формировать отдельную Feature Map.
Таким образом, наша реализация не является полноценной свёрточной нейронной сетью. Она показывает базовый механизм, на котором строится одна из ключевых операций CNN.
И этого достаточно для нашей задачи: мы увидели, как небольшое ядро перемещается по матрице, вычисляет отклик и выделяет границы между областями с разной яркостью.
8. Заключение
В этой статье мы разобрали одну из основных операций свёрточных нейронных сетей – свёртку – и реализовали её на чистом PHP.
Мы взяли небольшую матрицу яркости, создали ядро 3 × 3 и написали функцию, которая перемещает это ядро по матрице, перемножает соответствующие значения и суммирует результаты.
В результате получили Feature Map, на которой хорошо видна граница между тёмной и светлой областями.
Затем мы провели несколько простых экспериментов: изменили направление фильтра, попробовали найти горизонтальные границы и уменьшили контраст между областями. Каждый раз результат менялся в соответствии с тем, какие признаки искал наш фильтр.
Конечно, это ещё не полноценная CNN. Мы не обучали фильтры, не использовали несколько свёрточных слоёв и не работали с настоящими изображениями. Но мы разобрали сам механизм свёртки – без сторонних библиотек и готовых ML-алгоритмов.
Именно с таких небольших примеров проще всего начинать изучение машинного обучения: не просто использовать готовые инструменты, а понимать, какие вычисления стоят за ними.
Главная идея: свёрточная сеть анализирует изображение не целиком, а небольшими локальными участками, постепенно извлекая из них полезные признаки. Свёртка – один из механизмов, который позволяет ей это делать.
Если вам интересна тема AI и Machine Learning в PHP и вы хотите разобраться в ней глубже, приглашаю продолжить знакомство с помощью моих материалов:
Книга: AI для PHP-разработчиков: интуитивно и на практике – последовательное знакомство с основами AI и ML с примерами на PHP.
Интерактивные примеры: PHP AI Playground – возможность запустить примеры, поэкспериментировать с параметрами и самостоятельно изучить код.
Онлайн-курс: AI & ML Foundations for PHP Developers – бесплатный курс, который поможет систематизировать знания и разобраться в основных концепциях AI и Machine Learning.
Все материалы доступны бесплатно. Буду рад, если они помогут вам открыть для себя новые возможности AI в PHP!
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.