以下是一个使用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优化技术来训练神经网络。您可以根据需要更改这些超参数,以获得最佳的性能

BP算法的神经网络程序并测试ReLu、Maxout、RMSProp、Momentum、dropout

原文地址: https://www.cveoy.top/t/topic/cZBR 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录