Хабрахабр

[Перевод] Нейросети и глубокое обучение, глава 4: визуальное доказательство того, что нейросети способны вычислить любую функцию

В данной главе я даю простое и по большей части визуальное объяснение теоремы универсальности. Чтобы следить за материалом этой главы, не обязательно читать предыдущие. Он структурирован в виде самостоятельного эссе. Если у вас есть самое базовое представление о НС, вы должны суметь понять объяснения.

Содержание

Один из наиболее потрясающих фактов, связанных с нейросетями, заключается в том, что они могут вычислить вообще любую функцию. То есть, допустим, некто даёт вам какую-то сложную и извилистую функцию f(x):


И вне зависимости от этой функции гарантированно существует такая нейросеть, что для любого входа x значение f(x) (или некая близкая к нему аппроксимация) будет являться выходом этой сети, то есть:

К примеру, вот сеть, вычисляющая функцию с m=3 входами и n=2 выходами: Это работает, даже если это функция многих переменных f=f(x1,…,xm), и со многими значениями.

Неважно, какую функцию мы хотим вычислить, мы знаем, что существует нейросеть, способная сделать это. Этот результат говорит о том, что у нейросетей есть определённая универсальность.

одним скрытым слоем. Более того, теорема универсальности выполняется, даже если мы ограничим сети единственным слоем между входящими и выходящими нейронами – т.н. Так что даже сети с очень простой архитектурой могут быть чрезвычайно мощными.

Но хотя это так, понимание этого факта не так широко распространено. Теорема универсальности хорошо знакома людям, использующим нейросети. К примеру, одна из первых работ, доказывающих этот результат, использовала теорему Хана — Банаха, теорему представлений Риса и немного анализа Фурье. А большинство объяснений этого слишком технически сложные. А жаль, поскольку базовые причины универсальности просты и прекрасны. Если вы математик, вам несложно разобраться в этих доказательствах, но большинству людей это не так-то просто.

Мы шаг за шагом пройдём по лежащим в её основе идеям. В данной главе я даю простое и по большей части визуальное объяснение теоремы универсальности. Вы поймёте некоторые ограничения этого результата. Вы поймёте, почему нейросети действительно могут вычислить любую функцию. И поймёте, как результат связан с глубокими НС.

Он структурирован в виде самостоятельного эссе. Чтобы следить за материалом этой главы, не обязательно читать предыдущие. Но я буду иногда давать ссылки на предыдущие материалы, чтобы помочь заполнить пробелы в знаниях. Если у вас есть самое базовое представление о НС, вы должны суметь понять объяснения.

Но стоит напоминать себе: возможность вычислить любую произвольную функцию поистине удивительна. Теоремы универсальности часто встречаются в информатике, так, что иногда мы даже забываем, насколько они потрясающие. Рассмотрим задачу поиска названия музыкальной композиции на основе краткого отрывка. Практически любой процесс, который вы можете себе представить, можно свести к вычислению функции. Или рассмотрим задачу перевода китайского текста на английский. Это можно считать вычислением функции. Или рассмотрим задачу генерации описания сюжета фильма и качества актёрской игры на основе файла mp4. И это можно считать вычислением функции (на самом деле, многих функций, поскольку существует множество приемлемых вариантов переводов одного текста). Универсальность означает, что в принципе, НС могут выполнять все эти задачи, и множество других. Это тоже можно рассматривать, как вычисление некоей функции (здесь тоже верна ремарка, сделанная по поводу вариантов перевода текста).

Это ограничение также применимо к традиционным теоремам универсальности для таких моделей, как Булевы схемы. Конечно, только из того, что мы знаем, что существуют НС, способные, допустим, переводить с китайского на английский, не следует, что у нас есть хорошие техники для создания или даже распознавания такой сети. Комбинация алгоритмов обучения и универсальности – смесь привлекательная. Но, как мы уже видели в этой книге, у НС есть мощные алгоритмы для выучивания функций. В данной главе мы сконцентрируемся на универсальности и на том, что она означает. Пока что в книге мы концентрировались на обучающих алгоритмах.

Два подвоха

До того, как объяснить, почему теорема универсальности верна, я хочу упомянуть два подвоха, содержащихся в неформальном заявлении «нейросеть может вычислить любую функцию».

