别再死记硬背了!用Python+PyTorch手把手复现AI导论里的经典算法(附代码)
·
用Python+PyTorch实战AI导论:从理论到代码的沉浸式学习
人工智能导论课程往往充斥着抽象概念和数学公式,让许多初学者望而生畏。但真正的理解来自于实践——当你亲手用代码实现那些课本上的算法时,理论会突然变得清晰起来。本文将带你用Python和PyTorch搭建一个"AI实验室",把枯燥的课本知识转化为可运行的代码。
1. 搭建AI算法实验环境
在开始编码之前,我们需要配置一个适合AI算法实验的开发环境。不同于普通的Python开发,AI实验对库版本和硬件有一定要求。
基础环境配置:
conda create -n ai_lab python=3.8
conda activate ai_lab
pip install torch==1.9.0 torchvision==0.10.0
核心工具包选择:
- PyTorch :相比TensorFlow更Pythonic,适合教学和实验
- NumPy :处理矩阵运算和数值计算
- Matplotlib :可视化算法过程和结果
- Jupyter Notebook :交互式实验的理想选择
提示:如果使用GPU加速,需要安装对应版本的CUDA驱动。但大多数基础算法在CPU上也能良好运行。
下面是一个环境检查脚本,可以验证主要组件是否正常工作:
import torch
print(f"PyTorch版本: {torch.__version__}")
print(f"CUDA可用: {torch.cuda.is_available()}")
2. 谓词逻辑的编程实现
一阶谓词逻辑是AI知识表示的基础,我们可以用Python类来模拟这一系统。
谓词逻辑系统设计:
class Predicate:
def __init__(self, name, arity):
self.name = name # 谓词名称
self.arity = arity # 参数数量
def __call__(self, *args):
if len(args) != self.arity:
raise ValueError(f"谓词{self.name}需要{self.arity}个参数")
return Atom(self, args)
class Atom:
def __init__(self, predicate, args):
self.predicate = predicate
self.args = args
def __repr__(self):
args_str = ",".join(str(arg) for arg in self.args)
return f"{self.predicate.name}({args_str})"
实际应用示例:
# 定义谓词
Teacher = Predicate("Teacher", 1)
Father = Predicate("Father", 2)
Likes = Predicate("Likes", 2)
# 构建原子公式
statement1 = Teacher("MrWang")
statement2 = Father("MrWang", "XiaoMing")
statement3 = Likes("XiaoHong", "Music")
print(statement1) # 输出: Teacher(MrWang)
print(statement2) # 输出: Father(MrWang,XiaoMing)
归结原理的实现:
def resolve(clause1, clause2):
"""简单的归结推理实现"""
substitutions = unify(clause1, clause2)
if substitutions:
new_clause = apply_substitutions(clause1 + clause2, substitutions)
return simplify(new_clause)
return None
3. 搜索算法的Python实现
搜索是AI解决问题的基本策略,让我们实现几种经典搜索算法。
3.1 A*搜索算法
def a_star_search(start, goal, heuristic):
open_set = PriorityQueue()
open_set.put(start, 0)
came_from = {}
g_score = {start: 0}
while not open_set.empty():
current = open_set.get()
if current == goal:
return reconstruct_path(came_from, current)
for neighbor in get_neighbors(current):
tentative_g = g_score[current] + distance(current, neighbor)
if neighbor not in g_score or tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score = tentative_g + heuristic(neighbor, goal)
open_set.put(neighbor, f_score)
return None # 未找到路径
3.2 八数码问题实战
class EightPuzzle:
def __init__(self, initial_state):
self.state = initial_state
self.goal = [[1,2,3],[4,5,6],[7,8,0]]
def heuristic(self, state):
"""曼哈顿距离启发式"""
distance = 0
for i in range(3):
for j in range(3):
if state[i][j] != 0:
x, y = divmod(state[i][j]-1, 3)
distance += abs(x - i) + abs(y - j)
return distance
def get_successors(self):
"""生成所有可能的下一步状态"""
# 找到空格位置
for i in range(3):
for j in range(3):
if self.state[i][j] == 0:
x, y = i, j
break
successors = []
for dx, dy in [(0,1),(1,0),(0,-1),(-1,0)]:
nx, ny = x + dx, y + dy
if 0 <= nx < 3 and 0 <= ny < 3:
new_state = [row[:] for row in self.state]
new_state[x][y], new_state[nx][ny] = new_state[nx][ny], new_state[x][y]
successors.append(new_state)
return successors
4. 遗传算法框架实现
遗传算法模拟自然选择过程,是解决优化问题的强大工具。
基本遗传算法框架:
import random
import numpy as np
class GeneticAlgorithm:
def __init__(self, population_size, chromosome_length, fitness_func):
self.pop_size = population_size
self.chrom_len = chromosome_length
self.fitness_func = fitness_func
self.population = self.init_population()
def init_population(self):
return np.random.randint(2, size=(self.pop_size, self.chrom_len))
def selection(self, fitness):
"""轮盘赌选择"""
probs = fitness / fitness.sum()
return np.random.choice(
range(self.pop_size),
size=self.pop_size,
p=probs
)
def crossover(self, parent1, parent2, rate=0.8):
if random.random() < rate:
pt = random.randint(1, self.chrom_len-2)
child1 = np.concatenate([parent1[:pt], parent2[pt:]])
child2 = np.concatenate([parent2[:pt], parent1[pt:]])
return child1, child2
return parent1.copy(), parent2.copy()
def mutation(self, chromosome, rate=0.01):
for i in range(self.chrom_len):
if random.random() < rate:
chromosome[i] = 1 - chromosome[i]
return chromosome
def evolve(self, generations):
best_fitness = []
for gen in range(generations):
fitness = np.array([self.fitness_func(ind) for ind in self.population])
best_fitness.append(fitness.max())
# 选择
selected = self.selection(fitness)
# 交叉和变异
new_pop = []
for i in range(0, self.pop_size, 2):
p1, p2 = selected[i], selected[i+1]
c1, c2 = self.crossover(self.population[p1], self.population[p2])
new_pop.extend([self.mutation(c1), self.mutation(c2)])
self.population = np.array(new_pop)
return best_fitness
应用示例:求解函数最大值
def test_fitness(chromosome):
"""适应度函数示例:求二进制编码表示的数字的平方"""
num = int("".join(map(str, chromosome)), 2)
return num ** 2
ga = GeneticAlgorithm(
population_size=50,
chromosome_length=10,
fitness_func=test_fitness
)
fitness_history = ga.evolve(100)
5. 群智能算法实践
群智能算法模拟昆虫或鸟群等生物群体的集体行为,具有自组织和分布式特点。
5.1 蚁群算法实现
class AntColony:
def __init__(self, distances, n_ants, n_best, n_iterations, decay, alpha=1, beta=1):
self.distances = distances
self.pheromone = np.ones(self.distances.shape) / len(distances)
self.all_inds = range(len(distances))
self.n_ants = n_ants
self.n_best = n_best
self.n_iterations = n_iterations
self.decay = decay
self.alpha = alpha
self.beta = beta
def run(self):
shortest_path = None
best_length = float('inf')
for it in range(self.n_iterations):
all_paths = self.gen_all_paths()
self.spread_pheromone(all_paths)
current_shortest = min(all_paths, key=lambda x: x[1])
if current_shortest[1] < best_length:
best_length = current_shortest[1]
shortest_path = current_shortest[0]
self.pheromone *= self.decay
return shortest_path, best_length
def gen_path_dist(self, path):
return sum(self.distances[path[i], path[i+1]] for i in range(len(path)-1))
def gen_all_paths(self):
all_paths = []
for _ in range(self.n_ants):
path = self.gen_path()
all_paths.append((path, self.gen_path_dist(path)))
return all_paths
def gen_path(self):
path = []
visited = set()
visited.add(0)
prev = 0
for _ in range(len(self.distances)-1):
move = self.pick_move(self.pheromone[prev], self.distances[prev], visited)
path.append((prev, move))
prev = move
visited.add(move)
path.append((prev, 0)) # 回到起点
return [i for i,j in path]
def pick_move(self, pheromone, dist, visited):
pheromone = np.copy(pheromone)
pheromone[list(visited)] = 0
row = pheromone ** self.alpha * ((1.0 / (dist + 1e-10)) ** self.beta)
norm_row = row / row.sum()
move = np.random.choice(self.all_inds, 1, p=norm_row)[0]
return move
def spread_pheromone(self, all_paths):
sorted_paths = sorted(all_paths, key=lambda x: x[1])
for path, dist in sorted_paths[:self.n_best]:
for i,j in zip(path[:-1], path[1:]):
self.pheromone[i,j] += 1.0 / dist
5.2 粒子群优化算法
class ParticleSwarmOptimizer:
def __init__(self, n_particles, dimensions, objective_func,
w=0.7, c1=1.5, c2=1.5):
self.n_particles = n_particles
self.dimensions = dimensions
self.objective = objective_func
self.w = w # 惯性权重
self.c1 = c1 # 认知系数
self.c2 = c2 # 社会系数
# 初始化粒子位置和速度
self.positions = np.random.uniform(-5, 5, (n_particles, dimensions))
self.velocities = np.random.uniform(-1, 1, (n_particles, dimensions))
# 记录个体最优和全局最优
self.pbest_pos = self.positions.copy()
self.pbest_val = np.array([float('inf')] * n_particles)
self.gbest_pos = None
self.gbest_val = float('inf')
def optimize(self, max_iter):
history = []
for _ in range(max_iter):
# 评估当前粒子群
current_val = np.array([self.objective(p) for p in self.positions])
# 更新个体最优
improved_idx = current_val < self.pbest_val
self.pbest_pos[improved_idx] = self.positions[improved_idx]
self.pbest_val[improved_idx] = current_val[improved_idx]
# 更新全局最优
if current_val.min() < self.gbest_val:
self.gbest_val = current_val.min()
self.gbest_pos = self.positions[current_val.argmin()].copy()
# 更新速度和位置
r1 = np.random.random((self.n_particles, self.dimensions))
r2 = np.random.random((self.n_particles, self.dimensions))
cognitive = self.c1 * r1 * (self.pbest_pos - self.positions)
social = self.c2 * r2 * (self.gbest_pos - self.positions)
self.velocities = self.w * self.velocities + cognitive + social
self.positions += self.velocities
history.append(self.gbest_val)
return self.gbest_pos, self.gbest_val, history
在实际项目中,我发现将理论算法转化为代码时,最重要的是保持算法的核心思想不变,同时根据编程语言的特性进行适当调整。比如遗传算法中的选择操作,理论上应该严格按概率选择,但在实际编码时,可以加入精英保留策略来加速收敛。
更多推荐

所有评论(0)