# 01.4 反馈与学习 ## 核心问题 > 系统如何从经验中改进? > 强化学习的基本直觉是什么? > 如何设计一个好的奖励函数? --- ## 概念讲解 ### 反馈循环 **反馈**是系统学习的基础机制: ``` ┌─────────────────────────────────────────────────┐ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐│ │ │ Action │ ───→ │ Effect │ ───→ │Reward ││ │ └─────────┘ └─────────┘ └─────────┘│ │ │ │ │ │ │ ┌────────────┐ │ │ │ └───────────→│ Update │←──────┘ │ │ ↑ │ │ │ │ │ ┌──────┴──────┐ │ │ │ Policy │ │ │ │ Improvement│ │ │ └─────────────┘ │ │ │ └─────────────────────────────────────────────────┘ ``` **反馈的类型**: | 类型 | 说明 | 例子 | |-----|------|------| | **正反馈** | 强化正确行为 | 生态廊道有效,增加类似策略 | | **负反馈** | 抑制错误行为 | 阻力面不合理,调整权重 | | **延迟反馈** | 效果滞后 | 生态工程几年后才见效 | | **隐式反馈** | 未明确标注 | 用户不使用某功能 = 不好用 | ### 强化学习的直觉 强化学习(RL)是关于"如何通过试错学习": ``` 强化学习核心概念 智能体 ──→ 动作 ──→ 环境 ──→ 奖励 ↑ │ │ │ └─────────────── 观察状态 ←──────────────┘ │ ↓ 更新策略 ``` **关键要素**: 1. **状态 (State)**:智能体看到的当前情况 2. **动作 (Action)**:智能体能做的事情 3. **奖励 (Reward)**:动作好坏的即时反馈 4. **策略 (Policy)**:状态到动作的映射规则 5. **价值函数 (Value)**:对长期收益的估计 ```python # RL的数学直觉 # 策略:在状态s采取动作a的概率 π(a|s) = P(action=a | state=s) # 价值函数:从状态s开始的期望累积奖励 V(s) = E[Σ γ^t * r_t | s_0 = s] # γ是折扣因子,平衡即时和长期奖励 # 动作价值函数:在状态s采取动作a后的期望累积奖励 Q(s,a) = E[Σ γ^t * r_t | s_0 = s, a_0 = a] # 目标:找到最优策略,最大化累积奖励 π* = argmax_π V^π(s) ``` ### 探索与利用的权衡 RL中经典的困境: ``` 探索 (Explore) vs 利用 (Exploit) 利用 探索 ↓ ↓ 选择已知最好的动作 尝试新动作 获得稳定奖励 可能发现更好动作 可能错过最优 可能浪费资源 ``` **策略**: | 策略 | 方法 | 适用场景 | |-----|------|---------| | **ε-greedy** | 以ε概率随机探索 | 通用,简单 | | **Boltzmann** | 按价值概率选择 | 需要细粒度控制 | | **UCB** | 上置信界选择 | 需要理论保证 | | **Thompson Sampling** | 采样后验概率 | 贝叶斯框架 | ```python def epsilon_greedy_action(q_values, epsilon, n_actions): """ ε-greedy策略 Args: q_values: 各动作的估计价值 epsilon: 探索概率 n_actions: 动作数量 Returns: 选择的动作 """ if np.random.random() < epsilon: # 探索:随机选择 return np.random.randint(n_actions) else: # 利用:选择价值最高的 return np.argmax(q_values) # ε的衰减策略 def epsilon_schedule(initial_epsilon, final_epsilon, total_steps, current_step): """线性衰减ε""" decay = (initial_epsilon - final_epsilon) / total_steps return max(final_epsilon, initial_epsilon - decay * current_step) ``` --- ## 设计原理 ### 奖励函数设计 奖励函数定义了"什么是好的行为": ```python """ 奖励函数设计原则 """ # 原则1: 清晰明确 # 好的奖励 def good_reward(ecological_quality): """生态质量越高,奖励越高""" return ecological_quality # 不好的奖励(有歧义) def bad_reward(ecological_quality, cost): """混合多个目标,可能冲突""" return ecological_quality - cost * 0.001 # 原则2: 适度塑形 (Reward Shaping) # 不要过度引导,让智能体自己探索 def shaped_reward(base_reward, intermediate_metric): """ 基础奖励 + 形状奖励 基础奖励:定义最终目标 形状奖励:引导到达目标(权重较小) """ return base_reward + 0.1 * intermediate_metric # 原则3: 避免奖励黑客 (Reward Hacking) # 防止智能体找到"作弊"方法 def safe_reward_with_constraints(action_result): """ 带约束的奖励 """ base_reward = action_result['quality'] # 如果违反约束,给予惩罚 if action_result['violates_constraint']: base_reward -= 100 # 大惩罚 # 如果使用"作弊"方法,给予惩罚 if action_result['uses_exploit']: base_reward -= 50 return base_reward # 原则4: 多目标平衡 def multi_objective_reward(ecological, economic, social, weights): """ 多目标加权 Args: ecological: 生态效益 economic: 经济效益 social: 社会效益 weights: 各目标权重 Returns: 综合奖励 """ # 归一化到[0,1] normalized = { 'eco': min(ecological / 100, 1.0), 'eco': min(economic / 1000, 1.0), 'soc': min(social / 100, 1.0) } total = (weights['eco'] * normalized['eco'] + weights['eco'] * normalized['eco'] + weights['soc'] * normalized['soc']) return total ``` ### 在空间分析中的应用 ```python class SpatialOptimizerRL: """ 用强化学习优化空间布局 场景:给定区域内选择最优生态廊道路线 """ def __init__(self, landscape, constraints): self.landscape = landscape self.constraints = constraints # 状态空间:当前的廊道路线 # 动作空间:下一步走向哪个像元 # 奖励:连通性、距离、穿越地类的综合 def state_representation(self): """将当前空间格局转换为状态表示""" return { 'current_position': self.current_position, 'visited_cells': self.visited_cells, 'local_context': self._get_local_context() } def available_actions(self): """获取可用的动作""" # 可以向8个方向移动 directions = [ (0, 1), (1, 0), (0, -1), (-1, 0), # 上下左右 (1, 1), (1, -1), (-1, 1), (-1, -1) # 对角 ] actions = [] for dx, dy in directions: new_x = self.current_position[0] + dx new_y = self.current_position[1] + dy if self._is_valid_move(new_x, new_y): actions.append((new_x, new_y)) return actions def reward_function(self, action, new_state): """ 定义奖励函数 考虑: 1. 穿越的土地类型(林地奖励,城市惩罚) 2. 距离目标的远近(越近越好) 3. 是否到达目标(大奖励) """ x, y = new_state['position'] # 1. 土地类型奖励/惩罚 land_type = self.landscape[y, x] land_rewards = { 'forest': 10, 'grassland': 5, 'wetland': 8, 'agriculture': 0, 'urban': -50, 'water': -20 } land_reward = land_rewards.get(land_type, -10) # 2. 距离奖励(离目标越近越好) dist_to_goal = self._distance_to_goal(new_state['position']) distance_reward = -dist_to_goal * 0.1 # 3. 目标到达奖励 goal_reward = 0 if new_state['position'] == self.goal_position: goal_reward = 1000 # 4. 约束惩罚 constraint_penalty = 0 if self._violates_constraint(new_state): constraint_penalty = -100 # 总奖励 total_reward = (land_reward + distance_reward + goal_reward + constraint_penalty) return total_reward def train(self, n_episodes=1000): """ 训练智能体 使用Q-learning """ q_table = {} # Q值表 for episode in range(n_episodes): state = self._reset() epsilon = self._epsilon_schedule(episode) done = False while not done: # ε-greedy选择动作 if np.random.random() < epsilon: action = np.random.choice(self.available_actions()) else: # 选择Q值最高的动作 q_values = [q_table.get((state, a), 0) for a in self.available_actions()] action = self.available_actions()[np.argmax(q_values)] # 执行动作 new_state, reward, done = self._step(action) # 更新Q值 old_q = q_table.get((state, action), 0) max_next_q = max([q_table.get((new_state, a), 0) for a in self.available_actions()] + [0]) # Q-learning更新公式 q_table[(state, action)] = old_q + 0.1 * ( reward + 0.99 * max_next_q - old_q ) state = new_state return q_table ``` --- ## 代码示例 ### 简化的生态网络优化RL ```python """ 简化版:用Q-learning优化生态源地选择 """ import numpy as np from typing import List, Dict, Tuple import random class EcologicalNetworkOptimizer: """ 生态网络优化器(RL简化版) 问题:从候选源地中选择最优组合 - 最大化总生态价值 - 满足连通性要求 - 预算约束 """ def __init__(self, candidate_sites: List[Dict], budget: float): self.candidate_sites = candidate_sites self.budget = budget # 动作:选择或不选择某个源地 self.n_actions = len(candidate_sites) # 状态:已选源地列表 # 简化:用位掩码表示状态 self.n_states = 2 ** self.n_actions # Q表 self.q_table = np.zeros((self.n_states, self.n_actions)) def state_to_mask(self, state: int) -> List[bool]: """状态索引转位掩码""" return [(state >> i) & 1 for i in range(self.n_actions)] def mask_to_state(self, mask: List[bool]) -> int: """位掩码转状态索引""" state = 0 for i, bit in enumerate(mask): if bit: state |= (1 << i) return state def available_actions(self, state_mask: List[bool]) -> List[int]: """获取可用动作(未选的源地)""" return [i for i, selected in enumerate(state_mask) if not selected] def reward_function(self, state_mask: List[bool]) -> float: """ 计算当前选择的奖励 考虑: 1. 总生态价值 2. 连通性 3. 预算约束 """ # 选中源地 selected_sites = [self.candidate_sites[i] for i, selected in enumerate(state_mask) if selected] if not selected_sites: return 0 # 1. 总生态价值 total_value = sum(site['value'] for site in selected_sites) # 2. 连通性(简化:已选源地之间的平均距离) if len(selected_sites) > 1: positions = [(site['x'], site['y']) for site in selected_sites] distances = [] for i in range(len(positions)): for j in range(i + 1, len(positions)): dist = np.sqrt((positions[i][0] - positions[j][0])**2 + (positions[i][1] - positions[j][1])**2) distances.append(dist) avg_distance = np.mean(distances) connectivity_reward = -0.1 * avg_distance # 距离越近越好 else: connectivity_reward = 0 # 3. 预算惩罚 total_cost = sum(site['cost'] for site in selected_sites) budget_penalty = 0 if total_cost > self.budget: budget_penalty = -100 * (total_cost - self.budget) / self.budget # 总奖励 total_reward = total_value + connectivity_reward + budget_penalty return total_reward def step(self, state: int, action: int) -> Tuple[int, float, bool]: """ 执行一步 Returns: next_state: 下一个状态 reward: 奖励 done: 是否结束 """ state_mask = self.state_to_mask(state) # 执行动作(选择一个源地) if state_mask[action]: # 已经选过了 return state, -100, True # 惩罚并结束 new_mask = state_mask.copy() new_mask[action] = True # 计算奖励 reward = self.reward_function(new_mask) # 检查是否结束(预算用完或所有源地都选了) total_cost = sum(self.candidate_sites[i]['cost'] for i, selected in enumerate(new_mask) if selected) done = (total_cost >= self.budget) or (sum(new_mask) == len(new_mask)) next_state = self.mask_to_state(new_mask) return next_state, reward, done def train(self, n_episodes=1000, alpha=0.1, gamma=0.99, epsilon_start=1.0, epsilon_end=0.01): """ Q-learning训练 Args: n_episodes: 训练回合数 alpha: 学习率 gamma: 折扣因子 epsilon_start: 初始探索率 epsilon_end: 最终探索率 """ for episode in range(n_episodes): # 线性衰减ε epsilon = epsilon_start - (epsilon_start - epsilon_end) * episode / n_episodes state = 0 # 初始状态(空) done = False while not done: state_mask = self.state_to_mask(state) available = self.available_actions(state_mask) if not available: break # ε-greedy if np.random.random() < epsilon: action = random.choice(available) else: q_values = [self.q_table[state, a] for a in available] action = available[np.argmax(q_values)] # 执行动作 next_state, reward, done = self.step(state, action) # Q-learning更新 old_q = self.q_table[state, action] next_max = np.max(self.q_table[next_state]) self.q_table[state, action] = old_q + alpha * ( reward + gamma * next_max - old_q ) state = next_state # 定期报告 if episode % 100 == 0: current_epsilon = epsilon_start - (epsilon_start - epsilon_end) * episode / n_episodes print(f"Episode {episode}, ε={current_epsilon:.3f}, " f"Best Q: {np.max(self.q_table[0]):.2f}") return self.q_table def get_solution(self) -> List[Dict]: """获取学习到的最优解""" state = 0 state_mask = self.state_to_mask(state) solution = [] while True: available = self.available_actions(state_mask) if not available: break # 选择Q值最高的动作 q_values = [self.q_table[state, a] for a in available] action = available[np.argmax(q_values)] solution.append(self.candidate_sites[action]) state, _, done = self.step(state, action) if done: break return solution # 示例使用 def example_usage(): """示例使用""" print("=== 生态网络优化:Q-learning ===\n") # 创建候选源地 np.random.seed(42) n_candidates = 10 candidates = [] for i in range(n_candidates): candidates.append({ 'id': i, 'x': np.random.randint(0, 100), 'y': np.random.randint(0, 100), 'value': np.random.randint(50, 150), 'cost': np.random.randint(20, 80) }) budget = 200 print(f"候选源地数: {n_candidates}") print(f"预算: {budget}\n") # 创建优化器并训练 optimizer = EcologicalNetworkOptimizer(candidates, budget) optimizer.train(n_episodes=500) # 获取解 solution = optimizer.get_solution() print("\n=== 最优解 ===") print(f"选择源地数: {len(solution)}") total_value = sum(s['value'] for s in solution) total_cost = sum(s['cost'] for s in solution) print(f"总价值: {total_value}") print(f"总成本: {total_cost}") print("\n选择的源地:") for s in solution: print(f" 源地 {s['id']}: 价值={s['value']}, 成本={s['cost']}") if __name__ == "__main__": example_usage() ``` --- ## 案例分析 ### ENAgent中的反馈机制 ```python class ENAgentFeedback: """ ENAgent的反馈机制 场景:生态网络迭代的改进 """ def __init__(self): self.iteration_history = [] self.performance_metrics = [] def collect_feedback(self, iteration, result, human_feedback): """ 收集每轮的反馈 Args: iteration: 迭代次数 result: 本轮结果 human_feedback: 人类专家的反馈 """ feedback_record = { 'iteration': iteration, 'result': result, 'human_feedback': human_feedback, 'timestamp': time.time() } self.iteration_history.append(feedback_record) def analyze_feedback(self) -> Dict: """ 分析反馈,提取改进建议 Returns: 改进建议 """ if not self.iteration_history: return {} # 分析模式 suggestions = {} # 1. 常见问题 problem_counts = {} for record in self.iteration_history: for problem in record['human_feedback'].get('problems', []): problem_counts[problem] = problem_counts.get(problem, 0) + 1 if problem_counts: common_problems = sorted(problem_counts.items(), key=lambda x: x[1], reverse=True) suggestions['common_problems'] = common_problems # 2. 趋势分析 if len(self.iteration_history) > 1: recent_quality = self.iteration_history[-1]['result']['quality'] previous_quality = self.iteration_history[-2]['result']['quality'] if recent_quality > previous_quality: suggestions['trend'] = 'improving' else: suggestions['trend'] = 'stagnant_or_degrading' # 3. 参数调整建议 suggestions['parameter_adjustments'] = self._suggest_adjustments() return suggestions def _suggest_adjustments(self) -> Dict: """建议参数调整""" # 基于反馈历史,建议如何调整参数 # 这是一个简化示例 return { 'resistance_weights': 'consider adjusting urban weight', 'source_threshold': 'might be too high/low' } ``` --- ## 反思与延伸 ### 思考问题 1. **延迟奖励**:生态工程的效果多年后才显现,如何设计奖励函数? 2. **稀疏奖励**:当大多数步骤没有明确反馈时,如何学习? 3. **多目标冲突**:生态目标和经济目标冲突时,奖励函数如何平衡? 4. **人类反馈**:如何整合人类专家的定性反馈? ### 实践练习 1. **奖励设计**:为一个你熟悉的任务设计奖励函数 2. **调试RL**:观察Q表的变化,理解学习过程 3. **探索策略**:比较不同ε衰减策略的效果 ### 延伸阅读 - **"Reinforcement Learning: An Introduction"** (Sutton & Barto) - RL圣经 - **"Algorithms for Decision Making"** (Mykel Kochenderfer) - 决策与RL - **"Reward Shaping"**论文 - 奖励塑形理论 --- ## 关键要点 1. **反馈是学习的基础机制**,正反馈强化正确行为,负反馈纠正错误 2. **强化学习核心**:状态、动作、奖励、策略、价值函数 3. **探索vs利用**:经典困境,需要平衡策略 4. **奖励函数设计**是RL的关键,定义了"什么是好的行为" 5. **在空间分析中**:RL可用于优化布局、路径选择、参数调整