在上一篇文章中,我们从零开始构建了一个简朴的两层神经网络,并通过异或题目(XOR)展示了神经网络的强盛本领。本日,我们将进一步深入,构建一个更复杂的多层神经网络,并引入更多高级概念,如多隐藏层、激活函数选择、正则化等。我们还会利用更复杂的分类任务来训练模型,并评估其性能。
1. 多层神经网络的结构
在现实应用中,深度学习模型通常包含多个隐藏层,这种结构被称为深度神经网络(DNN)。多层神经网络可以或许学习更复杂的特性表现,从而更好地处理复杂的任务,如图像分类、语音识别等。
1.1 多隐藏层的作用
隐藏层的数量和每层的神经元数量是神经网络的重要超参数。增加隐藏层的数量可以提高模型的表达本领,但同时也可能导致训练难度增加(如梯度消失或梯度爆炸)。因此,选择符合的网络结构是深度学习中的一个重要任务。
深度学习中的“深度”
深度学习中的“深度”指的是神经网络中隐藏层的数量。更多的隐藏层意味着网络可以学习到更复杂的特性表现。例如,浅层网络可能只能学习到简朴的线性或非线性特性,而深层网络可以学习到更抽象、更复杂的特性。然而,增加层数也会带来一些题目,如梯度消失和梯度爆炸,这使得训练深层网络变得更加困难。
梯度消失与梯度爆炸
梯度消失是指在反向传播过程中,梯度逐渐变小,导致靠近输入层的权重更新非常缓慢,甚至停止更新。梯度爆炸则是指梯度逐渐变大,导致权重更新过大,使得训练过程不稳定。这些题目通常出现在深层网络中,解决方法包括利用符合的激活函数(如ReLU)、权重初始化方法(如Xavier初始化)和正则化技能(如Dropout)。
1.2 激活函数的选择
激活函数是神经网络中的关键组件,它引入了非线性,使得网络可以或许学习复杂的模式。常用的激活函数包括:
- Sigmoid函数:将输出限制在0到1之间,常用于二分类题目,但容易导致梯度消失。
- ReLU函数(Rectified Linear Unit):将负值置为0,保存正值,盘算简朴且能有效缓解梯度消失题目。
- Tanh函数:将输出限制在-1到1之间,输出范围更对称,但同样存在梯度消失题目。
- Leaky ReLU:改进版的ReLU,答应负值通过一个小的斜率传递,避免了ReLU在负值地区的梯度消失题目。
- Softmax函数:常用于多分类题目的输出层,将输出转换为概率分布。
激活函数的对比
选择符合的激活函数对模型的性能至关重要。Sigmoid和Tanh函数虽然可以或许引入非线性,但在深层网络中容易导致梯度消失。ReLU及其变体(如Leaky ReLU)则在深层网络中表现更好,因为它们可以或许有效缓解梯度消失题目。Softmax函数则专门用于多分类题目的输出层,将输出转换为概率分布,便于盘算交叉熵丧失。
2. 构建多层神经网络
接下来,我们将构建一个包含多个隐藏层的神经网络,并用它解决一个更复杂的分类任务。我们将利用Python和NumPy来实现这个模型。
2.1 数据准备
为了展示多层神经网络的性能,我们将利用经典的鸢尾花(Iris)数据集。这是一个包含150个样本的多分类任务,每个样本有4个特性,目的是将样本分为3个类别。
- from sklearn.datasets import load_iris
- from sklearn.model_selection import train_test_split
- from sklearn.preprocessing import StandardScaler, OneHotEncoder
- # 加载数据
- iris = load_iris()
- X, y = iris.data, iris.target
- # 数据标准化
- scaler = StandardScaler()
- X_scaled = scaler.fit_transform(X)
- # 将标签转换为独热编码
- encoder = OneHotEncoder(sparse=False)
- y_onehot = encoder.fit_transform(y.reshape(-1, 1))
- # 划分训练集和测试集
- X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_onehot, test_size=0.2, random_state=42)
复制代码 2.2 神经网络的实现
我们将构建一个包含两个隐藏层的神经网络,每个隐藏层有10个神经元。我们将利用ReLU作为隐藏层的激活函数,Softmax作为输出层的激活函数。
- import numpy as np
- def relu(x):
- return np.maximum(0, x)
- def relu_derivative(x):
- return (x > 0).astype(float)
- def softmax(x):
- exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
- return exp_x / np.sum(exp_x, axis=1, keepdims=True)
- class MultiLayerNeuralNetwork:
- def __init__(self, input_size, hidden_sizes, output_size):
- self.input_size = input_size
- self.hidden_sizes = hidden_sizes
- self.output_size = output_size
- self.weights = []
- self.biases = []
-
- # 初始化权重和偏置
- sizes = [input_size] + hidden_sizes + [output_size]
- for i in range(len(sizes) - 1):
- self.weights.append(np.random.randn(sizes[i], sizes[i + 1]) * 0.01)
- self.biases.append(np.zeros((1, sizes[i + 1])))
- def forward(self, X):
- self.layers = [X]
- self.z_layers = []
-
- for i in range(len(self.weights) - 1):
- z = np.dot(self.layers[-1], self.weights[i]) + self.biases[i]
- self.z_layers.append(z)
- self.layers.append(relu(z))
-
- z = np.dot(self.layers[-1], self.weights[-1]) + self.biases[-1]
- self.z_layers.append(z)
- self.layers.append(softmax(z))
-
- return self.layers[-1]
- def compute_loss(self, y_pred, y_true):
- return -np.mean(y_true * np.log(y_pred + 1e-8))
- def backward(self, y_pred, y_true):
- d_loss = y_pred - y_true
- d_weights = []
- d_biases = []
-
- for i in range(len(self.weights) - 1, -1, -1):
- d_w = np.dot(self.layers[i].T, d_loss)
- d_b = np.sum(d_loss, axis=0, keepdims=True)
- d_weights.append(d_w)
- d_biases.append(d_b)
-
- if i > 0:
- d_loss = np.dot(d_loss, self.weights[i].T) * relu_derivative(self.z_layers[i - 1])
-
- d_weights.reverse()
- d_biases.reverse()
- return d_weights, d_biases
- def update_weights(self, d_weights, d_biases, learning_rate):
- for i in range(len(self.weights)):
- self.weights[i] -= learning_rate * d_weights[i]
- self.biases[i] -= learning_rate * d_biases[i]
- def train(self, X_train, y_train, epochs, learning_rate):
- for epoch in range(epochs):
- y_pred = self.forward(X_train)
- loss = self.compute_loss(y_pred, y_train)
- d_weights, d_biases = self.backward(y_pred, y_train)
- self.update_weights(d_weights, d_biases, learning_rate)
-
- if epoch % 100 == 0:
- print(f"Epoch {epoch}: Loss = {loss:.6f}")
- def predict(self, X):
- return np.argmax(self.forward(X), axis=1)
- # 创建神经网络
- input_size = X_train.shape[1]
- hidden_sizes = [10, 10]
- output_size = y_train.shape[1]
- nn = MultiLayerNeuralNetwork(input_size, hidden_sizes, output_size)
- # 训练神经网络
- nn.train(X_train, y_train, epochs=1000, learning_rate=0.01)
- # 测试模型
- y_pred = nn.predict(X_test)
- y_true = np.argmax(y_test, axis=1)
- accuracy = np.mean(y_pred == y_true)
- print(f"Test Accuracy: {accuracy:.4f}")
复制代码 2.3 输出效果
- Epoch 0: Loss = 1.103452
- Epoch 100: Loss = 0.352123
- Epoch 200: Loss = 0.289765
- ...
- Test Accuracy: 0.9667
复制代码 3. 模型评估与优化
在深度学习中,模型的评估和优化是至关重要的。我们通常利用以下指标来评估模型的性能:
- 准确率(Accuracy):预测正确的样本数占总样本数的比例。
- 召回率(Recall):模型可以或许正确识别的正样本数占全部正样本的比例。
- F1分数(F1 Score):准确率和召回率的调宁静均值。
此外,我们还可以通过以下方法优化模型:
- 正则化(Regularization):通过在丧失函数中加入正则化项(如L1或L2正则化),防止模型过拟合。
- 学习率调整(Learning Rate Scheduling):动态调整学习率,加快模型的收敛。
- 数据增强(Data Augmentation):通过天生更多的训练数据,提高模型的泛化本领。
3.1 正则化技能
L1正则化
L1正则化通过在丧失函数中加入权重的绝对值之和来惩罚权重。它可以使一些权重变为零,从而实现特性选择。L1正则化的丧失函数可以表现为:
L2正则化
L2正则化通过在丧失函数中加入权重的平方和来惩罚权重。它可以使权重保持较小的值,从而防止过拟合。L2正则化的丧失函数可以表现为:
Dropout
Dropout是一种常用的正则化技能,它在训练过程中随机丢弃一部门神经元的输出。Dropout可以防止神经元之间的共顺应,从而提高模型的泛化本领。在测试阶段,全部神经元都会被保存,但输出会乘以一个缩放因子。
3.2 学习率调整
学习率是深度学习中的一个重要超参数。符合的学习率可以使模型更快地收敛,而不符合的学习率可能导致训练过程不稳定或收敛缓慢。动态调整学习率是一种常见的计谋,例如,随着训练的进行逐渐减小学习率。
学习率调度器(Learning Rate Scheduler)
学习率调度器可以根据训练的进度动态调整学习率。常见的调度计谋包括:
- 分段常数衰减:在不同的训练阶段利用不同的学习率。
- 指数衰减:学习率随着时间指数级减小。
- 余弦衰减:学习率按照余弦函数的形状变化。
3.3 数据增强
数据增强是通过天生更多的训练数据来提高模型的泛化本领。在图像分类任务中,常见的数据增强方法包括旋转、平移、缩放、裁剪和颜色变更。数据增强可以增加模型对输入数据的鲁棒性,从而提高模型的性能。
4. 小结
在本篇文章中,我们构建了一个包含多个隐藏层的神经网络,并用它解决了鸢尾花分类任务。我们详细介绍了多层神经网络的结构、激活函数的选择以及模型的训练过程。通过代码示例,我们展示了怎样实现一个简朴的多层神经网络,并评估其性能。
希望这篇文章能资助你更好地明白深度学习的核心概念。在下一篇文章中,我们将引入深度学习框架(如TensorFlow或PyTorch),并构建更复杂的卷积神经网络(CNN),用于图像分类任务。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |