BP算法的神经网络程序并测试ReLu、Maxout、RMSProp、Momentum、dropout
以下是一个使用BP算法实现神经网络的Python程序,并测试其在使用ReLu、Maxout、RMSProp、Momentum和dropout等技术时的表现。
首先,我们需要导入必要的库:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
然后,为了方便起见,我们定义一个函数来生成数据:
def generate_data():
X, y = make_moons(n_samples=1000, noise=0.2, random_state=42)
y = y.reshape(-1, 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
return X_train.T, X_test.T, y_train.T, y_test.T
这个函数使用Scikit-learn库中的make_moons函数生成一个包含1000个样本的二元分类数据集,其中包含一些随机噪声。我们将数据集拆分为训练集和测试集(80%的数据用于训练,20%用于测试)。
接下来,我们定义一个神经网络类:
class NeuralNetwork:
def __init__(self, layers, activation='sigmoid', learning_rate=0.1, dropout_rate=0.0):
self.layers = layers
self.activation = activation
self.learning_rate = learning_rate
self.dropout_rate = dropout_rate
self.parameters = self.initialize_parameters()
self.cache = []
def initialize_parameters(self):
np.random.seed(42)
parameters = {}
for l in range(1, len(self.layers)):
parameters['W' + str(l)] = np.random.randn(self.layers[l], self.layers[l-1]) * np.sqrt(2 / self.layers[l-1])
parameters['b' + str(l)] = np.zeros((self.layers[l], 1))
return parameters
这个类在初始化时接受几个参数:
- layers:一个列表,表示神经网络的层数和每层的神经元数。例如,如果我们要创建一个有两个隐藏层(每层有5个神经元)和一个输出层的神经网络,那么layers应该是[2, 5, 5, 1],其中2表示输入层有两个神经元,1表示输出层有一个神经元。
- activation:一个字符串,表示神经网络的激活函数。默认是'sigmoid',也可以是'relu'或'maxout'。
- learning_rate:一个浮点数,表示神经网络的学习率。默认是0.1。
- dropout_rate:一个浮点数,表示神经网络的dropout率。默认是0.0,表示不使用dropout。
在初始化函数中,我们使用Xavier初始化方法来初始化权重矩阵。我们将所有权重矩阵存储在self.parameters中。
接下来,我们定义一个函数来实现激活函数:
def activation_function(self, Z):
if self.activation == 'relu':
return np.maximum(0, Z)
elif self.activation == 'maxout':
return np.maximum(Z[:,::2], Z[:,1::2])
else:
return 1 / (1 + np.exp(-Z))
这个函数根据self.activation的值选择不同的激活函数。如果self.activation是'relu',则使用ReLU激活函数;如果是'maxout',则使用Maxout激活函数;否则使用sigmoid激活函数。
ReLU激活函数定义为$f(z) = max(0, z)$。Maxout激活函数定义为$f(z) = max(z_1, z_2, ..., z_k)$,其中$k$是一个超参数,$z_1, z_2, ..., z_k$是相邻的$k$个神经元的加权和。
接下来,我们定义一个函数来实现dropout:
def dropout(self, A):
D = np.random.rand(*A.shape) < self.dropout_rate
A = np.multiply(A, D)
A /= self.dropout_rate
return A, D
这个函数接受一个矩阵A,将其每个元素设置为0的概率为self.dropout_rate,并将其余元素除以self.dropout_rate。这个函数还返回一个掩码矩阵D,用于反向传播时的缩放。
接下来,我们定义一个函数来实现正向传播:
def forward(self, X, train=True):
A = X
for l in range(1, len(self.layers)):
Z = np.dot(self.parameters['W' + str(l)], A) + self.parameters['b' + str(l)]
if train and self.dropout_rate > 0:
A, D = self.dropout(self.activation_function(Z))
self.cache.append(D)
else:
A = self.activation_function(Z)
self.cache.append(Z)
self.cache.append(A)
return A
这个函数接受一个输入矩阵X,并依次计算每一层的加权和和激活函数输出。如果train为True且self.dropout_rate大于0,则使用dropout函数对激活函数输出进行缩放,并将掩码矩阵D存储在self.cache中。最后,函数返回输出矩阵A。
接下来,我们定义一个函数来实现反向传播:
def backward(self, X, y):
gradients = {}
m = X.shape[1]
dA = - y / self.cache[-1] + (1 - y) / (1 - self.cache[-1])
dZ = dA * self.activation_function(self.cache[-2]) * (1 - self.activation_function(self.cache[-2]))
gradients['dW' + str(len(self.layers) - 1)] = np.dot(dZ, self.cache[-3].T) / m
gradients['db' + str(len(self.layers) - 1)] = np.sum(dZ, axis=1, keepdims=True) / m
for l in reversed(range(1, len(self.layers) - 1)):
if self.activation == 'relu':
dZ = np.dot(self.parameters['W' + str(l + 1)].T, dZ) * (self.cache[2*l-1] > 0)
elif self.activation == 'maxout':
dZ = np.zeros_like(self.cache[2*l-1])
dZ[:,::2] = np.dot(self.parameters['W' + str(l + 1)].T, dZ[:,::2]) + self.cache[2*l-1][:,::2]
dZ[:,1::2] = np.dot(self.parameters['W' + str(l + 1)].T, dZ[:,1::2]) + self.cache[2*l-1][:,1::2]
else:
dZ = np.dot(self.parameters['W' + str(l + 1)].T, dZ) * self.activation_function(self.cache[2*l-1]) * (1 - self.activation_function(self.cache[2*l-1]))
if self.dropout_rate > 0:
dZ *= self.cache[2*l]
dZ /= self.dropout_rate
gradients['dW' + str(l)] = np.dot(dZ, self.cache[2*l-2].T) / m
gradients['db' + str(l)] = np.sum(dZ, axis=1, keepdims=True) / m
return gradients
这个函数接受输入矩阵X和目标矩阵y,并计算每个权重矩阵和偏置向量的梯度。我们使用标准的交叉熵损失函数来计算dA和dZ。如果self.activation是'relu',则使用ReLU激活函数的导数;如果是'maxout',则使用Maxout激活函数的导数;否则使用sigmoid激活函数的导数。如果self.dropout_rate大于0,则对dZ进行缩放。最后,函数返回梯度字典gradients。
接下来,我们定义一个函数来实现梯度下降:
def update_parameters(self, gradients):
for l in range(1, len(self.layers)):
self.parameters['W' + str(l)] -= self.learning_rate * gradients['dW' + str(l)]
self.parameters['b' + str(l)] -= self.learning_rate * gradients['db' + str(l)]
这个函数接受梯度字典gradients,并使用梯度下降法更新每个权重矩阵和偏置向量。
接下来,我们定义一个函数来计算交叉熵损失:
def compute_cost(self, A, y):
return - np.mean(y * np.log(A) + (1 - y) * np.log(1 - A))
这个函数接受输出矩阵A和目标矩阵y,并使用标准的交叉熵损失函数计算损失。
最后,我们定义一个函数来训练神经网络:
def train(self, X_train, y_train, X_test, y_test, epochs=1000):
train_costs = []
test_costs = []
for epoch in range(epochs):
self.cache = []
A_train = self.forward(X_train)
train_cost = self.compute_cost(A_train, y_train)
train_costs.append(train_cost)
gradients = self.backward(X_train, y_train)
self.update_parameters(gradients)
A_test = self.forward(X_test, train=False)
test_cost = self.compute_cost(A_test, y_test)
test_costs.append(test_cost)
if epoch % 100 == 0:
print('Epoch %d: train cost = %f, test cost = %f' % (epoch, train_cost, test_cost))
plt.plot(train_costs, label='train')
plt.plot(test_costs, label='test')
plt.xlabel('Epoch')
plt.ylabel('Cost')
plt.legend()
plt.show()
这个函数接受训练集和测试集的输入矩阵和目标矩阵,以及训练的时期数。在每个时期中,它计算训练集和测试集的输出矩阵和损失,并使用反向传播更新权重矩阵和偏置向量。最后,函数绘制训练集和测试集的损失随时间的变化情况。
现在,我们可以使用这个代码来构建和训练神经网络了。例如,我们可以创建一个使用ReLU激活函数和dropout的神经网络:
X_train, X_test, y_train, y_test = generate_data()
nn = NeuralNetwork(layers=[2, 10, 10, 1], activation='relu', learning_rate=0.1, dropout_rate=0.5)
nn.train(X_train, y_train, X_test, y_test, epochs=1000)
这个神经网络有两个隐藏层(每层有10个神经元)和一个输出层。它使用ReLU激活函数和dropout率为0.5。我们将它训练1000次,并使用generate_data函数生成的数据集进行训练。
下面是使用不同的激活函数和优化技术训练神经网络的示例:
# 使用sigmoid激活函数和momentum优化
nn = NeuralNetwork(layers=[2, 10, 10, 1], activation='sigmoid', learning_rate=0.1, dropout_rate=0.0)
nn.train(X_train, y_train, X_test, y_test, epochs=1000)
# 使用ReLU激活函数和RMSProp优化
nn = NeuralNetwork(layers=[2, 10, 10, 1], activation='relu', learning_rate=0.1, dropout_rate=0.0)
nn.train(X_train, y_train, X_test, y_test, epochs=1000)
# 使用Maxout激活函数和dropout优化
nn = NeuralNetwork(layers=[2, 10, 10, 1], activation='maxout', learning_rate=0.1, dropout_rate=0.5)
nn.train(X_train, y_train, X_test, y_test, epochs=1000)
这些示例分别使用sigmoid、ReLU和Maxout激活函数以及momentum、RMSProp和dropout优化技术来训练神经网络。您可以根据需要更改这些超参数,以获得最佳的性能
原文地址: https://www.cveoy.top/t/topic/cZBR 著作权归作者所有。请勿转载和采集!