前馈神经网络(Feedforward Neural Network,FFNN)是一种最基本的神经网络模型,也被称为多层感知机(Multi-Layer Perceptron,MLP)。它由多个神经元组成,每个神经元接收来自上一层神经元的输出,并通过一定的权重和偏置进行加权和处理,最终得到本层神经元的输出,进而作为下一层神经元的输入。该网络的信息流是单向的,只能从输入层流向输出层,因此称为前馈神经网络。
前馈神经网络通常包括输入层、若干个隐藏层和输出层,其中输入层接收原始数据输入,隐藏层对输入进行一定的变换和特征提取,输出层根据隐藏层的结果输出模型预测值。每个层都由若干个神经元组成,神经元之间的连接带有权重,可以通过反向传播算法来学习优化。前馈神经网络是一种强大的模型,能够处理非线性分类和回归任务。
import numpy as np
class FeedForwardNN:
def __init__(self, input_size, hidden_size, output_size):
# 初始化神经网络的参数
self.weights1 = np.random.randn(input_size, hidden_size)
self.bias1 = np.zeros((1, hidden_size))
self.weights2 = np.random.randn(hidden_size, output_size)
self.bias2 = np.zeros((1, output_size))
def forward(self, x):
# 前向传播,计算输出值
self.z1 = np.dot(x, self.weights1) + self.bias1
self.a1 = np.tanh(self.z1)
self.z2 = np.dot(self.a1, self.weights2) + self.bias2
self.output = self.z2
def backward(self, x, y):
# 反向传播,计算参数的梯度
m = x.shape[0]
delta2 = self.output - y
dweights2 = np.dot(self.a1.T, delta2) / m
dbias2 = np.sum(delta2, axis=0, keepdims=True) / m
delta1 = np.dot(delta2, self.weights2.T) * (1 - np.power(self.a1, 2))
dweights1 = np.dot(x.T, delta1) / m
dbias1 = np.sum(delta1, axis=0) / m
# 更新参数
self.weights1 -= 0.1 * dweights1
self.bias1 -= 0.1 * dbias1
self.weights2 -= 0.1 * dweights2
self.bias2 -= 0.1 * dbias2
def train(self, x, y, epochs):
# 训练神经网络
for i in range(epochs):
self.forward(x)
self.backward(x, y)
def predict(self, x):
self.forward(x)
return self.output
在这个示例中,定义了一个名为FeedForwardNN的类,它有三个初始化参数:输入层神经元数量input_size,隐藏层神经元数量hidden_size,输出层神经元数量output_size。在初始化方法__init__中,根据这些参数随机初始化了权重和偏置。
该类有三个主要的方法:前向传播方法forward,反向传播方法backward和预测方法predict。在前向传播方法forward中,使用权重和偏置计算加权和,然后通过tanh函数计算激活值。在输出层,直接计算加权和和输出值。在反向传播方法backward中,首先计算误差,然后计算参数的梯度,并使用梯度下降法更新参数。在训练方法train中,进行前向传播和反向传播的交替训练。在预测方法predict中,使用训练好的模型进行预测,并返回预测值。
这个示例是一个简单的前馈神经网络,可以用来解决分类和回归问题。
一个前馈神经网络的具体实例是基于MNIST手写数字数据集的手写数字识别问题。该问题的目标是根据输入的手写数字图像,判断其代表的数字是什么。下面是一个简单的前馈神经网络的实现示例:
import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
# 加载MNIST手写数字数据集
mnist = fetch_openml('mnist_784')
X, y = mnist.data / 255., mnist.target.astype(int)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 定义前馈神经网络
class FeedForwardNN:
def __init__(self, input_size, hidden_size, output_size):
self.weights1 = np.random.randn(input_size, hidden_size) * 0.01
self.bias1 = np.zeros((1, hidden_size))
self.weights2 = np.random.randn(hidden_size, output_size) * 0.01
self.bias2 = np.zeros((1, output_size))
def forward(self, x):
self.z1 = np.dot(x, self.weights1) + self.bias1
self.a1 = np.tanh(self.z1)
self.z2 = np.dot(self.a1, self.weights2) + self.bias2
self.output = self.softmax(self.z2)
def backward(self, x, y):
m = x.shape[0]
delta2 = self.output - y
dweights2 = np.dot(self.a1.T, delta2) / m
dbias2 = np.sum(delta2, axis=0, keepdims=True) / m
delta1 = np.dot(delta2, self.weights2.T) * (1 - np.power(self.a1, 2))
dweights1 = np.dot(x.T, delta1) / m
dbias1 = np.sum(delta1, axis=0) / m
self.weights1 -= 0.1 * dweights1
self.bias1 -= 0.1 * dbias1
self.weights2 -= 0.1 * dweights2
self.bias2 -= 0.1 * dbias2
def train(self, x, y, epochs):
for i in range(epochs):
self.forward(x)
self.backward(x, y)
def predict(self, x):
self.forward(x)
return np.argmax(self.output, axis=1)
def softmax(self, z):
e_z = np.exp(z - np.max(z, axis=1, keepdims=True))
return e_z / np.sum(e_z, axis=1, keepdims=True)
# 初始化神经网络
input_size = X_train.shape[1]
hidden_size = 128
output_size = 10
nn = FeedForwardNN(input_size, hidden_size, output_size)
# 训练神经网络
nn.train(X_train, np.eye(output_size)[y_train], epochs=100)
# 测试神经网络
y_pred = nn.predict(X_test)
accuracy = np.mean(y_pred == y_test)
print("Accuracy: %.2f%%" % (accuracy * 100))
在上述代码中,我们首先加载了MNIST手写数字数据集,然后定义了一个名为FeedForwardNN的前馈神经网络类。在该类的初始化函数中,我们随机初始化了两个权重矩阵和两个偏置向量。其中,weights1和bias1是连接输入层和隐藏层的权重矩阵和偏置向量,weights2和bias2是连接隐藏层和输出层的权重矩阵和偏置向量。
在该类中,我们定义了三个主要的方法:forward、backward和train。在forward方法中,我们首先计算了隐藏层的加权输入z1,然后将其输入到tanh激活函数中,得到了隐藏层的激活输出a1。接下来,我们计算了输出层的加权输入z2,并将其输入到softmax函数中,得到了输出层的激活输出output。
在backward方法中,我们首先计算了输出误差delta2,然后使用delta2计算了连接隐藏层和输出层的权重矩阵weights2和偏置向量bias2的梯度。接着,我们使用delta2和weights2计算了连接输入层和隐藏层的权重矩阵weights1和偏置向量bias1的梯度。最后,我们使用梯度下降算法更新了四个参数。
在train方法中,我们使用前向传播和反向传播算法训练神经网络。在每个训练迭代中,我们使用当前的权重和偏置向量计算了网络的输出,并使用反向传播算法计算了参数的梯度。然后,我们使用梯度下降算法更新了参数。
在predict方法中,我们使用前向传播算法计算了网络的输出,并返回具有最大值的输出作为预测类别。
最后,我们使用训练后的神经网络进行预测,并计算了分类准确率。
以下是一个使用Python代码实现的前馈神经网络的具体实例,用于在二维空间中分类圆形和方形数据点。代码通过matplotlib库生成可视化结果,显示了训练后神经网络的分类决策边界。
import numpy as np
import matplotlib.pyplot as plt
# Generate random circular data
num_samples = 1000
theta = np.random.uniform(low=0.0, high=2*np.pi, size=num_samples)
r = np.random.uniform(low=0.0, high=1.0, size=num_samples)
x = r * np.cos(theta)
y = r * np.sin(theta)
circles = np.vstack((x, y)).T
# Generate random square data
num_samples = 1000
square_x = np.random.uniform(low=-1.0, high=1.0, size=num_samples)
square_y = np.random.uniform(low=-1.0, high=1.0, size=num_samples)
squares = np.vstack((square_x, square_y)).T
# Combine data and labels
X = np.vstack((circles, squares))
y = np.hstack((np.zeros(len(circles)), np.ones(len(squares))))
# Define the model
input_dim = 2
hidden_dim = 10
output_dim = 2
# Initialize the model parameters
W1 = np.random.randn(input_dim, hidden_dim)
b1 = np.zeros((1, hidden_dim))
W2 = np.random.randn(hidden_dim, output_dim)
b2 = np.zeros((1, output_dim))
# Define the forward propagation function
def forward_prop(model, X):
W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
# Calculate the output of the hidden layer
hidden_output = np.maximum(0, np.dot(X, W1) + b1)
# Calculate the output of the output layer
output = np.dot(hidden_output, W2) + b2
# Return the model predictions
return {'X': X, 'hidden_output': hidden_output, 'output': output}
# Define the predict function
def predict(model, X):
forward_output = forward_prop(model, X)
return np.argmax(forward_output['output'], axis=1)
# Define the calculate loss function
def calculate_loss(model, X, y):
num_examples = X.shape[0]
forward_output = forward_prop(model, X)
exp_scores = np.exp(forward_output['output'])
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
loss = -np.sum(np.log(probs[range(num_examples), y]))
return loss / num_examples
# Define the train function
def train(model, X, y, learning_rate, reg_lambda, num_epochs):
np.random.seed(0)
for i in range(num_epochs):
# Forward propagation
forward_output = forward_prop(model, X)
X, hidden_output, output = forward_output['X'], forward_output['hidden_output'], forward_output['output']
# Calculate the error at the output layer
num_examples = X.shape[0]
exp_scores = np.exp(output)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
delta3 = probs
delta3[range(num_examples), y] -= 1
# Backpropagation
dW2 = np.dot(hidden_output.T, delta3)
db2 = np.sum(delta3, axis=0, keepdims=True)
delta2 = np.dot(delta3, W2.T) * (hidden_output > 0)
dW1 = np.dot(X.T, delta2)
db1 = np.sum(delta2, axis=0)
# Regularization
dW2 += reg_lambda * W2
dW1 += reg_lambda * W1
# Update the model parameters
W1 += -learning_rate * dW1
b1 += -learning_rate * db1
W2 += -learning_rate * dW2
b2 += -learning_rate * db2
# Print the loss every 1000 epochs
if i % 1000 == 0:
loss = calculate_loss(model, X, y)
print("Loss after epoch %i: %f" % (i, loss))
# Return the trained model
return {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}
#Train the model
model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}
model = train(model, X, y, 0.01, 0.01, 10000)
#Visualize the classification boundary
h = 0.01
x_min, x_max = X[:, 0].min() - 0.1, X[:, 0].max() + 0.1
y_min, y_max = X[:, 1].min() - 0.1, X[:, 1].max() + 0.1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = predict(model, np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.scatter(circles[:, 0], circles[:, 1], color='blue')
plt.scatter(squares[:, 0], squares[:, 1], color='red')
plt.show()
在这个例子中,我们使用numpy库生成了一些随机的圆形和方形数据点,并将它们组合成一个二维的特征矩阵X。我们定义了一个包含一个隐藏层的前馈神经网络,用于将输入数据点映射到输出类别标签。我们使用反向传播算法训练了这个神经网络,通过更新模型的参数来最小化损失函数。最后,我们使用matplotlib库可视化结果,显示了训练后神经网络的分类决策边界。