Мы лишь можем получить настолько хорошее приближение, насколько нам нужно. Во-первых, это не значит, что сеть можно использовать для точного подсчёта любой функции. К примеру, ранее я иллюстрировал сеть, вычисляющую некую функцию f(x) с использованием трёх скрытых нейронов. Увеличивая количество скрытых нейронов, мы улучшаем аппроксимацию. Увеличив количество скрытых нейронов (допустим, до пяти), мы обычно можем получить улучшенное приближение: Для большинства функций при помощи трёх нейронов можно будет получить только низкокачественное приближение.

И ещё улучшить ситуацию, увеличивая количество скрытых нейронов и далее.

Есть гарантия, что при использовании достаточного количества скрытых нейронов, мы всегда сможем найти НС, выход которой g(x) удовлетворяет уравнению |g(x)−f(x)|<ε для любого x. Чтобы уточнить это утверждение, допустим, нам дали функцию f(x), которую мы хотим вычислить с некоей нужной точностью ε>0. Иначе говоря, аппроксимация будет достигнута с нужной точностью для любого возможного входного значения.

Если функция прерывается, то есть, делает внезапные резкие скачки, то в общем случае её будет невозможно аппроксимировать при помощи НС. Второй подвох состоит в том, что функции, которые можно аппроксимировать описанным способом, принадлежат к непрерывному классу. Однако, даже если функция, которую нам очень нужно вычислить, разрывная, часто оказывается достаточно непрерывной аппроксимации. И это неудивительно, поскольку наши НС вычисляют непрерывные функции от входных данных. На практике это ограничение обычно не является важным. Если это так, то мы можем использовать НС.

В данной главе мы докажем чуть менее строгую версию этой теоремы, используя два скрытых слоя вместо одного. В итоге, боле точным утверждением теоремы универсальности будет то, что НС с одним скрытым слоем можно использовать для аппроксимации любой непрерывной функции с любой желаемой точностью. В задачах я кратко опишу как это объяснение можно, с небольшими изменениями, адаптировать к доказательству, использующему только один скрытый слой.

Универсальность с одним входным и одним выходным значением

Чтобы понять, почему теорема универсальности истинна, начнём с понимания того, как создать НС, аппроксимирующую функцию только с одним входным и одним выходным значением:

Как только мы поймём этот особый случай, будет довольно легко расширить его на функции со многими входными и выходными значениями. Оказывается, что это – суть задачи универсальности.

Чтобы создать понимание того, как сконструировать сеть для подсчёта f, начнём с сети, содержащей едиинственный скрытый слой с двумя скрытыми нейронами, и с выходным слоем, содержащим один выходной нейрон:

На диаграмме в оригинале статьи можно интерактивно менять вес мышью, кликнув на «w», и сразу же увидеть, как меняется функция, вычисляемая верхним скрытым нейроном: Чтобы представить, как работают компоненты сети, сконцентрируемся на верхнем скрытом нейроне.

Пока что мы довольно часто использовали эту алгебраическую форму. Как мы узнали ранее в книге, скрытый нейрон подсчитывает σ(wx+b), где σ(z) ≡ 1/(1+e−z) – сигмоида. Это не только поможет лучше почувствовать, что происходит, но и даст нам доказательство универсальности, применимое к другим функциям активации, кроме сигмоиды. Однако для доказательства универсальности будет лучше, если мы полностью проигнорируем эту алгебру, и вместо этого будем манипулировать и наблюдать за формой на графике.

Но я считаю, что визуальный подход даёт больше понимания истинности итогового результата, чем традиционное доказательство. Строго говоря, избранный мною визуальный подход традиционно не считается доказательством. В предлагаемом мною доказательстве изредка будут попадаться пробелы; я буду давать разумное, но не всегда строгое визуальное доказательство. А, конечно, подобное понимание и есть реальная цель доказательства. Однако не теряйте из виду главной цели: понять, почему теорема универсальности верна. Если это беспокоит вас, то считайте своей задачей заполнить эти пробелы.

Вы увидите, что с увеличением смещения график двигается влево, но не меняет форму. Чтобы начать с этим доказательством, кликните в оригинальной диаграмме на смещение b и проведите мышью вправо, чтобы увеличить его.

Вы увидите, что график двигается вправо, не меняя форму. Затем протяните его влево, чтобы уменьшить смещение.

Вы увидите, что с уменьшением веса кривая распрямляется. Уменьшите вес до 2-3. Чтобы кривая не убегала с графика, возможно, придётся подправить смещение.

Кривая будет становиться всё круче, и в итоге приблизится к ступеньке. Наконец, увеличьте вес до значений более 100. На видео ниже показано, что должно получиться: Попробуйте подрегулировать смещение так, чтобы её угол находился в районе точки x=0,3.

