您现在的位置是:首页 >技术杂谈 >神经网络之异或与非线性网站首页技术杂谈

神经网络之异或与非线性

ITIRONMAN 2024-06-17 10:13:49
简介神经网络之异或与非线性

在深度学习中,我们常常使用神经网络来解决各种问题。然而,并不是所有的问题都可以被神经网络解决。其中一个著名的例子就是异或问题。

异或(XOR)是一种逻辑操作符,它表示两个相同则为0,不同则为1。例如,1 XOR 1 = 0,1 XOR 0 = 1,0 XOR 0 = 0,0 XOR 1 = 1。现在考虑以下的异或问题:给定两个输入x和y,我们想要训练一个模型来输出它们的异或结果z=x XOR y。如果我们把这个问题看作是一种二元分类问题,其中对应的标签为1表示z=1,标签为0表示z=0,那么这个问题就是一个非常简单的分类问题。但是,当我们采用单一神经元或线性分类器来解决这个问题时,却会发现无法达到很好的效果。

单一神经元包括了若干个输入 x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn,每个输入都有对应的权重 w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1,w2,...,wn。神经元将这些输入加权求和,并通过激活函数f得出最终输出y=f(wx+b)。如果我们设置激活函数为阶跃函数,就可以将神经元看做是一个二元分类器。

那么,我们来尝试使用单一神经元来解决异或问题。对于输入向量 ( x 1 , x 2 ) (x_1, x_2) (x1,x2),它们的异或结果为 x 1 x_1 x1 XOR x 2 x_2 x2。我们可以将这两个输入作为神经元的两个输入 x 1 x_1 x1 x 2 x_2 x2,然后通过权重和激活函数得到输出:

y = f ( w 1 x 1 + w 2 x 2 + b ) y = f(w_1x_1 + w_2x_2 + b) y=f(w1x1+w2x2+b)

但是,我们会发现无论怎样调整权重和偏差(bias),都无法得到正确的输出。这是因为异或问题不是一个线性可分问题。简单地说,就是我们不能在二维平面上画出一条直线将标签为0和标签为1的点完全分开。标签为0和标签为1的点没有办法用一条直线完全分开。而单一神经元本质上就是一条直线,所以它无法解决异或问题。

接下来,我们来看一下线性分类器的结构。线性分类器也可以被视为单一神经元的一种形式。

线性分类器的结构与单一神经元非常相似,只是它的激活函数不同。线性分类器使用的激活函数通常是符号函数(sign function),其输出为-1或1:

f ( x ) = { 1 , x > 0 − 1 , x ≤ 0 f(x) = egin{cases} 1, & x>0 \ -1, & xleq 0 end{cases} f(x)={1,1,x>0x0

因此,我们可以将线性分类器看做是单一神经元的一种特殊情况。同样地,线性分类器也无法解决异或问题。

那么,为什么单一神经元和线性分类器无法解决异或问题呢?这是因为异或问题不能用一个超平面(hyperplane)完全分开。在二维平面上,可以用一个圆将标签为0和标签为1的点完全分开,但是这个圆并不是一个超平面。在更高维的空间中,异或问题更加复杂,无法通过一个超平面将标签为0和标签为1的点完全分开。

解决这个问题的方法有很多,最常见的方法是使用多层神经网络。多层神经网络可以被视为一系列单一神经元(或称为节点)的组合。每个节点会接收前一层节点的输出作为输入,并对其进行加权求和和激活函数处理,得到当前节点的输出。这样一层一层地堆叠起来,就形成了多层神经网络。通过多层神经网络,我们可以学习到更加复杂的特征表示,从而解决异或问题。

下图展示了一个简单的两层神经网络解决异或问题的过程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cAaQphxz-1683886595591)(null)]

首先,输入向量 ( x 1 , x 2 ) (x_1,x_2) (x1,x2)被输入到第一层的两个节点上。每个节点都会对输入进行加权求和和激活函数处理,得到输出 h 1 h_1 h1 h 2 h_2 h2。然后,这两个输出被输入到第二层的一个节点上。同样地,该节点也会对输入进行加权求和和激活函数处理,得到最终输出 y y y

值得注意的是,这个简单的两层神经网络中的每个节点都是使用阶跃函数作为激活函数。由于阶跃函数具有不连续、不可导等性质,因此它并不适合在实际应用中使用。在实际应用中,我们通常会采用其他更加平滑的激活函数,比如sigmoid函数、tanh函数或ReLU函数。

最后,再来看一下Python代码,展示如何使用多层神经网络来解决异或问题:

import numpy as np

# 定义输入和标签
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])

# 定义神经网络结构
input_size = 2
hidden_size = 2
output_size = 1

# 随机初始化权重
W1 = np.random.randn(input_size, hidden_size)
W2 = np.random.randn(hidden_size, output_size)

# 定义sigmoid函数作为激活函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 定义前向传播过程
def forward(X):
    # 第一层:输入到隐藏层
    z1 = np.dot(X, W1)
    h1 = sigmoid(z1)

    # 第二层:隐藏层到输出
    z2 = np.dot(h1, W2)
    y_hat = sigmoid(z2)

    return y_hat

# 定义损失函数
def loss(y, y_hat):
    return np.mean((y - y_hat) ** 2)

# 定义反向传播过程
def backward(X, y, y_hat):
    # 第二层:输出到隐藏层
    delta2 = (y - y_hat) * y_hat * (1 - y_hat)
    dW2 = np.dot(h1.T, delta2)

    # 第一层:隐藏层到输入
    delta1 = np.dot(delta2, W2.T) * h1 * (1 - h1)
    dW1 = np.dot(X.T, delta1)

    return dW1, dW2

# 训练神经网络
learning_rate = 0.1
for i in range(5000):
    # 前向传播
    y_hat = forward(X)

    # 计算损失函数
    l = loss(y, y_hat)

    # 反向传播
    dW1, dW2 = backward(X, y, y_hat)

    # 更新权重
    W1 += learning_rate * dW1
    W2 += learning_rate * dW2

    # 每隔1000次迭代输出一次损失函数的值
    if i % 1000 == 0:
        print("Iteration {}: Loss = {}".format(i, l))

# 测试神经网络
y_pred = forward(X)
print("Final predictions: ")
print(y_pred)

上面的代码中,我们首先定义了输入向量X和对应的标签y。然后,我们定义了神经网络的结构:输入层包含2个节点,隐藏层包含2个节点,输出层包含1个节点。接下来,我们随机初始化了权重W1和W2,并定义了激活函数sigmoid。在前向传播过程中,我们将输入X通过第一层和第二层得到输出y_hat。在反向传播过程中,我们计算了每个节点的误差并更新了权重。最后,我们使用训练好的网络对输入数据进行预测,并打印出预测结果。

可以看到,在使用多层神经网络解决异或问题时,我们需要至少两层(一个隐藏层)才能够得到正确的结果。这种现象被称为“万能逼近定理”(universal approximation theorem),它表明任何连续的函数都可以用一个具有足够多节点的单隐藏层神经网络来逼近。这也是为什么在实际应用中,多层神经网络比单层神经网络更加常见的原因之一。

总结一下,异或问题无法使用单一神经元或线性分类器解决,因为它不是一个线性可分问题。需要使用多层神经网络进行解决。多层神经网络可以通过堆叠多个节点来学习到更加复杂的特征表示,从而解决非线性问题。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。