""" 赫布学习协调器 - 跨微柱、跨功能柱的协同学习 实现"一起激活的神经元连接在一起"的赫布法则 """ import numpy as np from typing import Dict, List, Optional, Tuple from enum import Enum class HebbianMode(Enum): """赫布学习模式""" STANDARD = 'standard' # 标准: ΔW = η * pre * post OJA = 'oja' # Oja法则: 加入权重复归一化 BCM = 'bcm' # BCM理论: 稳定可塑性 HOMEOSTATIC = 'homeostatic' # 稳态: 抑制过活跃神经元 class HebbianLearningCoordinator: """ 赫布学习协调器 - 管理整个网络的协同学习 功能: - 微柱内赫布学习(同一功能柱内微柱之间) - 微柱间赫布学习(不同功能柱之间) - 功能区之间赫布学习(跨区域联想) - 可塑性调节(根据任务动态调整学习率) """ def __init__( self, learning_rate: float = 0.01, mode: HebbianMode = HebbianMode.OJA, decay_rate: float = 0.001, min_learning_rate: float = 0.001, max_learning_rate: float = 0.1 ): self.base_learning_rate = learning_rate self.current_learning_rate = learning_rate self.mode = mode self.decay_rate = decay_rate self.min_lr = min_learning_rate self.max_lr = max_learning_rate # 微柱间连接权重(跨微柱学习) self._inter_column_weights: Dict[Tuple[str, str], np.ndarray] = {} # 激活历史(用于赫布计算) self._activation_history: Dict[str, List[np.ndarray]] = {} self._max_history = 20 # 神经元活跃度统计(稳态调节) self._activity_stats: Dict[str, float] = {} # 平均活跃度 # 学习统计 self._total_updates = 0 self._coactivity_events = 0 # ============ 核心赫布学习公式 ============ def compute_hebbian_update( self, pre_activity: np.ndarray, post_activity: np.ndarray, current_weight: Optional[np.ndarray] = None, mode: Optional[HebbianMode] = None ) -> np.ndarray: """ 计算赫布学习权重更新 ΔW = η * pre * post - λ * W (标准) ΔW = η * pre * post - η * β * W * post² (Oja) Args: pre_activity: 前突触激活 post_activity: 后突触激活 current_weight: 当前权重矩阵(如有) mode: 学习模式 Returns: weight_update: 权重更新量 """ mode = mode or self.mode lr = self.current_learning_rate # 外积得到更新矩阵 if pre_activity.ndim == 1: pre = pre_activity.reshape(-1, 1) post = post_activity.reshape(1, -1) else: pre = pre_activity post = post_activity hebbian_update = lr * np.dot(pre, post) if mode == HebbianMode.STANDARD and current_weight is not None: # 标准: 加上衰减项 update = hebbian_update - lr * self.decay_rate * current_weight elif mode == HebbianMode.OJA and current_weight is not None: # Oja法则: 抑制性项与post²成正比 post_squared = np.sum(post_activity ** 2) inhibition = lr * self.decay_rate * post_squared update = hebbian_update - inhibition * current_weight elif mode == HebbianMode.BCM: # BCM: 使用阈值φ(post) threshold = np.mean(post_activity) phi_post = post_activity * (post_activity - threshold) phi_post = phi_post.reshape(-1, 1) update = lr * (pre_activity.reshape(-1, 1) @ phi_post.T) # 衰减 if current_weight is not None: update -= lr * self.decay_rate * current_weight elif mode == HebbianMode.HOMEOSTATIC: # 稳态: 抑制过活跃的 activity_ratio = np.mean(post_activity) / (self._activity_stats.get('target', 0.5) + 1e-8) if activity_ratio > 1.0: # 过活跃,降低学习率 self.current_learning_rate = max(self.min_lr, lr * 0.5) else: self.current_learning_rate = min(self.max_lr, lr * 1.2) update = hebbian_update if current_weight is not None: update -= lr * self.decay_rate * current_weight else: update = hebbian_update return update # ============ 微柱间学习 ============ def register_micro_column(self, mc_name: str): """注册微柱以跟踪其激活""" if mc_name not in self._activation_history: self._activation_history[mc_name] = [] self._activity_stats[mc_name] = 0.0 def record_activation(self, mc_name: str, activation: np.ndarray): """记录微柱激活历史""" if mc_name not in self._activation_history: self.register_micro_column(mc_name) act = np.asarray(activation, dtype=np.float32).flatten() self._activation_history[mc_name].append(act.copy()) # 保持历史长度 if len(self._activation_history[mc_name]) > self._max_history: self._activation_history[mc_name].pop(0) # 更新活跃度统计 self._activity_stats[mc_name] = 0.9 * self._activity_stats.get(mc_name, 0) + 0.1 * np.mean(np.abs(act)) def learn_inter_column( self, source_mc: str, target_mc: str, source_activation: np.ndarray, target_activation: np.ndarray ) -> np.ndarray: """ 微柱间赫布学习 Args: source_mc: 源微柱名 target_mc: 目标微柱名 source_activation: 源激活 target_activation: 目标激活 Returns: weight_update: 权重更新 """ key = (source_mc, target_mc) # 获取或初始化权重 if key not in self._inter_column_weights: dim = min(len(source_activation), len(target_activation)) self._inter_column_weights[key] = np.random.randn(dim, dim).astype(np.float32) * 0.01 current_weights = self._inter_column_weights[key] # 调整维度 src = source_activation.flatten()[:current_weights.shape[0]] tgt = target_activation.flatten()[:current_weights.shape[1]] # 计算赫布更新 update = self.compute_hebbian_update(src, tgt, current_weights) # 应用更新 self._inter_column_weights[key] = np.clip( current_weights + update, -2.0, 2.0 ) self._total_updates += 1 return update def learn_coactivity( self, mc_pairs: List[Tuple[str, str]], activations: Dict[str, np.ndarray] ) -> int: """ 多微柱共活跃学习 Args: mc_pairs: 微柱对列表 [(mc1, mc2), ...] activations: 微柱激活字典 {mc_name: activation} Returns: updated_pairs: 更新的对数 """ updated = 0 for src, tgt in mc_pairs: if src in activations and tgt in activations: self.learn_inter_column( src, tgt, activations[src], activations[tgt] ) self._coactivity_events += 1 updated += 1 return updated # ============ 区域间学习 ============ def learn_area_association( self, area_a_name: str, area_b_name: str, area_a_output: np.ndarray, area_b_output: np.ndarray ) -> np.ndarray: """ 功能区之间的联想学习 两个区域同时活跃时,增强它们之间的联系 """ key = (f"area_{area_a_name}", f"area_{area_b_name}") if key not in self._inter_column_weights: dim_a = len(area_a_output) dim_b = len(area_b_output) self._inter_column_weights[key] = np.random.randn(dim_a, dim_b).astype(np.float32) * 0.01 weights = self._inter_column_weights[key] # 确保维度匹配 min_a = min(dim_a, weights.shape[0]) min_b = min(dim_b, weights.shape[1]) src = area_a_output.flatten()[:min_a] tgt = area_b_output.flatten()[:min_b] # 赫布更新 update = self.compute_hebbian_update(src, tgt, weights[:min_a, :min_b]) # 应用 self._inter_column_weights[key][:min_a, :min_b] = np.clip( weights[:min_a, :min_b] + update, -2.0, 2.0 ) return update # ============ 可塑性调节 ============ def adjust_learning_rate(self, task_difficulty: float, feedback_quality: float): """ 根据任务难度和反馈质量动态调整学习率 Args: task_difficulty: 0-1, 任务难度 feedback_quality: 0-1, 反馈质量(正确=1,错误=0) """ # 难任务需要更大学习率 difficulty_factor = 1.0 + task_difficulty # 高质量反馈可以大学习率 feedback_factor = 0.5 + 0.5 * feedback_quality # 计算新学习率 new_lr = self.base_learning_rate * difficulty_factor * feedback_factor self.current_learning_rate = np.clip(new_lr, self.min_lr, self.max_lr) def plasticity_regulation( self, recent_accuracy: float, stability_threshold: float = 0.9 ) -> str: """ 可塑性调节 - 根据准确性动态调整 Args: recent_accuracy: 近期准确率 stability_threshold: 稳定阈值 Returns: regulation_type: 'increase', 'decrease', 'maintain' """ if recent_accuracy < stability_threshold - 0.1: # 准确性下降,增加可塑性 self.current_learning_rate = min( self.max_lr, self.current_learning_rate * 1.5 ) return 'increase' elif recent_accuracy > stability_threshold: # 准确性很高,减少可塑性(巩固学习) self.current_learning_rate = max( self.min_lr, self.current_learning_rate * 0.8 ) return 'decrease' else: return 'maintain' # ============ 权重传播 ============ def propagate_activity( self, source_mc: str, target_mc: str, activation: np.ndarray ) -> np.ndarray: """ 通过学习到的权重传播激活 Args: source_mc: 源微柱 target_mc: 目标微柱 activation: 源激活 Returns: propagated: 传播后的激活 """ key = (source_mc, target_mc) if key not in self._inter_column_weights: return activation weights = self._inter_column_weights[key] # 维度适配 src = activation.flatten()[:weights.shape[0]] # 矩阵乘法 propagated = np.dot(weights, src) return propagated # ============ 统计与查询 ============ def get_inter_column_weights(self, source_mc: str, target_mc: str) -> Optional[np.ndarray]: """获取微柱间权重""" key = (source_mc, target_mc) return self._inter_column_weights.get(key) def get_learning_stats(self) -> Dict: """获取学习统计""" return { 'total_updates': self._total_updates, 'coactivity_events': self._coactivity_events, 'current_learning_rate': self.current_learning_rate, 'learning_mode': self.mode.value, 'registered_micro_columns': len(self._activation_history), 'inter_column_connections': len(self._inter_column_weights), 'activity_stats': {k: float(v) for k, v in self._activity_stats.items()} } def reset_learning(self): """重置学习状态(保留权重)""" self._activation_history = {k: [] for k in self._activation_history} self._activity_stats = {k: 0.0 for k in self._activity_stats} def clear_weights(self): """清除所有学习到的权重""" self._inter_column_weights = {} self._total_updates = 0 self._coactivity_events = 0