Your browser does not support HTML5 video.

Ниже я построил выход верхнего скрытого нейрона для веса w=999. Мы можем очень сильно упростить наш анализ, увеличив вес так, чтобы выход реально был хорошей аппроксимацией ступенчатой функции. Это статичное изображение:

Причина в том, что в выходном слое складываются вклады от всех скрытых нейронов. Со ступенчатыми функциями работать немного проще, чем с типичными сигмоидами. Поэтому будет гораздо проще предположить, что наши скрытые нейроны выдаёт ступенчатые функции. Сумму кучки ступенчатых функций анализировать легко, а вот рассуждать о том, что происходит при сложении кучи кривых в виде сигмоиды – сложнее. Конечно, работа с выходом, как со ступенчатой функцией – это приближение, но очень хорошее, и пока что мы будем относиться к функции, как к истинно ступенчатой. Точнее, мы делаем это, фиксируя вес w на некоем очень большом значении, а потом назначая положение ступеньки через смещение. Позднее я вернусь к обсуждению влияния отклонений от этого приближения.

Иначе говоря, как положение ступеньки зависит от веса и смещения? На каком значении x находится ступенька?

Можете ли вы понять, как положение ступеньки зависит от w и b? Для ответа на вопрос попытайтесь изменить вес и смещение в интерактивной диаграмме. Попрактиковавшись немного, вы сможете убедить себя, что её положение пропорционально b и обратно пропорционально w.

На самом деле, ступенька находится на отметке s=−b/w, как будет видно, если подстроить вес и смещение к следующим значениям:

На следующей интерактивной диаграмме можно менять уже просто s: Наши жизни сильно упростятся, если мы будем описывать скрытые нейроны единственным параметром, s, то есть, положением ступеньки, s=−b/w.

И мы легко можем превратить таким образом параметризованный нейрон обратно к обычной форме, выбрав смещение b=−ws. Как отмечено выше, мы специально назначили весу w на входе очень большое значение – достаточно большое, чтобы ступенчатая функция стала хорошим приближением.

Давайте посмотрим на поведение всей сети. Пока что мы концентрировались на выходе только верхнего скрытого нейрона. Их соответствующими выходными весами будут w1 и w2. Предположим, что скрытые нейроны вычисляют ступенчатые функции, заданные параметрами ступенек s1 (верхний нейрон) и s2 (нижний нейрон). Вот наша сеть:

Здесь a1 и a2 — выходы верхнего и нижнего скрытых нейронов, соответственно. Справа строится график взвешенного выхода w1a1 + w2a2 скрытого слоя. Они обозначаются через «a», поскольку их часто называют активациями нейронов.

Это, очевидно, не то же самое, что взвешенный выход скрытого слоя, график которого мы строим. Кстати, отметим, что выход всей сети равен σ(w1a1 + w2a2 + b), где b – смещение выходного нейрона. Но пока мы сконцентрируемся на взвешенном выходе скрытого слоя, и только позднее подумаем, как он связан с выходом всей сети.

Посмотрите, как это меняет взвешенный выход скрытого слоя. Попробуйте на интерактивной диаграмме в оригинале статьи увеличивать и уменьшать ступеньку s1 верхнего скрытого нейрона. Вы увидите, что график в этих случаях меняет форму, поскольку мы переходим от ситуации, в которой верхний скрытый нейрон активируется первым, к ситуации, в которой нижний скрытый нейрон активируется первым. Особенно полезно понять, что происходит, когда s1 превышает s2.

Сходным образом попробуйте манипулировать ступенькой s2 у нижнего скрытого нейрона, и посмотрите, как это меняет общий выход скрытых нейронов.

Заметьте, как это масштабирует вклад от соответствующих скрытых нейронов. Попробуйте уменьшать и увеличивать выходные веса. Что будет, если один из весов сравняется с 0?

Получится функция «выступа», с началом в точке s1, концом в точке s2, и высотой 0,8. Наконец, попробуйте выставить w1 в 0,8, а w2 в -0,8. К примеру, взвешенный выход может выглядеть так:

Давайте использовать один параметр, h, обозначающий высоту. Конечно, выступ можно масштабировать до любой высоты. Также для упрощения я избавлюсь от обозначений «s1=…» и «w1=…».

Попробуйте сделать h отрицательным. Попробуйте увеличивать и уменьшать значение h, чтобы посмотреть, как меняется высота выступа. Попробуйте менять точки ступенек, чтобы понаблюдать, как это меняет форму выступа.

