在前面几节课中,我们学习了AI的基础知识和数学原理。今天,我们将通过实际的代码体验早期AI的经典案例,包括感知机二分类和搜索算法在路径规划中的应用,让你亲手感受AI的魅力!
早期AI发展回顾
早期AI主要集中在符号主义和简单连接主义方法上,虽然算法相对简单,但为后续发展奠定了重要基础。
timeline
title 早期AI重要里程碑
1950年代 : 感知机诞生,AI学科建立
1960年代 : 专家系统兴起
1970年代 : 知识表示和推理技术发展
1980年代 : 机器学习开始兴起
1990年代 : 统计学习方法崭露头角
感知机:AI的起点
感知机是最早的人工神经网络模型之一,由Frank Rosenblatt在1957年提出。虽然简单,但它奠定了神经网络和深度学习的基础。
感知机原理
感知机是一个二分类模型,它通过学习一个线性决策边界来将数据分为两类。
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
"""感知机实现"""
def __init__(self, learning_rate=0.01, n_iterations=1000):
self.learning_rate = learning_rate
self.n_iterations = n_iterations
self.weights = None
self.bias = None
def fit(self, X, y):
"""训练感知机"""
# 初始化权重和偏置
n_samples, n_features = X.shape
self.weights = np.zeros(n_features)
self.bias = 0
# 将标签转换为-1和1
y_ = np.where(y <= 0, -1, 1)
# 训练过程
for _ in range(self.n_iterations):
for idx, x_i in enumerate(X):
# 计算线性输出
linear_output = np.dot(x_i, self.weights) + self.bias
# 预测结果
y_predicted = np.where(linear_output >= 0, 1, -1)
# 更新权重和偏置
update = self.learning_rate * (y_[idx] - y_predicted)
self.weights += update * x_i
self.bias += update
def predict(self, X):
"""预测"""
linear_output = np.dot(X, self.weights) + self.bias
return np.where(linear_output >= 0, 1, 0)
def decision_boundary(self, x):
"""计算决策边界"""
return -(self.weights[0] * x + self.bias) / self.weights[1]
# 生成示例数据
def generate_and_data():
"""生成AND逻辑门数据"""
X = np.array([
[0, 0],
[0, 1],
[1, 0],
[1, 1]
])
y = np.array([0, 0, 0, 1]) # AND逻辑
return X, y
def generate_or_data():
"""生成OR逻辑门数据"""
X = np.array([
[0, 0],
[0, 1],
[1, 0],
[1, 1]
])
y = np.array([0, 1, 1, 1]) # OR逻辑
return X, y
# 训练感知机解决AND问题
def perceptron_and_demo():
"""感知机解决AND问题演示"""
X, y = generate_and_data()
# 创建并训练感知机
perceptron = Perceptron(learning_rate=0.1, n_iterations=100)
perceptron.fit(X, y)
# 预测
predictions = perceptron.predict(X)
print("感知机解决AND逻辑问题:")
print("输入\t\t实际输出\t预测输出")
for i in range(len(X)):
print(f"{X[i]}\t\t{y[i]}\t\t{predictions[i]}")
# 可视化
plt.figure(figsize=(10, 6))
# 绘制数据点
for i in range(len(X)):
if y[i] == 1:
plt.scatter(X[i, 0], X[i, 1], c='red', s=100, marker='o', label='正类' if i == 3 else "")
else:
plt.scatter(X[i, 0], X[i, 1], c='blue', s=100, marker='s', label='负类' if i == 0 else "")
# 绘制决策边界
x_range = np.linspace(-0.5, 1.5, 100)
y_range = perceptron.decision_boundary(x_range)
plt.plot(x_range, y_range, 'g-', linewidth=2, label='决策边界')
plt.xlabel('输入1')
plt.ylabel('输入2')
plt.title('感知机解决AND问题')
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(-0.5, 1.5)
plt.ylim(-0.5, 1.5)
plt.show()
print(f"\n学习到的权重: {perceptron.weights}")
print(f"学习到的偏置: {perceptron.bias}")
# 训练感知机解决OR问题
def perceptron_or_demo():
"""感知机解决OR问题演示"""
X, y = generate_or_data()
# 创建并训练感知机
perceptron = Perceptron(learning_rate=0.1, n_iterations=100)
perceptron.fit(X, y)
# 预测
predictions = perceptron.predict(X)
print("\n感知机解决OR逻辑问题:")
print("输入\t\t实际输出\t预测输出")
for i in range(len(X)):
print(f"{X[i]}\t\t{y[i]}\t\t{predictions[i]}")
# 可视化
plt.figure(figsize=(10, 6))
# 绘制数据点
for i in range(len(X)):
if y[i] == 1:
plt.scatter(X[i, 0], X[i, 1], c='red', s=100, marker='o', label='正类' if i == 1 else "")
else:
plt.scatter(X[i, 0], X[i, 1], c='blue', s=100, marker='s', label='负类' if i == 0 else "")
# 绘制决策边界
x_range = np.linspace(-0.5, 1.5, 100)
y_range = perceptron.decision_boundary(x_range)
plt.plot(x_range, y_range, 'g-', linewidth=2, label='决策边界')
plt.xlabel('输入1')
plt.ylabel('输入2')
plt.title('感知机解决OR问题')
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(-0.5, 1.5)
plt.ylim(-0.5, 1.5)
plt.show()
print(f"\n学习到的权重: {perceptron.weights}")
print(f"学习到的偏置: {perceptron.bias}")
# XOR问题演示(感知机无法解决)
def perceptron_xor_demo():
"""感知机解决XOR问题演示(会失败)"""
X = np.array([
[0, 0],
[0, 1],
[1, 0],
[1, 1]
])
y = np.array([0, 1, 1, 0]) # XOR逻辑
# 创建并训练感知机
perceptron = Perceptron(learning_rate=0.1, n_iterations=1000)
perceptron.fit(X, y)
# 预测
predictions = perceptron.predict(X)
print("\n感知机解决XOR逻辑问题:")
print("输入\t\t实际输出\t预测输出")
for i in range(len(X)):
print(f"{X[i]}\t\t{y[i]}\t\t{predictions[i]}")
print("\n注意:感知机无法正确解决XOR问题,因为XOR不是线性可分的!")
# 可视化
plt.figure(figsize=(10, 6))
# 绘制数据点
colors = ['blue', 'red', 'red', 'blue'] # XOR模式
markers = ['s', 'o', 'o', 's']
for i in range(len(X)):
plt.scatter(X[i, 0], X[i, 1], c=colors[i], s=100, marker=markers[i],
label=f'正类' if y[i] == 1 and i == 1 else (
f'负类' if y[i] == 0 and i == 0 else ""))
# 绘制决策边界
x_range = np.linspace(-0.5, 1.5, 100)
y_range = perceptron.decision_boundary(x_range)
plt.plot(x_range, y_range, 'g--', linewidth=2, label='感知机决策边界')
plt.xlabel('输入1')
plt.ylabel('输入2')
plt.title('感知机尝试解决XOR问题(线性不可分)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.xlim(-0.5, 1.5)
plt.ylim(-0.5, 1.5)
plt.show()
# 运行演示
perceptron_and_demo()
perceptron_or_demo()
perceptron_xor_demo()
搜索算法:路径规划问题
搜索算法是早期AI的另一个重要分支,广泛应用于游戏、路径规划等领域。我们以经典的A*算法为例来演示。
A*算法原理
A*算法是一种启发式搜索算法,它结合了Dijkstra算法的准确性和贪心最佳优先搜索的效率。
import heapq
import math
class Node:
"""节点类"""
def __init__(self, x, y):
self.x = x
self.y = y
self.g = float('inf') # 从起点到当前节点的实际代价
self.h = 0 # 启发式估计代价(到终点的估计)
self.f = float('inf') # f = g + h
self.parent = None # 父节点
def __lt__(self, other):
return self.f < other.f
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
class AStar:
"""A*算法实现"""
def __init__(self, grid):
self.grid = grid
self.rows = len(grid)
self.cols = len(grid[0])
def heuristic(self, node, goal):
"""启发式函数(欧几里得距离)"""
return math.sqrt((node.x - goal.x)**2 + (node.y - goal.y)**2)
def get_neighbors(self, node):
"""获取邻居节点"""
neighbors = []
# 8个方向的移动
directions = [(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)]
for dx, dy in directions:
new_x, new_y = node.x + dx, node.y + dy
# 检查边界
if 0 <= new_x < self.rows and 0 <= new_y < self.cols:
# 检查是否为障碍物
if self.grid[new_x][new_y] != 1:
neighbors.append(Node(new_x, new_y))
return neighbors
def reconstruct_path(self, node):
"""重构路径"""
path = []
current = node
while current is not None:
path.append((current.x, current.y))
current = current.parent
return path[::-1] # 反转路径
def search(self, start, goal):
"""执行A*搜索"""
# 初始化起点
start_node = Node(start[0], start[1])
goal_node = Node(goal[0], goal[1])
start_node.g = 0
start_node.h = self.heuristic(start_node, goal_node)
start_node.f = start_node.g + start_node.h
# 开放列表和关闭列表
open_list = []
closed_list = set()
heapq.heappush(open_list, start_node)
while open_list:
# 获取f值最小的节点
current_node = heapq.heappop(open_list)
closed_list.add((current_node.x, current_node.y))
# 到达目标
if current_node == goal_node:
return self.reconstruct_path(current_node)
# 检查邻居
for neighbor in self.get_neighbors(current_node):
if (neighbor.x, neighbor.y) in closed_list:
continue
# 计算从当前节点到邻居的代价
if abs(neighbor.x - current_node.x) == 1 and abs(neighbor.y - current_node.y) == 1:
# 对角线移动
move_cost = math.sqrt(2)
else:
# 直线移动
move_cost = 1
tentative_g = current_node.g + move_cost
# 检查是否找到更好的路径
if tentative_g < neighbor.g:
neighbor.parent = current_node
neighbor.g = tentative_g
neighbor.h = self.heuristic(neighbor, goal_node)
neighbor.f = neighbor.g + neighbor.h
# 检查是否已在开放列表中
if neighbor not in open_list:
heapq.heappush(open_list, neighbor)
return None # 未找到路径
# 路径规划演示
def pathfinding_demo():
"""路径规划演示"""
# 创建网格地图 (0=可通过, 1=障碍物)
grid = [
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
# 定义起点和终点
start = (0, 0)
goal = (7, 6)
# 创建A*对象并搜索路径
astar = AStar(grid)
path = astar.search(start, goal)
if path:
print("找到路径:")
for i, pos in enumerate(path):
print(f"步骤 {i}: {pos}")
# 可视化路径
plt.figure(figsize=(10, 8))
# 绘制网格
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
plt.scatter(j, i, c='black', s=200, marker='s') # 障碍物
else:
plt.scatter(j, i, c='lightgray', s=100, marker='s') # 可通过
# 绘制起点和终点
plt.scatter(start[1], start[0], c='green', s=200, marker='o', label='起点')
plt.scatter(goal[1], goal[0], c='red', s=200, marker='*', label='终点')
# 绘制路径
if path:
path_x = [pos[1] for pos in path]
path_y = [pos[0] for pos in path]
plt.plot(path_x, path_y, 'b-', linewidth=2, marker='o', markersize=6, label='路径')
plt.title('A*路径规划')
plt.xlabel('列')
plt.ylabel('行')
plt.legend()
plt.grid(True, alpha=0.3)
plt.gca().invert_yaxis() # 使坐标系符合数组索引
plt.show()
else:
print("未找到路径!")
pathfinding_demo()
深蓝与搜索算法
1997年,IBM的深蓝计算机击败了国际象棋世界冠军加里·卡斯帕罗夫,这是AI历史上的重要里程碑。深蓝主要使用了强力搜索和评估函数。
# 简化的棋盘评估函数示例
class SimpleChessEvaluator:
"""简化版国际象棋评估函数"""
# 棋子价值
PIECE_VALUES = {
'P': 1, # 兵
'N': 3, # 马
'B': 3, # 象
'R': 5, # 车
'Q': 9, # 后
'K': 0 # 王(不计入评估)
}
def evaluate_position(self, board):
"""评估棋盘位置"""
score = 0
# 简单的棋子计数评估
for row in board:
for piece in row:
if piece:
if piece.isupper(): # 白方棋子
score += self.PIECE_VALUES.get(piece.upper(), 0)
else: # 黑方棋子
score -= self.PIECE_VALUES.get(piece.upper(), 0)
return score
# 搜索树示例
class SimpleMinimax:
"""简化版Minimax算法"""
def __init__(self, depth=3):
self.depth = depth
self.evaluator = SimpleChessEvaluator()
def minimax(self, board, depth, maximizing_player):
"""Minimax算法"""
# 到达最大深度或游戏结束
if depth == 0:
return self.evaluator.evaluate_position(board)
if maximizing_player:
max_eval = float('-inf')
# 这里应该生成所有可能的移动,为简化只演示概念
# for move in generate_moves(board, 'white'):
# new_board = make_move(board, move)
# eval_score = self.minimax(new_board, depth-1, False)
# max_eval = max(max_eval, eval_score)
return max_eval
else:
min_eval = float('inf')
# for move in generate_moves(board, 'black'):
# new_board = make_move(board, move)
# eval_score = self.minimax(new_board, depth-1, True)
# min_eval = min(min_eval, eval_score)
return min_eval
# 演示深蓝的搜索概念
def deep_blue_concept_demo():
"""深蓝搜索概念演示"""
print("深蓝计算机的核心思想:")
print("1. 强力搜索: 搜索大量可能的棋步")
print("2. 评估函数: 评估每个局面的优劣")
print("3. 剪枝技术: 减少不必要的搜索分支")
print("4. 并行计算: 同时评估多个可能性")
# 简单的棋盘表示
simple_board = [
['r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'],
['p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
['P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'],
['R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R']
]
evaluator = SimpleChessEvaluator()
score = evaluator.evaluate_position(simple_board)
print(f"\n初始棋盘评估得分: {score}")
print("(正值表示白方优势,负值表示黑方优势)")
print("\n深蓝的技术特点:")
print("- 每秒可评估2亿个棋局")
print("- 搜索深度可达12-14步")
print("- 使用专门的硬件芯片")
print("- 包含大量象棋知识的开局库和残局库")
deep_blue_concept_demo()
本周学习总结
今天我们通过实际代码体验了早期AI的经典案例:
-
感知机模型
- 理解了感知机的工作原理
- 实现了AND和OR逻辑门分类
- 认识到了感知机的局限性(无法解决XOR问题)
-
搜索算法
- 学习了A*算法的基本原理
- 实现了路径规划问题的解决
- 了解了启发式搜索的优势
-
深蓝计算机
- 了解了强力搜索在游戏AI中的应用
- 认识了评估函数的重要性
graph TD
A[早期AI案例] --> B[感知机]
A --> C[搜索算法]
A --> D[深蓝计算机]
B --> E[线性分类]
B --> F[局限性]
C --> G[A*算法]
C --> H[路径规划]
D --> I[强力搜索]
D --> J[评估函数]
课后练习
- 修改感知机代码,尝试不同的学习率和迭代次数,观察效果变化
- 在A*路径规划中添加更多的障碍物,测试算法的鲁棒性
- 实现一个简单的BFS(广度优先搜索)算法,并与A*进行比较
- 思考并写下感知机与现代深度学习网络的联系与区别
下节预告
下一节我们将深入学习传统机器学习模型,包括线性回归、逻辑回归、决策树等核心算法,这些都是现代AI技术的重要基础,敬请期待!
有任何疑问请在讨论区留言,我们会定期回复大家的问题。