体验早期AI案例:感知机和搜索算法实战

2 阅读1分钟

在前面几节课中,我们学习了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的经典案例:

  1. 感知机模型

    • 理解了感知机的工作原理
    • 实现了AND和OR逻辑门分类
    • 认识到了感知机的局限性(无法解决XOR问题)
  2. 搜索算法

    • 学习了A*算法的基本原理
    • 实现了路径规划问题的解决
    • 了解了启发式搜索的优势
  3. 深蓝计算机

    • 了解了强力搜索在游戏AI中的应用
    • 认识了评估函数的重要性
graph TD
    A[早期AI案例] --> B[感知机]
    A --> C[搜索算法]
    A --> D[深蓝计算机]
    B --> E[线性分类]
    B --> F[局限性]
    C --> G[A*算法]
    C --> H[路径规划]
    D --> I[强力搜索]
    D --> J[评估函数]

课后练习

  1. 修改感知机代码,尝试不同的学习率和迭代次数,观察效果变化
  2. 在A*路径规划中添加更多的障碍物,测试算法的鲁棒性
  3. 实现一个简单的BFS(广度优先搜索)算法,并与A*进行比较
  4. 思考并写下感知机与现代深度学习网络的联系与区别

下节预告

下一节我们将深入学习传统机器学习模型,包括线性回归、逻辑回归、决策树等核心算法,这些都是现代AI技术的重要基础,敬请期待!


有任何疑问请在讨论区留言,我们会定期回复大家的问题。