Вы увидите, что мы используем наши нейроны не просто, как графические примитивы, но и как более привычные программистам единицы – нечто вроде инструкции if-then-else в программировании:

if вход >= начало ступеньки:
добавить 1 к взвешенному выходу
else:
добавить 0 к взвешенному выходу

Однако иногда вам будет полезно переключаться на представление if-then-else и размышлять о происходящем в этих терминах. По большей части я буду придерживаться графических обозначений.

Мы можем использовать наш трюк с появлением выступа, склеив две части скрытых нейронов вместе в одной сети:

Попробуйте поиграть с обоими значениями h, и понаблюдать, как это меняет график. Здесь я опустил веса, просто записав значения h для каждой пары скрытых нейронов. Подвигайте выступы, меняя точки ступенек.

В частности, мы можем разделить интервал [0,1] на большое количество (N) подынтервалов, и использовать N пар скрытых нейронов для получения пиков любой нужной высоты. В более общем случае эту идею можно использовать для получения любого желаемого количества пиков любой высоты. Это уже довольно много нейронов, поэтому я немного ужму представления. Посмотрим, как это работает для N=5. Извините за сложную диаграмму – я бы мог спрятать сложность за дополнительными абстракциями, но мне кажется, что стоит немного помучаться со сложностью, чтобы лучше почувствовать то, как работают нейросети.

Точки ступенек соответствующих пар располагаются на значениях 0,1/5, затем 1/5,2/5, и так далее, вплоть до 4/5,5/5. Вы видите, что у нас есть пять пар скрытых нейронов. Эти значения фиксированы – мы получаем пять выступов равной ширины на графике.

Помните, что у выходных связей нейронов есть веса h и –h. У каждой пары нейронов есть связанное с нею значение h. С изменением высоты меняется и график. В оригинале статьи на диаграмме можно кликнуть на значения h и подвигать их влево-вправо. Изменяя выходные веса, мы конструируем итоговую функцию!

При изменении её высоты вы видите, как изменяется высота соответствующего h. На диаграмме можно ещё кликнуть по графику, и потаскать высоту ступеньки вверх или вниз. Иначе говоря, мы напрямую манипулируем функцией, график которой показан справа, и видим эти изменения в значениях h слева. Соответствующим образом меняются выходные веса +h и –h. Можно ещё зажать клавишу мыши на одном из выступов, а потом провести мышью влево или вправо, и выступы будут подстраиваться под текущую высоту.

Настало время справиться с задачей.

Вспомним функцию, которую я нарисовал в самом начале главы:

Тогда я не упоминал об этом, но на самом деле она выглядит так:

2+0. $ f(x) = 0. 3x \sin(15 x) + 0. 4 x^2+0. 05 \cos(50 x) \tag $

Она строится для значений x от 0 до 1, а значения по оси y варьируются от 0 до 1.

И вы должны придумать, как подсчитать её с использованием нейросетей. Очевидно, что эта функция нетривиальная.

Мы знаем, как получить значительный контроль над этой величиной. В наших нейросетях выше мы анализировали взвешенную комбинацию ∑jwjaj выхода скрытых нейронов. Выход сети – это σ(∑jwjaj + b), где b – смещение выходного нейрона. Но, как я отметил ранее, эта величина не равна выходу сети. Можем ли мы получить контроль непосредственно над выходом сети?

То есть, мы хотим, чтобы взвешенный выход скрытого слоя был таким: Решение – разработать такую нейросеть, у которой взвешенный выход скрытого слоя задаётся уравнением σ−1⋅f(x), где σ−1 — обратная функция σ.

Если это получится, тогда выход всей сети будет хорошей аппроксимацией f(x) (смещение выходного нейрона я установил в 0).

Чтобы лучше понять происходящее, рекомендую вам решить эту задачу дважды. Тогда ваша задача – разработать НС, аппроксимирующую целевую функцию, показанную выше. Вам довольно легко будет получить хорошее приближение к целевой функции. В первый раз в оригинале статьи кликните на график, и напрямую подстройте высоты разных выступов. Ваша задача – привести среднее отклонение к минимальному значению. Степень приближения оценивается средним отклонением, разницей между целевой функцией и той функцией, которую подсчитывает сеть. Задача считается выполненной, когда среднее отклонение не превышает 0,40.

Второй раз не трогайте график, а изменяйте величины h с левой стороны диаграммы, пытаясь привести среднее отклонение к величине 0,40 или менее. Достигнув успеха, нажмите кнопку Reset, которая случайным образом поменяет выступы.

