Содержание статьи
Библиотека TensorFlow: пишем нейросеть и изучаем принципы машинного обучения
Что запомнить
Получилось странно — мы ожидали, что будет число 51 (потому что подставили 10 в выражение 5X + 1) — но на выходе нейросеть выдала число 50.98739. А всё потому, что модель нашла очень близкую, но не до конца точную формулу — например, 4.891X + 0.993. Это одна из особенностей машинного обучения.
Обучается нейросеть итеративно — или поэтапно. На каждой итерации она будет предлагать алгоритм, по которому входные значения сопоставляются с результатом. Затем она проверит свои предположения, вычислив все входные данные по формуле и сравнив с настоящими результатами. Так она узнает, насколько сильно ошиблась. И уже на основе этих ошибок скорректирует формулу на следующей итерации.
В целом машинное обучение похоже на обучение обычного человека. Например, чтобы различать обувь и одежду, нам нужно посмотреть на какое-то количество экземпляров обуви и одежды, высказать свои предположения относительно того, что именно сейчас находится перед нами, получить обратную связь от кого-то, кто уже умеет их различать, — и тогда у нас появится алгоритм, как отличать одно от другого. Увидев туфли после успешного обучения, мы сразу сможем сказать, что это обувь, потому что по всем признакам они соответствуют этой категории.
Разберём код подробнее. Sequential — это тип нейросети, означающий, что процесс обучения будет последовательным. Это стандартный процесс обучения для простых нейросетей: в нём она сначала делает предсказания, затем тестирует их и сравнивает с результатом, а в конце — корректирует ошибки.
Функция fit как раз занимается обучением. Она берёт набор входных данных — xs — и сопоставляет с набором правильных результатов — ys. И так нейросеть обучается в течение 500 итераций — epochs=500. Мы использовали 500 итераций, чтобы наверняка прийти к правильному результату. Суть простая: чем больше итераций обучения, тем точнее будут результаты (однако улучшение точности с каждым повтором будет всё меньше и меньше).
Давайте поймем почему формула имеет такой вид. Сначала нам нужно учесть то, что мы хотим скорректировать вес пропорционально размеру ошибки. Далее ошибка умножается на значение, поданное на вход нейрона, что, в нашем случае, 0 или 1. Если на вход был подан 0, то вес не корректируется. И в конце выражение умножается на градиент сигмоиды. Разберемся в последнем шаге по порядку:
Как можно улучшить нейронную сеть
Больше мощностей. Нейронные сети работают с матрицами, так что если нейронов много, вычисления получаются очень ресурсоемкие. Известные нейросети вроде Midjourney или ChatGPT — это сложные и «тяжелые» системы, для их работы нужны сервера с мощным «железом». Так что написать собственный DALL-E на домашнем компьютере не получится. Но есть сервисы для аренды мощностей: ими как раз пользуются инженеры машинного обучения, чтобы создавать, обучать и тестировать модели.
Фреймворк TensorFlow — это относительно простой инструмент, который позволяет быстро создавать нейросети любой сложности. Он очень дружелюбен для начинающих, потому что содержит много примеров и уже готовых моделей машинного обучения, которые можно встроить в любое приложение. А продвинутым разработчикам TensorFlow предоставляет тонкие настройки и API для ускоренного обучения.
Еще есть, например, метод обратного распространения ошибки — градиентный алгоритм для многослойных нейросетей. Сигналы ошибки, рассчитанные с помощью градиента, распространяются от выхода нейронной сети к входу, то есть идут не в прямом, а в обратном направлении.
keras.layers.Dense — указывает на то, что мы хотим создать слой в нашей модели. Слой — это место, куда мы будем складывать нейроны, которые запоминают информацию об ошибках и которые отвечают за «умственные способности» нейросети. Dense — это тип слоя, который использует специальные алгоритмы для обучения.
А так как изначально мы сказали, что два числа будут равны, если разница между ними меньше 0.0000001, то обе формулы могут считаться идентичными, потому что получившаяся у нас на практике погрешность 0.0000000024 меньше допустимого значения, о котором мы договорились, — то есть 0.0000001. Вот такая интересная математика.
Так часто происходит в реальных задачах, например, при распознавании предметов. Не у всех из них есть жесткие критерии: скажем, гипертрофированного мультяшного персонажа мы по-прежнему различаем как человека, хотя у него совсем другие пропорции. Нейронную сеть сложно научить похожему — но современные системы могут справиться и с этим.
Но нейронные сети — все же не человеческий мозг. Мозг сложнее, объемнее, в нем намного больше нейронов, чем в любой компьютерной нейросети. Поэтому чрезмерное обучение может сделать хуже. Например, переобученная нейросеть может начать распознавать предметы там, где их нет — так люди иногда видят лица в фарах машин и принимают пакеты за котов. А в случае с искусственной нейронной сетью такой эффект еще явнее и заметнее. Если же учить нейросеть на нескольких разнородных данных, скажем, сначала обучить считать числа, а потом — распознавать лица, она просто сломается и начнет работать непредсказуемо. Для таких задач нужны разные нейросети, разные структуры и связи.
Другие методы и формулы. Чтобы нейроны обучались, нужно задать формулу корректировки весов — мы говорили про это выше. Если нейронов много, то формулу нужно как-то распространить на все из них. Для этого используется метод градиентного спуска: рассчитывается градиент по весам, а потом от него делается шаг в меньшую сторону. Звучит сложно, но на самом деле для этого есть специальные формулы и функции.