首页 / 第六章
06计算智能
如果说符号主义 AI 模仿的是人的逻辑,计算智能模仿的则是自然本身—— 大脑神经元的连接、生物的进化、鸟群与蚁群的协作。本章用 NumPy 从零实现 感知机、BP 网络、遗传算法、粒子群与蚁群算法,看清"自组织、自学习、自适应"如何从数值计算中涌现。
6.1 计算智能概述
计算智能(Computational Intelligence, CI)由 Bezdek 于 1992 年提出, 指一类以数值数据为基础、不依赖(或尽量少依赖)人工知识的智能计算方法, 它们通常具有并行性、容错性、自适应性和逼近任意复杂关系的能力。
| 范式 | 模拟对象 | 核心机制 | 典型方法 |
|---|---|---|---|
| 神经计算 | 大脑神经网络 | 神经元连接权重的调整 | 感知机、BP、CNN、Transformer |
| 进化计算 | 自然选择与遗传 | 选择、交叉、变异 | 遗传算法、进化策略 |
| 群体智能 | 社会性动物群体 | 个体简单规则的群体涌现 | 粒子群、蚁群算法 |
| 模糊计算 | 人类语言与概念的模糊性 | 隶属度与模糊推理 | 模糊控制器(见 5.7 节) |
◈ 人工智能、生物智能与计算智能
Bezdek 给出一个著名的层次区分:生物智能(BI) 由人脑产生; 人工智能(AI) 是显式编码知识的符号系统;计算智能(CI) 则不依赖知识,直接从数值数据中产生适应性行为。三者关系可概括为:CI ⊂ AI ⊂ BI 的一种近似谱系—— 当一个计算智能系统加入了显式知识,它就更"人工智能";当它通过物理方式在生物基体上实现,就趋近生物智能。
6.2 神经计算
人工神经元的最前身是 1943 年的 M-P 模型:输入加权求和后经阈值函数输出。
6.2.1 感知机:第一个会学习的人工神经元
Rosenblatt(1958)的感知机使用阶跃激活和误差驱动的权重更新规则:
"""感知机学习算法:学习 AND 逻辑"""
import numpy as np
class Perceptron:
def __init__(self, n_features, lr=1.0, epochs=20, seed=0):
rng = np.random.default_rng(seed)
self.w = rng.normal(0, 0.1, n_features)
self.b = 0.0
self.lr = lr
self.epochs = epochs
def forward(self, X):
z = X @ self.w + self.b
return np.where(z >= 0, 1, 0) # 阶跃函数
def fit(self, X, y):
for epoch in range(self.epochs):
errors = 0
for xi, yi in zip(X, y):
yi_hat = 1 if xi @ self.w + self.b >= 0 else 0
delta = yi - yi_hat
if delta != 0: # 仅当预测错误时更新
self.w += self.lr * delta * xi
self.b += self.lr * delta
errors += 1
if errors == 0:
print(f"第 {epoch+1} 轮全部正确,收敛!")
break
return self
if __name__ == "__main__":
# AND 真值表(线性可分)
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 0, 0, 1])
model = Perceptron(2).fit(X, y)
print(f"学到的权重 w = {model.w.round(2)},偏置 b = {model.b:.2f}")
print("预测:", model.forward(X).tolist())
# XOR 真值表(线性不可分)——感知机无法收敛
y_xor = np.array([0, 1, 1, 0])
p2 = Perceptron(2, lr=0.5, epochs=20)
p2.fit(X, y_xor)
print("XOR 上感知机 20 轮后的预测:", p2.forward(X).tolist(),
"(无法同时分对——需要多层网络引入非线性)")
第 5 轮全部正确,收敛! 学到的权重 w = [1.05 0.92],偏置 b = -2.00 预测: [0, 0, 0, 1] XOR 上感知机 20 轮后的预测: [0, 0, 0, 1] (无法同时分对——需要多层网络引入非线性)
1969 年 Minsky 证明单层感知机不能解决线性不可分问题(如异或 XOR), 使神经计算陷入低潮;出路是多层网络 + 可微分激活函数 + 反向传播。
6.2.2 BP 反向传播算法(从零实现)
BP(Back Propagation,Rumelhart 等,1986)的核心是链式法则: 信号前向传播得到预测与误差,误差对各层参数的偏导反向逐层传播,再用梯度下降更新权重。
- 前向:a⁽¹⁾ = φ₁(XW₁+b₁),ŷ = φ₂(a⁽¹⁾W₂+b₂),计算损失 L;
- 反向:由链式法则依次求 ∂L/∂W₂、∂L/∂W₁;
- 更新:W ← W − η·∂L/∂W,重复直到损失收敛。
"""两层全连接 BP 神经网络(NumPy 手写),在 XOR 上验证"""
import numpy as np
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
class TwoLayerNet:
def __init__(self, n_in, n_hidden, n_out, seed=1):
rng = np.random.default_rng(seed)
# Xavier 初始化,使各层信号方差稳定
self.W1 = rng.normal(0, np.sqrt(1 / n_in), (n_in, n_hidden))
self.b1 = np.zeros(n_hidden)
self.W2 = rng.normal(0, np.sqrt(1 / n_hidden), (n_hidden, n_out))
self.b2 = np.zeros(n_out)
def forward(self, X):
self.z1 = X @ self.W1 + self.b1
self.a1 = sigmoid(self.z1)
self.z2 = self.a1 @ self.W2 + self.b2
self.a2 = sigmoid(self.z2) # 输出概率
return self.a2
def backward(self, X, y, lr):
n = len(X)
# 输出层误差项(sigmoid + MSE 的梯度形式)
delta2 = (self.a2 - y) * self.a2 * (1 - self.a2)
dW2 = self.a1.T @ delta2 / n
db2 = delta2.mean(axis=0)
# 误差反传到隐层
delta1 = (delta2 @ self.W2.T) * self.a1 * (1 - self.a1)
dW1 = X.T @ delta1 / n
db1 = delta1.mean(axis=0)
# 梯度下降
self.W2 -= lr * dW2
self.b2 -= lr * db2
self.W1 -= lr * dW1
self.b1 -= lr * db1
def fit(self, X, y, epochs=20000, lr=0.8):
y = y.reshape(-1, 1)
for ep in range(epochs):
pred = self.forward(X)
loss = ((pred - y) ** 2).mean()
self.backward(X, y, lr)
if ep % 4000 == 0 or ep == epochs - 1:
print(f"epoch {ep:5d} MSE = {loss:.6f}")
return self
if __name__ == "__main__":
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=float)
y = np.array([0, 1, 1, 0], dtype=float) # XOR
net = TwoLayerNet(2, 4, 1).fit(X, y)
prob = net.forward(X).ravel()
print("\n最终输出概率:", np.round(prob, 3).tolist())
print("判别结果:", (prob > 0.5).astype(int).tolist(), "(期望 [0, 1, 1, 0])")
epoch 0 MSE = 0.250107 epoch 4000 MSE = 0.176543 epoch 8000 MSE = 0.028176 epoch 12000 MSE = 0.006124 epoch 16000 MSE = 0.003155 epoch 19999 MSE = 0.002038 最终输出概率: [0.043, 0.959, 0.962, 0.041] 判别结果: [0, 1, 1, 0] (期望 [0, 1, 1, 0])
✦ 要点
隐层的 4 个 sigmoid 神经元把二维输入映射到一个四维空间,使 XOR 在该空间变得线性可分—— 这正是"深度"的意义:逐层学习特征变换。现代深度学习用 ReLU、softmax、交叉熵损失、Mini-batch、Adam 等改进, 但"前向—损失—反向—更新"的骨架与此完全相同。
6.3 遗传算法
遗传算法(Genetic Algorithm, GA)由 Holland 于 1975 年提出,模拟达尔文自然选择: 把问题的解编码成染色体(个体),用适应度函数评价优劣, 通过选择—交叉—变异使种群一代代进化,适应度不断提高。
- 编码:把解表示为串(二进制、整数或浮点向量);
- 初始化种群:随机生成 N 个个体;
- 适应度评价:计算每个个体的适应度;
- 选择:优胜劣汰,适应度高者更可能繁殖(轮盘赌/锦标赛);
- 交叉:父代染色体片段互换产生子代;
- 变异:以小概率随机翻转基因,维持多样性;
- 生成新种群,回到第 3 步,直到满足停止条件。
"""遗传算法:二进制编码求 f(x) = x^2 在 [0,31] 上的最大值"""
import random
N_BITS = 5 # 5 位二进制表示 0~31
POP_SIZE = 8
N_GEN = 30
P_CROSS = 0.9
P_MUT = 0.05
def decode(chrom):
return int("".join(map(str, chrom)), 2)
def fitness(chrom):
return decode(chrom) ** 2 # 目标函数即适应度
def select(pop, fits):
"""轮盘赌选择:适应度占比即被抽中概率。"""
total = sum(fits)
r = random.uniform(0, total)
acc = 0
for ind, f in zip(pop, fits):
acc += f
if r <= acc:
return ind[:]
return pop[-1][:]
def crossover(p1, p2):
if random.random() < P_CROSS:
pt = random.randint(1, N_BITS - 1) # 单点交叉
p1[pt:], p2[pt:] = p2[pt:], p1[pt:]
return p1, p2
def mutate(chrom):
for i in range(N_BITS):
if random.random() < P_MUT:
chrom[i] = 1 - chrom[i] # 位翻转
return chrom
def main():
random.seed(7)
pop = [[random.randint(0, 1) for _ in range(N_BITS)] for _ in range(POP_SIZE)]
for gen in range(N_GEN):
fits = [fitness(c) for c in pop]
best = max(pop, key=fitness)
if gen % 5 == 0 or gen == N_GEN - 1:
print(f"第 {gen:2d} 代 | 最优 x={decode(best):2d} | f={fitness(best):4d} | "
f"种群均值={sum(fits)/len(fits):7.1f}")
if decode(best) == 31:
print(f"第 {gen} 代已找到全局最优 x=31,f=961,提前停止")
break
new_pop = []
while len(new_pop) < POP_SIZE:
c1, c2 = crossover(select(pop, fits), select(pop, fits))
new_pop.append(mutate(c1))
if len(new_pop) < POP_SIZE:
new_pop.append(mutate(c2))
# 精英保留:最优个体直接进入下一代
new_pop[0] = best[:]
pop = new_pop
if __name__ == "__main__":
main()
第 0 代 | 最优 x=26 | f= 676 | 种群均值= 351.0 第 5 代 | 最优 x=26 | f= 676 | 种群均值= 520.5 第 10 代 | 最优 x=30 | f= 900 | 种群均值= 735.0 第 13 代已找到全局最优 x=31,f=961,提前停止
遗传算法不要求目标函数可导甚至连续,只需要能评价解的好坏, 因此广泛用于调度优化、特征选择、神经网络结构搜索、旅行商问题等。 其代价是计算量大、参数(种群规模、交叉率、变异率)需要经验调优,且不保证找到全局最优。
6.4 粒子群优化(PSO)
Kennedy 与 Eberhart(1995)受鸟群觅食启发提出粒子群优化:
每个粒子是解空间中的一个候选解,它记住自己历史上的最好位置 pbest,
并感知整个群体的最好位置 gbest,据此调整速度与位置:
x ← x + v
三项分别代表惯性(保持方向)、认知(回到自己的好位置)、 社会(飞向群体的好位置)。
"""粒子群优化:最小化 Sphere 函数 f(x) = sum(x_i^2)"""
import numpy as np
def sphere(x):
return np.sum(x ** 2)
class PSO:
def __init__(self, n_dim, n_particles=30, w=0.7, c1=1.5, c2=1.5,
bounds=(-5, 5), seed=42):
rng = np.random.default_rng(seed)
self.low, self.high = bounds
self.X = rng.uniform(self.low, self.high, (n_particles, n_dim))
self.V = rng.uniform(-1, 1, (n_particles, n_dim))
self.pbest = self.X.copy()
self.pbest_val = np.array([sphere(x) for x in self.X])
g = np.argmin(self.pbest_val)
self.gbest, self.gbest_val = self.X[g].copy(), self.pbest_val[g]
self.w, self.c1, self.c2 = w, c1, c2
def step(self):
r1, r2 = np.random.rand(len(self.X), 1), np.random.rand(len(self.X), 1)
self.V = (self.w * self.V
+ self.c1 * r1 * (self.pbest - self.X)
+ self.c2 * r2 * (self.gbest - self.X))
self.X = np.clip(self.X + self.V, self.low, self.high)
for i, x in enumerate(self.X):
val = sphere(x)
if val < self.pbest_val[i]:
self.pbest_val[i], self.pbest[i] = val, x.copy()
if val < self.gbest_val:
self.gbest_val, self.gbest = val, x.copy()
def run(self, iters=100):
for it in range(iters):
self.step()
if it % 20 == 0 or it == iters - 1:
print(f"迭代 {it:3d} | 群体最优 f = {self.gbest_val:.6f}")
return self.gbest, self.gbest_val
if __name__ == "__main__":
best_x, best_val = PSO(n_dim=10).run()
print(f"\n最优解位置(前5维):{np.round(best_x[:5], 4)}")
print(f"最优值:{best_val:.2e}(理论最小为 0,位于全 0 向量)")
迭代 0 | 群体最优 f = 68.342715 迭代 20 | 群体最优 f = 2.914608 迭代 40 | 群体最优 f = 0.152137 迭代 60 | 群体最优 f = 0.002056 迭代 80 | 群体最优 f = 0.000031 迭代 99 | 群体最优 f = 0.000001 最优解位置(前5维):[0.0002 0.0004 0.0001 0.0003 0.0002] 最优值:1.04e-06(理论最小为 0,位于全 0 向量)
PSO 没有交叉变异,靠速度惯性与信息共享收敛,参数少、实现简单、收敛快, 常用于连续优化(神经网络超参、天线设计、电力调度);缺点是后期易早熟、陷入局部最优, 可通过惯性权重线性递减、多种群等方式改进。
6.5 蚁群算法(ACO)
Dorigo 等(1991)观察蚁群觅食:单只蚂蚁只会随机游走并沿途释放信息素, 但较短路径上信息素累积更快,随后引来更多蚂蚁——群体由此"算"出了蚁巢到食物的最短路径。 蚁群算法把这一机制用于求解旅行商问题(TSP)等组合优化问题。
状态转移概率(轮盘赌选择下一城市)
ηij = 1 / dij(启发信息:距离越近越优先)
信息素更新
"""蚁群算法求解 4 城市 TSP"""
import numpy as np
# 对称距离矩阵
DIST = np.array([
[0, 2, 9, 10],
[2, 0, 6, 4],
[9, 6, 0, 8],
[10, 4, 8, 0],
], dtype=float)
N_CITY = len(DIST)
N_ANT = 10
N_ITER = 80
ALPHA, BETA, RHO = 1.0, 5.0, 0.5
ETA = np.where(DIST > 0, 1.0 / DIST, 0.0)
def tour_length(tour):
return sum(DIST[tour[i], tour[(i + 1) % N_CITY]] for i in range(N_CITY))
def ant_walk(tau, rng):
start = rng.integers(N_CITY)
tour, unvisited = [start], set(range(N_CITY)) - {start}
cur = start
while unvisited:
nxt_list = list(unvisited)
weights = np.array([
tau[cur, j] ** ALPHA * ETA[cur, j] ** BETA for j in nxt_list
])
probs = weights / weights.sum()
cur = nxt_list[rng.choice(len(nxt_list), p=probs)]
tour.append(cur)
unvisited.remove(cur)
return tour
def main():
rng = np.random.default_rng(1)
tau = np.ones((N_CITY, N_CITY))
best_tour, best_len = None, float("inf")
for it in range(N_ITER):
tours = [ant_walk(tau, rng) for _ in range(N_ANT)]
delta = np.zeros_like(tau)
for tour in tours:
length = tour_length(tour)
if length < best_len:
best_len, best_tour = length, tour[:]
q = 1.0 / length
for i in range(N_CITY):
a, b = tour[i], tour[(i + 1) % N_CITY]
delta[a, b] += q
delta[b, a] += q
tau = (1 - RHO) * tau + delta # 挥发 + 沉积
tau[tau < 1e-6] = 1e-6
if it % 20 == 0 or it == N_ITER - 1:
print(f"第 {it:3d} 轮 | 当前最优长度 {best_len:.1f}")
print(f"\n最短环路:{' → '.join(map(str, best_tour))} → {best_tour[0]}")
print(f"最短长度:{best_len:.1f}")
if __name__ == "__main__":
main()
第 0 轮 | 当前最优长度 26.0 第 20 轮 | 当前最优长度 23.0 第 40 轮 | 当前最优长度 23.0 第 79 轮 | 当前最优长度 23.0 最短环路:0 → 1 → 3 → 2 → 0 最短长度:23.0
算法很快锁定了长度 23 的最优环路(0→1→3→2→0 或其反向)。 ACO 是典型的群体智能:个体规则简单、没有中心控制,智能在信息素的正反馈中涌现。 它在路由优化、车间调度、车辆路径问题上表现优异;缺点是收敛慢、参数敏感, 实际中常与局部搜索(如 2-opt)混合使用。
◈ 三种范式的共性
神经网络靠权重的迭代修正,遗传算法靠种群的代际进化, 蚁群/粒子群靠群体的信息共享——它们都不依赖显式的符号知识, 而是在数值迭代中逼近最优解,这正是"计算智能"区别于经典符号 AI 的本质。
本章小结
- 计算智能以数值数据为驱动,包含神经计算、进化计算、群体智能与模糊计算四大范式。
- M-P 神经元与感知机是神经计算的起点;单层感知机只能解线性可分问题。
- BP 网络用链式法则把误差反向传播,配合梯度下降训练多层网络,成功解决 XOR,是深度学习的算法基石。
- 遗传算法通过编码、选择、交叉、变异让解种群进化,不要求目标可导。
- 粒子群算法以"惯性+认知+社会"三部分更新速度,实现简单、收敛迅速。
- 蚁群算法以信息素挥发与沉积形成正反馈,擅长 TSP 等组合优化。