Аппроксимация получилась грубой, но мы легко можем улучшить результат, просто увеличив количество пар скрытых нейронов, что увеличит количество выступов. И вот, вы нашли все элементы, необходимые для того, чтобы сеть приблизительно вычисляла функцию f(x)!

Позвольте быстро напомнить, как это работает. В частности, легко превратить все найденные данные обратно в стандартный вид с параметризацией, используемый для НС.

У первого слоя все веса имеют большое постоянное значение, к примеру, w=1000.

Так что, к примеру, для второго скрытого нейрона s=0,2 превращается в b=−1000×0,2=−200. Смещения скрытых нейронов вычисляются через b=−ws.

Так что, к примеру, значение, выбранное вами для первого h, h= -0,2, означает, что выходные веса двух верхних скрытых нейронов равны -0,2 и 0,2 соответственно. Последний слой весов определяется значениями h. И так далее, для всего слоя выходных весов.

Наконец, смещение выходного нейрона равно 0.

И мы понимаем, как улучшить качество аппроксимации, улучшая количество скрытых нейронов. И это всё: у нас получилось полное описание НС, неплохо вычисляющей изначальную целевую функцию.

Подобную процедуру можно было бы использовать для любой непрерывной функции на отрезках от [0,1] до [0,1]. Кроме того, в нашей оригинальной целевой функции f(x)=0,2+0,4x2+0,3sin(15x)+0,05cos(50x) нет ничего особенного. И мы можем взять эту идею за основу, чтобы получить обобщённое доказательство универсальности. По сути, мы используем нашу однослойную НС для построения справочной таблицы по функции.

Функция от многих параметров

Расширим наши результаты на случай множества входящих переменных. Звучит сложно, но все нужные нам идеи можно понять уже для случая всего с двумя входящими переменными. Поэтому рассмотрим случай с двумя входящими переменными.

Начнём с рассмотрения того, что будет, когда у нейрона есть два входа:

Установим вес w2 в 0 и поиграемся с первым, w1, и смещением b, чтобы посмотреть, как они влияют на выход нейрона: У нас есть входы x и y, с соответствующими весами w1 и w2 и смещением b нейрона.

Всё происходит так, будто x – единственный вход. Как видим, при w2=0 вход y не влияет на выход нейрона.

Если это сразу вам непонятно, подумайте немного над этим вопросом. Учитывая это, что, как вы думаете, произойдёт, когда мы увеличим вес w1 до w1=100, а w2 оставим 0? Потом посмотрите следующее видео, где показано, что произойдёт:

Your browser does not support HTML5 video.

Разница в том, что наша ступенчатая функция теперь расположена в трёх измерениях. Как и ранее, с увеличением входного веса выход приближается к форме ступеньки. Угол будет находиться в точке sx≡−b/w1. Как и раньше, мы можем передвигать местоположение ступеньки, изменяя смещение.

Давайте переделаем диаграмму, чтобы параметром было местоположение ступеньки:

Число на нейроне – это положение ступеньки, а x над ним напоминает, что мы передвигаем ступеньку по оси x. Мы предполагаем, что входящий вес у x имеет большое значение – я использовал w1=1000 – и вес w2=0. Естественно, вполне возможно получить ступенчатую функцию по оси y, сделав входящий вес для y большим (допустим, w2=1000), и вес для x равным 0, w1=0:

Я бы мог напрямую обозначить веса для x и y, но не стал, поскольку это замусорило бы диаграмму. Число на нейроне, опять-таки, обозначает положение ступеньки, а y над ним напоминает, что мы передвигаем ступеньку по оси y. Но учтите, что маркер y говорит о том, что вес для y большой, а для x равен 0.

Для этого мы возьмём два нейрона, каждый из которых будет вычислять ступенчатую функцию по оси x. Мы можем использовать только что сконструированные нами ступенчатые функции для вычисления функции трёхмерного выступа. Всё это видно на следующей диаграмме: Затем мы скомбинируем эти ступенчатые функции с весами h и –h, где h – желаемая высота выступа.

Посмотрите, как она связана с весами сети. Попробуйте поменять величину h. И как она меняет высоту функции выступа справа.

Посмотрите, как она меняет форму выступа. Также попытайтесь изменить точку ступеньки, величина которой установлена в 0,30 в верхнем скрытом нейроне. Что будет, если перенести её за точку 0,70, связанную с нижним скрытым нейроном?

