从原理到实战:一文读懂人工神经网络(ANN)算法
在人工智能的浩瀚星空中,人工神经网络(Artificial Neural Network, ANN)无疑是最耀眼的那颗星。作为深度学习的基础,ANN 不仅在图像识别、自然语言处理等领域大放异彩,更是我们理解现代 AI 的必经之路。
今天,我们就来深入剖析 ANN 的核心原理,并手把手带你实现一个简单的神经网络。
什么是人工神经网络?
简单来说,人工神经网络是一种受生物神经系统启发而构建的计算模型。它模仿了人脑神经元的工作方式,通过大量的节点(神经元)相互连接,形成复杂的网络结构,从而具备强大的学习和非线性映射能力。
你可以把 ANN 想象成一个极其复杂的函数,它接收输入数据(如图片像素),经过层层计算,最终输出结果(如“这是一只猫”)。
核心组成:神经网络的“积木”
一个典型的 ANN 由以下三个部分组成:
- 输入层:负责接收外部数据。例如,一张 28x28 像素的灰度图,展平后就是 784 个输入节点。
- 隐藏层:位于输入层和输出层之间,是网络的核心。一个网络可以包含一个或多个隐藏层。正是这些层赋予了网络强大的表达能力。
- 输出层:输出最终的预测结果。例如,在 MNIST 手写数字识别任务中,输出层有 10 个节点,分别代表数字 0 到 9。
神经元:网络的“基本单元”
神经元是 ANN 的基本计算单元。它的工作原理可以概括为两步:
- 加权求和:接收来自上一层所有神经元的输出,每个输出都乘以一个对应的权重,然后将它们全部加起来,再加上一个偏置项。
- 激活函数:将加权求和的结果输入到一个激活函数中,得到该神经元的最终输出。
用数学公式表示就是:
$y = f(\sum_{i=1}^{n} w_i x_i + b)$
其中,$x_i$ 是输入,$w_i$ 是权重,$b$ 是偏置,$f$ 是激活函数,$y$ 是输出。
激活函数:注入非线性
如果网络中只有线性计算,那么无论多少层,最终都可以被简化为一个单层网络。激活函数的作用就是引入非线性因素,让网络能够学习和拟合复杂的函数关系。
常见的激活函数有:
- Sigmoid:将输出压缩到 (0, 1) 区间,常用于二分类的输出层。
- ReLU:当输入大于 0 时,输出等于输入;否则输出 0。计算简单,能有效缓解梯度消失问题,是目前最常用的激活函数。
- Tanh:将输出压缩到 (-1, 1) 区间,以 0 为中心,收敛速度通常比 Sigmoid 快。
训练过程:前向传播与反向传播
神经网络的训练过程,本质上就是不断调整网络中所有权重和偏置的过程,以使预测结果尽可能接近真实值。这个过程分为两步:
- 前向传播:数据从输入层开始,经过隐藏层,最终到达输出层,得到一个预测值。
- 反向传播:计算预测值与真实值之间的误差(通过损失函数,如均方误差或交叉熵),然后将这个误差从输出层反向传播回网络,利用链式法则计算每个权重和偏置对总误差的“贡献”(即梯度)。最后,使用优化器(如随机梯度下降)根据梯度来更新所有参数,以减小误差。
这个过程会不断迭代,直到模型的误差收敛到一个可接受的范围。
代码实战:用 Python 和 NumPy 实现一个简单的 ANN
下面,我们将使用 Python 和 NumPy 库,从零开始实现一个简单的神经网络,来解决一个多分类问题。
1. 生成模拟数据
我们将生成三组二维数据,每组数据代表一个类别。
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子,确保结果可复现
np.random.seed(42)
# 生成三组数据
class0 = np.random.normal(loc=, scale=0.5, size=(500, 2))
class1 = np.random.normal(loc=, scale=0.5, size=(500, 2))
class2 = np.random.normal(loc=, scale=0.5, size=(500, 2))
# 合并数据和标签
all_data = np.vstack([class0, class1, class2])
all_labels = np.hstack([np.zeros(500), np.ones(500), np.ones(500) * 2])
# 打乱数据
shuffle_idx = np.random.permutation(len(all_data))
all_data = all_data[shuffle_idx]
all_labels = all_labels[shuffle_idx]
# 划分训练集和测试集
split_idx = int(len(all_data) * 0.8)
train_data, test_data = all_data[:split_idx], all_data[split_idx:]
train_labels, test_labels = all_labels[:split_idx], all_labels[split_idx:]
# 可视化数据
plt.figure(figsize=(8, 6))
plt.scatter(train_data[train_labels == 0, 0], train_data[train_labels == 0, 1], label='Class 0')
plt.scatter(train_data[train_labels == 1, 0], train_data[train_labels == 1, 1], label='Class 1')
plt.scatter(train_data[train_labels == 2, 0], train_data[train_labels == 2, 1], label='Class 2')
plt.legend()
plt.title('2D Synthetic Data')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
2. 定义神经网络类
我们将创建一个 NeuralNetwork 类,包含初始化、前向传播和反向传播方法。
class NeuralNetwork:
def __init__(self, layers):
"""
初始化神经网络
:param layers: 一个列表,包含每层的神经元数量,例如
"""
self.layers = layers
self.weights = []
self.biases = []
# 使用 Xavier 初始化权重
for i in range(len(layers) - 1):
limit = np.sqrt(6 / (layers[i] + layers[i+1]))
self.weights.append(np.random.uniform(-limit, limit, (layers[i], layers[i+1])))
self.biases.append(np.zeros((1, layers[i+1])))
def sigmoid(self, z):
# 使用 clip 防止数值溢出
return 1 / (1 + np.exp(-np.clip(z, -500, 500)))
def sigmoid_derivative(self, a):
return a * (1 - a)
def forward(self, X):
"""
前向传播
:param X: 输入数据
:return: 网络的最终输出
"""
self.activations = [X]
# 隐藏层使用 tanh,输出层使用 sigmoid
for i in range(len(self.weights) - 1):
z = np.dot(self.activations[-1], self.weights[i]) + self.biases[i]
self.activations.append(np.tanh(z))
# 输出层
z = np.dot(self.activations[-1], self.weights[-1]) + self.biases[-1]
self.activations.append(self.sigmoid(z))
return self.activations[-1]
def backward(self, X, y, learning_rate):
"""
反向传播
:param X: 输入数据
:param y: 真实标签 (独热编码)
:param learning_rate: 学习率
"""
m = X.shape
# 计算输出层的误差
delta = self.activations[-1] - y
# 从后向前计算每一层的梯度并更新参数
for i in range(len(self.weights) - 1, -1, -1):
dW = np.dot(self.activations[i].T, delta) / m
db = np.sum(delta, axis=0, keepdims=True) / m
self.weights[i] -= learning_rate * dW
self.biases[i] -= learning_rate * db
if i > 0:
# 计算上一层的误差
if i == len(self.weights) - 1:
# 输出层到隐藏层,激活函数是 sigmoid
delta = np.dot(delta, self.weights[i].T) * self.sigmoid_derivative(self.activations[i])
else:
# 隐藏层之间,激活函数是 tanh
delta = np.dot(delta, self.weights[i].T) * (1 - self.activations[i]**2)
# 辅助函数:将标签转换为独热编码
def one_hot_encode(y, num_classes):
return np.eye(num_classes)[y.astype(int)]
3. 训练模型
# 定义网络结构:输入层2个节点,隐藏层4个节点,输出层3个节点
nn = NeuralNetwork()
# 训练参数
epochs = 1000
learning_rate = 1.0
# 对标签进行独热编码
train_labels_one_hot = one_hot_encode(train_labels, 3)
# 开始训练
for epoch in range(epochs):
nn.forward(train_data)
nn.backward(train_data, train_labels_one_hot, learning_rate)
if (epoch + 1) % 200 == 0:
# 计算当前损失
output = nn.forward(train_data)
loss = np.mean((output - train_labels_one_hot) ** 2)
print(f'Epoch {epoch + 1}, Loss: {loss:.4f}')
4. 评估模型
# 在测试集上进行预测
test_output = nn.forward(test_data)
# 获取预测类别
predictions = np.argmax(test_output, axis=1)
# 计算准确率
accuracy = np.mean(predictions == test_labels)
print(f'Test Accuracy: {accuracy:.2%}')
总结
本文我们从零开始,介绍了人工神经网络的基本概念、核心组件和训练机制,并通过一个完整的 Python 示例,展示了如何实现一个简单的 ANN。
理解 ANN 是通往深度学习世界的第一步。在此基础上,你可以进一步探索更复杂的网络结构,如卷积神经网络(CNN)和循环神经网络(RNN)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)