Джулия: Решение проблемы XOR с многослойными персептронами

Julia

1/ Проблема исключающего ИЛИ

Проблема XOR заключается в том, что когда логические значения двух входов одинаковы, выход True (представленный 1), а если логические значения двух входов несовместимы, выход False (представленный 0).

Говорят, что многоуровневый персептрон (MLP) трудно справляется с проблемой XOR, такой как следующая проблема.

Впервые представлено вопросом, упражнение 4-2 из главы 4 книги Цю Сипенга «Нейронные сети и глубокое обучение»:

Упражнение 4-2Попробуйте спроектировать нейронную сеть с прямой связью для решения проблемы XOR, требуя, чтобы нейронная сеть с прямой связью имела два скрытых нейрона и один выходной нейрон и использовала ReLU в качестве функции активации.

Достижимый результат выглядит следующим образом:

W(1)=[1111],b(1)=[01]w(2)=[12],b(2)=[0](1)\boldsymbol{W}^{(1)}=\left[\begin{array}{ll}1 & 1 \\ 1 & 1\end{array}\right], \boldsymbol{b}^{(1)}=\left[\begin{array}{c}0 \\ -1\end{array}\right]\\ \boldsymbol{w}^{(2)}=\left[\begin{array}{c}1 \\ -2\end{array}\right], b^{(2)}=\left[0\right] \tag{1}

Следовательно, расчет всей сети:

y=(w(2))T(ReLU((W(1))TX+b(1)))+b(2)\boldsymbol{y}=\left(\boldsymbol{w}^{(2)}\right)^{\mathrm{T}}\left(\operatorname{ReLU}\left(\left(\boldsymbol{W}^{(1)}\right)^{\mathrm{T}} \boldsymbol{X}+\boldsymbol{b}^{(1)}\right)\right)+b^{(2)}

Заменить в:

X=[00110101]\boldsymbol{X}=\left[\begin{array}{llll}0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1\end{array}\right]

Его можно рассчитать как:y=[0110]\boldsymbol{y}=\left[\begin{array}{llll}0 & 1 & 1 & 0\end{array}\right]

2/ Тренируйтесь с Flux

2.1/ ​​Два скрытых нейрона

На самом деле такая структура сети, если она обучается методом случайной инициализации, для обучения не годится. Причина в том, что в середине требуется функция активации ReLU. Если ее заменить другими функциями активации, ее можно хорошо обучить .

Используйте следующий код:

using Flux

function loss()
    ŷ = mlp(data)
    Flux.mse(ŷ, y)
end

cb = function ()
    println(loss())
end

data = Array([[0 1 0 1];
              [0 0 1 1]]);
y = Array([[0 1 1 0];]);

mlp = Chain(Dense(2, 2, relu), Dense(2, 1));
ps = Flux.params(mlp);

opt = ADAM(0.01)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)

После тренировки вы обнаружите, что потери по-прежнему очень велики, а выходные результаты будут все очень близки.0.50.5.

Если мы установим параметры скрытого слоя на результат (1), то обучим только веса выходного слояw(2)\boldsymbol{w}^{(2)}, то вы получите тот же результат:

# 自定义权重,将权重都初始化为全 1 的矩阵
mlp = Chain(Dense(2, 2, relu, bias=[0; -1], init=ones),
            Dense(2, 1, bias=zeros(1), init=ones))
# 只拿出第三个参数,即输出层的权重训练
ps = Flux.params(Flux.params(mlp)[3])
opt = ADAM(0.1)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)

результат будетw(2)=[0.9999...1.9999...]\boldsymbol{w}^{(2)}=[0.9999... -1.9999...], который совпадает с дизайном заголовка.

2.2/ Три скрытых нейрона

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

mlp = Chain(Dense(2, 3, relu), Dense(3, 1));
ps = Flux.params(mlp)
opt = ADAM(0.01)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)
# loss = 0.22230548
# loss = 0.21818444
# ...
# loss = 0.0
ŷ = mlp(data)

Окончательное решение правильное, вы можете узнать, посмотрев параметры каждого слоя

W(1)=[0.5743090.5743090.927540.9662121.123781.12138],b(1)=[0.57431280.000461418240.0034916808]w(2)=[1.741220.600531.2883],b(2)=[1.0000067]\boldsymbol{W}^{(1)}=\left[\begin{array}{ll} 0.574309 & -0.574309\\ 0.92754 & -0.966212\\ 1.12378 & -1.12138\end{array}\right], \boldsymbol{b}^{(1)}=\left[\begin{array}{c} 0.5743128\\ -0.00046141824\\ -0.0034916808\end{array}\right]\\ \boldsymbol{w}^{(2)}=\left[\begin{array}{c} -1.74122 \\ 0.60053 \\ 1.2883\end{array}\right], b^{(2)}=\left[1.0000067\right]

При использовании двух скрытых нейронов очень сложно тренироваться путем случайной инициализации весов, но при использовании трех скрытых нейронов возможности достаточно для решения задачи XOR.

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

Основная проблема по-прежнему должна заключаться в том, что ReLU будет напрямую обрезать часть меньше нуля, что эквивалентно тому факту, что нейрон не активирован, что легко приведет к тому, что нейрон «умрет» и не сможет продолжать обучение.