Естественно, мы легко можем сделать функцию выступа и по оси y, используя две ступенчатые функции по оси y. Мы узнали, как построить функцию выступа по оси x. И вот, что получится: Вспомним, что мы можем сделать это, сделав большие веса на входе y, и установив вес 0 на входе x.

Единственное видимое изменение – маленькие маркеры y на скрытых нейронах. Выглядит почти идентично предыдущей сети! Как и раньше, я решил не показывать этого непосредственно, чтобы не захламлять рисунок. Они напоминают нам о том, что выдают ступенчатые функции для y, а не для x, поэтому на входе y вес очень большой, а на входе x – нулевой, а не наоборот.

Посмотрим, что будет, если мы добавим две функции выступа, одну по оси x, другую по оси y, обе высотой h:

Пока что я оставил маленькие маркеры x и y на скрытых нейронах, чтобы напомнить, в каких направлениях вычисляются функции выступов. Для упрощения диаграммы связи с нулевым весом я опустил. Позже мы и от них откажемся, поскольку они подразумеваются входящей переменной.

Как видите, из-за этого меняются выходные веса, а также веса обеих функций выступа, x и y. Попробуйте менять параметр h.

Созданное нами немного похоже на «функцию башни»:

Если мы можем создать такие функции башен, то мы можем использовать их для аппроксимации произвольных функций, просто добавляя башни различных высот в разных местах:

Мы пока сконструировали что-то вроде центральной башни высоты 2h с окружающим её плато высоты h. Конечно, мы пока ещё не дошли до создания произвольной функции башни.

Вспомните, что раньше мы показали, как нейроны можно использовать для реализации инструкции if-then-else: Но мы можем сделать функцию башни.

if вход >= порог: выход 1 else: выход 0

Это был нейрон с одним входом. А нам нужно применить сходную идею к комбинированному выходу скрытых нейронов:

if скомбинированный выход скрытых нейронов >= порог: выход 1 else: выход 0

Если мы правильно выберем порог – к примеру, 3h/2, втиснутый между высотой плато и высотой центральной башни – мы сможем раздавить плато до нуля, и оставить только одну башню.

Попробуйте поэкспериментировать со следующей сетью. Представляете, как это сделать? Это значит, что мы добавляем член смещения к взвешенному выходу от скрытого слоя, и применяем сигмоиду. Теперь мы строим график выхода всей сети, а не просто взвешенный выход скрытого слоя. Если вы застрянете на этом моменте, вот две подсказки: (1) чтобы выходящий нейрон продемонстрировал правильное поведение в стиле if-then-else, нам нужно, чтобы входящие веса (все h или –h) были крупными; (2) значение b определяет масштаб порога if-then-else. Сможете ли вы найти значения для h и b, при которых получится башня?

Чтобы получить желаемое поведение, нужно увеличить значение h. С параметрами по умолчанию выход похож на расплющенную версию предыдущей диаграммы, с башней и плато. Во-вторых, чтобы правильно задать порог, нужно выбрать b ≈ −3h/2. Это даст нам пороговое поведение if-then-else.

Вот как это выглядит для h=10:

Your browser does not support HTML5 video.

Даже для относительно скромных величин h мы получаем неплохую функцию башни. И, конечно, мы можем получить сколь угодно красивый результат, увеличивая h и дальше, и удерживая смещение на уровне b=−3h/2.

Чтобы соответствующие роли двух подсетей были ясны, я поместил их в отдельные прямоугольники: каждый из них вычисляет функцию башни при помощи описанной выше техники. Давайте попробуем склеить вместе две сети, чтобы подсчитать две разные функции башен. График справа показывает взвешенный выход второго скрытого слоя, то есть, взвешенную комбинацию функций башен.

В частности, видно, что изменяя веса в последнем слое, можно менять высоту выходных башен.

Мы можем сделать их сколь угодно тонкими и высокими. Та же идея позволяет вычислять сколько угодно башен. В итоге мы гарантируем, что взвешенный выход второго скрытого слоя аппроксимирует любую нужную функцию двух переменных:

В частности, заставив взвешенный выход второго скрытого слоя хорошо аппроксимировать σ−1⋅f, мы гарантируем, что выход нашей сети будет хорошей аппроксимацией желаемой функции f.

А что же насчёт функций многих переменных?

Следующую сеть можно использовать для подсчёта функции башни в четырёх измерениях? Попробуем взять три переменных, x1,x2,x3.

s1, t1 и так далее – точки ступенек дл нейронов – то есть, все веса в первом слое большие, а смещения назначены так, чтобы точки ступенек равнялись s1, t1, s2,… Веса во втором слое чередуются, +h,−h, где h – некое очень большое число. Здесь x1,x2,x3 обозначают вход сети. Выходное смещение равно −5h/2.

Сеть равна 0 во всех других местах. Сеть вычисляет функцию, равную 1, при выполнении трёх условий: x1 находится между s1 и t1; x2 находится между s2 и t2; x3 находится между s3 и t3. Это такая башня, у которой 1 – небольшой участок пространства входа, и 0 – всё остальное.

Та же идея работает в m измерений. Склеивая множество таких сетей, мы можем получить сколько угодно башен, и аппроксимировать произвольную функцию трёх переменных. Меняется только выходное смещение (−m+1/2)h, чтобы правильно втиснуть нужные значения и убрать плато.

Что насчёт векторных функций f(x1,…,xm) ∈ Rn? Хорошо, теперь мы знаем, как использовать НС для аппроксимации вещественной функции многих переменных. А потом мы просто склеиваем все сети вместе. Конечно, такую функцию можно рассматривать, просто как n отдельных вещественных функций f1(x1,…,xm), f2(x1,…,xm), и так далее. Так что с этим легко разобраться.

Задача

  • Мы увидели, как использовать нейросети с двумя скрытыми слоями для аппроксимации произвольной функции. Можете ли вы доказать, что это возможно делать с одним скрытым слоем? Подсказка – попробуйте работать с всего двумя выходными переменными, и показать, что: (a) возможно получить функции ступенек не только по осям x или y, но и в произвольном направлении; (b) складывая множество конструкций с шага (a), возможно аппроксимировать функцию круглой, а не прямоугольной башни; © используя круглые башни, возможно аппроксимировать произвольную функцию. Шаг © будет проще сделать, используя материал, представленный в этой главе немного ниже.

Выход за рамки сигмоидных нейронов

Мы доказали, что сеть, состоящая из сигмоидных нейронов, может вычислить любую функцию. Вспомним, что в сигмоидном нейроне входы x1,x2,… превращаются на выходе в σ(∑jwjxj + b), где wj — веса, b – смещение, σ — сигмоида.

Что, если мы рассмотрим другой тип нейрона, использующий другую функцию активации, s(z):

То есть, мы предположим, что если у нейрона на входе будет x1,x2,… веса w1,w2,… и смещение b, то на выходе будет s(∑jwjxj + b).

Попробуйте (в оригинале статьи) на диаграмме задрать вес до, допустим, w=100: Мы можем использовать эту функцию активации для получения ступенчатой, точно так же, как в случае с сигмоидой.

Попробуйте поменять смещение, и вы увидите, что мы можем изменить местоположение ступеньки на любое. Как и в случае с сигмоидой, из-за этого функция активации сжимается, и в итоге превращается в очень хорошую аппроксимацию ступенчатой функции. Поэтому мы можем использовать всё те же трюки, что и ранее, для вычисления любой желаемой функции.

Нам нужно предположить, что s(z) хорошо определена при z→−∞ и z→∞. Какие свойства должны быть у s(z), чтобы это сработало? Нам также нужно предположить, что эти пределы отличаются. Эти пределы – это два значения, принимаемых нашей ступенчатой функцией. Но если функция активации s(z) удовлетворяет этим свойствам, основанные на ней нейроны универсально подходят для вычислений. Если бы они не отличались, ступеньки бы не получилось, был бы просто плоский график!

Задачи

  • Ранее в книге мы познакомились с нейроном другого типа — выпрямленным линейным нейроном, или выпрямленной линейной единицей [rectified linear unit, ReLU]. Поясните, почему такие нейроны не удовлетворяют условиям, необходимым для универсальности. Найдите доказательство универсальности, показывающее, что ReLU универсально подходят для вычислений.
  • Допустим, мы рассматриваем линейные нейроны, с функцией активации s(z)=z. Поясните, почему линейные нейроны не удовлетворяют условиям универсальности. Покажите, что такие нейроны нельзя использовать для универсальных вычислений.

Исправляем ступенчатую функцию

Покамест мы предполагали, что наши нейроны выдают точные ступенчатые функции. Это неплохое приближение, но лишь приближение. На самом деле существует узкий промежуток отказа, показанный на следующем графике, где функции ведут себя совсем не так, как ступенчатая:

В этом промежутке отказа данное мною объяснение универсальности не работает.

Задавая достаточно большие входные веса, мы можем делать эти промежутки сколь угодно малыми. Отказ не такой уж страшный. Так что, возможно, нам не стоит волноваться из-за этой проблемы. Мы можем сделать их гораздо меньшими, чем на графике, невидимыми глазу.

Тем не менее, хотелось бы иметь некий способ её решения.

Давайте посмотрим на это решение для вычисляющих функции НС со всего одним входом и выходом. Оказывается, её легко решить. Те же идеи сработают и для решения проблемы с большим количеством входов и выходов.

Как и раньше, мы пытаемся сделать это, проектируя сеть так, чтобы взвешенный выход скрытого слоя нейронов был σ−1⋅f(x): В частности, допустим, мы хотим, чтобы наша сеть вычислила некую функцию f.

Если мы будем делать это, используя описанную выше технику, мы заставим скрытые нейроны выдать последовательность функций выступов:

Должно быть ясно, что если мы сложим все эти функции выступов, то получим достаточно хорошую аппроксимацию σ−1⋅f(x) везде, кроме промежутков отказа. Я, конечно, преувеличил размер промежутков отказа, чтобы их было легче увидеть.

Конечно, это будет выглядеть, просто как масштабированная версия последнего графика: Но, допустим, что вместо использования только что описанной аппроксимации, мы используем набор скрытых нейронов для вычисления аппроксимации половины нашей изначальной целевой функции, то есть, σ−1⋅f(x)/2.

И, допустим, мы заставим ещё один набор скрытых нейронов вычислять приближение к σ−1⋅f(x)/2, однако у него основания выступов будут сдвинуты на половину их ширины:

Если мы сложим две этих аппроксимации, то получим общее приближение к σ−1⋅f(x). Теперь у нас есть два разных приближения для σ−1⋅f(x)/2. Но проблема будет меньше, чем раньше – ведь точки, попадающие в промежутки отказа первой аппроксимации, не попадут в промежутки отказа второй аппроксимации. У этого общего приближения всё равно будут неточности в небольших промежутках. Поэтому аппроксимация в этих промежутках окажется примерно в 2 раза лучше.

Если все промежутки отказа у них будут достаточно узкими, любая тока будет находиться лишь в одном из них. Мы можем улучшить ситуацию, добавив большое количество, M, накладывающихся аппроксимаций функции σ−1⋅f(x)/M. Если использовать достаточно большое количество накладывающихся аппроксимаций M, в итоге получится прекрасное общее приближение.

Заключение

Рассмотренное здесь объяснение универсальности определённо нельзя назвать практическим описанием того, как подсчитывать функции при помощи нейросетей! В этом смысле оно больше похоже на доказательство универсальности логических вентилей NAND и прочего. Поэтому я в основном пытался сделать так, чтобы эта конструкция была ясной, и ей было просто следовать, не оптимизируя её детали. Однако попытки оптимизировать эту конструкцию могут стать для вас интересным и поучительным упражнением.

Ответ на такой вопрос всегда будет положительным. Хотя полученный результат нельзя напрямую использовать для создания НС, он важен, поскольку он снимает вопрос вычислимости какой-либо определённой функции при помощи НС. Поэтому правильно спрашивать не вычислима ли какая-либо функция, а каков правильный способ её вычисления.

Как мы обсуждали, возможно получить тот же результат при помощи единственного скрытого слоя. Разработанная нами универсальная конструкция использует всего два скрытых слоя для вычисления произвольной функции. Не можем ли мы просто заменить эти сети на неглубокие, имеющие один скрытый слой? Учитывая это, вы можете задуматься, зачем вообще нам нужны глубокие сети, то есть, сети с большим количеством скрытых слоёв.

Как описано в главе 1, у глубоких НС есть иерархическая структура, позволяющая им хорошо адаптироваться для изучения иерархических знаний, которые оказываются полезными для решения реальных проблем. Хотя, в принципе, это возможно, существуют хорошие практические причины для использования глубоких нейросетей. В более поздних главах мы увидим свидетельства, говорящие в пользу того, что глубокие НС смогут лучше неглубоких справиться с изучением подобных иерархий знания. Более конкретно, при решении таких задач, как распознавание образов, полезно бывает использовать систему, понимающую не только отдельные пиксели, но и всё более сложные концепции: от границ до простых геометрических фигур, и далее, вплоть до сложных сцен с участием нескольких объектов. Подытоживая: универсальность говорит нам, что НС могут подсчитать любую функцию; эмпирические свидетельства говорят о том, что глубокие НС лучше адаптированы к изучениям функций, полезных для решения многих задач реального мира.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть