0
算数問題

画像認識10枚

0
0
$$$$

画像認識

      from collections import defaultdict
import matplotlib.pyplot as plt
import numpy as np
import random
from sklearn.datasets import load_digits
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
# =========================================================
# 1. 環境とデータの準備(手書き数字 64次元データ)
# =========================================================
np.random.seed(42)
random.seed(42)
digits = load_digits()
X_raw, y_raw = digits.data, digits.target
total_indices = np.random.choice(len(X_raw), 400, replace=False)
X_400, y_400 = X_raw[total_indices], y_raw[total_indices]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_400)
train_idx = []
for c in range(10):
    c_idxs = np.where(y_400 == c)[0]
    train_idx.extend(c_idxs[:1])
test_idx = [i for i in range(400) if i not in train_idx]
X_train, y_train = X_scaled[train_idx], y_400[train_idx]
X_test, y_test = X_scaled[test_idx], y_400[test_idx]
NUM_CLASSES = 10
INPUT_DIM = 64
# --- ハイパーパラメータ ---
INIT_CELLS = 350        # 最初から多めの細胞でスタート
MAX_CELLS = 4000
MIN_CELLS = 80
THOUGHT_STEPS = 9
DIVISION_THRESHOLD = 0.5
DEATH_THRESHOLD = 0.09
epochs = 30
# =========================================================
# 👥 2. 細胞の定義(4つの個性・役割分化の実装)
# =========================================================
class VisionMemoryCell:
    def __init__(self, cell_id):
        self.id = cell_id
        self.w_in = np.random.normal(0, 0.3, INPUT_DIM)
        self.A = np.ones(NUM_CLASSES) / NUM_CLASSES
        self.pos = np.random.uniform(-0.3, 0.2, 3)
        self.links = {} # 構造記憶を伴う動的シナプス
        
        self.visits = 0.0
        self.energy = 0.5
        self.recent_activity = 0.0
        
        # 役割(個性)の割り振り
        self.role = random.choice(["Explorer", "Storage", "Bridge", "Default"])
        
        if self.role == "Explorer":
            self.lr = 0.35          # 高い学習率
            self.a_decay = 0.70    # 忘却が早い
            self.div_rate = 1.2     # 分裂しやすい
        elif self.role == "Storage":
            self.lr = 0.08          # 慎重に学ぶ
            self.a_decay = 0.998    # ほぼ忘れない頑強なストレージ
            self.div_rate = 0.8
        elif self.role == "Bridge":
            self.lr = 0.20
            self.a_decay = 0.992
            self.div_rate = 1.0
            self.pos *= 0.5         # 橋渡し細胞は、初期配置を少し中心寄りに
        else: # Default
            self.lr = 0.20
            self.a_decay = 0.995
            self.div_rate = 1.0
def cosine_similarity(w, x):
    return np.dot(w, x) / (np.linalg.norm(w) * np.linalg.norm(x) + 1e-9)
def softmax(x, temp=1.0):
    x = np.array(x) / temp
    x = x - np.max(x)
    e = np.exp(x)
    return e / (np.sum(e) + 1e-12)
# =========================================================
# 🌐 3. 空間トポロジー力学(構造記憶 & グリッド高速化)
# =========================================================
def update_topology_with_memory(memory_space, radius_connect=1.5, decay=0.92):
    # 1. 既存リンクのマイルドな減衰(忘却)
    for cell in memory_space:
        cell.links = {k: v * decay for k, v in cell.links.items() if v * decay > 0.04}
        
    # 2. 現在の物理距離に基づくリンクの補強・新規開通
    num_cells = len(memory_space)
    for i in range(num_cells):
        for j in range(i + 1, num_cells):
            c1 = memory_space[i]
            c2 = memory_space[j]
            dist = np.linalg.norm(c1.pos - c2.pos)
            
            if dist < radius_connect:
                delta_w = (1.0 - (dist / radius_connect)) * 0.12
                c1.links[c2.id] = min(1.0, c1.links.get(c2.id, 0.0) + delta_w)
                c2.links[c1.id] = min(1.0, c2.links.get(c1.id, 0.0) + delta_w)
def update_cell_positions_fast(memory_space, path_history, grid_size=1.2):
    dt = 0.1
    num_cells = len(memory_space)
    if num_cells == 0: return
    forces = {c.id: np.zeros(3) for c in memory_space}
    
    # 1. 空間グリッドへ細胞を登録
    grid = defaultdict(list)
    for cell in memory_space:
        grid_key = tuple(np.floor(cell.pos / grid_size).astype(int))
        grid[grid_key].append(cell)
        
    # 2. 同一および隣接27マス内の近傍細胞間でのみ引力・斥力を計算
    for grid_key, cells_in_grid in grid.items():
        for dx in [-1, 0, 1]:
            for dy in [-1, 0, 1]:
                for dz in [-1, 0, 1]:
                    neighbor_key = (grid_key[0]+dx, grid_key[1]+dy, grid_key[2]+dz)
                    if neighbor_key not in grid: continue
                    
                    for c1 in cells_in_grid:
                        for c2 in grid[neighbor_key]:
                            if c1.id >= c2.id: continue
                            
                            direction = c2.pos - c1.pos
                            distance = np.linalg.norm(direction) + 1e-5
                            unit_dir = direction / distance
                            
                            repulsion = 0.03 / (distance ** 2)
                            sim_A = cosine_similarity(c1.A, c2.A)
                            
                            bridge_factor = 1.3 if (c1.role == "Bridge" or c2.role == "Bridge") else 1.0
                            
                            if sim_A > 0.6:
                                attraction = 0.08 * (sim_A - 0.6) * distance * bridge_factor
                                force_mag = -repulsion + attraction
                            else:
                                force_mag = -(repulsion + 0.05 * (0.6 - sim_A))
                                
                            forces[c1.id] += unit_dir * force_mag
                            forces[c2.id] -= unit_dir * force_mag
    # 3. ブラックホール化の防止:パスの隣接ノード間のみ引き合わせ
    for path in path_history:
        for i in range(len(path) - 1):
            u, v = path[i], path[i+1]
            if u not in forces or v not in forces: continue
            c_u = next((c for c in memory_space if c.id == u), None)
            c_v = next((c for c in memory_space if c.id == v), None)
            if not c_u or not c_v: continue
            
            dir_uv = c_v.pos - c_u.pos
            dist_uv = np.linalg.norm(dir_uv) + 1e-5
            forces[u] += (dir_uv / dist_uv) * 0.05 * dist_uv
            forces[v] -= (dir_uv / dist_uv) * 0.05 * dist_uv
                
    # 4. 位置更新
    for cell in memory_space:
        cell.pos += forces[cell.id] * dt
        cell.pos = np.clip(cell.pos, -4.0, 4.0)
# =========================================================
# 🔄 4. 融合生命ダイナミクス
# =========================================================
def live_vision_cycle(memory_space, x_64d=None, target_class=None, 
                      sensory_drive=1.0, intrinsic_drive=0.0, learning_gate=1.0):
    if len(memory_space) == 0: return np.zeros(NUM_CLASSES), np.zeros(INPUT_DIM), []
    id_to_cell = {c.id: c for c in memory_space}
    
    # --- 初期ノードの選択 ---
    start_probabilities = np.zeros(len(memory_space))
    if x_64d is not None and sensory_drive > 0.0:
        sims = np.array([cosine_similarity(cell.w_in, x_64d) for cell in memory_space])
        start_probabilities += softmax(sims, temp=0.1) * sensory_drive
    if intrinsic_drive > 0.0:
        activity_weights = np.array([cell.energy * (cell.recent_activity + 0.05) for cell in memory_space])
        start_probabilities += (activity_weights / (np.sum(activity_weights) + 1e-12)) * intrinsic_drive
        
    if np.sum(start_probabilities) == 0: 
        start_probabilities = np.ones(len(memory_space)) / len(memory_space)
    start_probabilities /= np.sum(start_probabilities)
    
    current_cell_id = np.random.choice(list(id_to_cell.keys()), p=start_probabilities)
    path = [current_cell_id]
    
    collected_signals = [id_to_cell[current_cell_id].A.copy()]
    imagined_pixels = [id_to_cell[current_cell_id].w_in.copy()]
    
    # --- 思考のグラフウォーク ---
    for step in range(THOUGHT_STEPS - 1):
        current_cell = id_to_cell[current_cell_id]
        current_cell.recent_activity += sensory_drive * 1.0
        
        all_ids = list(id_to_cell.keys())
        
        # Explorerのランダム探索
        if current_cell.role == "Explorer" and random.random() < 0.25:
            current_cell_id = random.choice(all_ids)
            path.append(current_cell_id)
            collected_signals.append(id_to_cell[current_cell_id].A.copy())
            imagined_pixels.append(id_to_cell[current_cell_id].w_in.copy())
            continue
            
        candidates = set(np.random.choice(all_ids, min(20, len(all_ids)), replace=False))
        candidates.update(current_cell.links.keys())
        
        scores = []
        c_ids = []
        for cid in candidates:
            if cid in path or cid not in id_to_cell: continue
            cell = id_to_cell[cid]
            
            score = current_cell.links.get(cid, 0.0) * 3.0
            if x_64d is not None:
                score += 2.0 * cosine_similarity(cell.w_in, x_64d) * sensory_drive
            
            score += 0.8 * cosine_similarity(current_cell.A, cell.A)
            
            if cell.role == "Bridge":
                score *= 2.5
                
            scores.append(score)
            c_ids.append(cid)
            
        if not scores: break
        probs = softmax(scores, temp=0.3)
        current_cell_id = np.random.choice(c_ids, p=probs)
        path.append(current_cell_id)
        
        collected_signals.append(id_to_cell[current_cell_id].A.copy())
        imagined_pixels.append(id_to_cell[current_cell_id].w_in.copy())
        
    final_perception = np.mean(np.stack(collected_signals), axis=0) if collected_signals else np.zeros(NUM_CLASSES)
    final_image = np.mean(np.stack(imagined_pixels), axis=0) if imagined_pixels else np.zeros(INPUT_DIM)
    
    sensory_factor = sensory_drive * learning_gate
    inferred_class = np.argmax(final_perception)
    target = target_class if target_class is not None else inferred_class
    
    target_vec = np.zeros(NUM_CLASSES)
    target_vec[target] = 1.0
    
    # --- 報酬設計(分類改善量) ---
    base_reward = min(1.0 / (np.linalg.norm(target_vec - final_perception) + 0.15), 2.5) * 1.5
    
    novelty_reward = 0.0
    for cid in path:
        if cid in id_to_cell and id_to_cell[cid].visits < 4.0:
            novelty_reward += 0.10
            
    info_gain = 0.0
    if len(collected_signals) > 1:
        first_error = np.linalg.norm(target_vec - collected_signals[0])
        final_error = np.linalg.norm(target_vec - final_perception)
        info_gain = max(0.0, first_error - final_error) * 2.0
        
    reward = base_reward + novelty_reward + info_gain
    
    # --- 側頭抑制 ---
    for cid in path:
        if cid in id_to_cell:
            for neighbor_id in id_to_cell[cid].links.keys():
                if neighbor_id not in path and neighbor_id in id_to_cell:
                    id_to_cell[neighbor_id].energy *= 0.96
    # --- 🧠 Aベクトル & w_inの更新(ユニーク化&揺らぎ) ---
    if x_64d is not None and sensory_factor > 0.0:
        unique_visited_ids = set(path)
        
        for cid in unique_visited_ids:
            if cid not in id_to_cell: continue
            cell = id_to_cell[cid]
            
            if random.random() < 0.10: # 10%でドロップアウト
                continue 
            
            if cell.role == "Explorer":
                noise = np.random.normal(0, 0.12)
                dynamic_lr = max(0.05, cell.lr + noise)
            else:
                noise = np.random.normal(0, 0.05)
                dynamic_lr = max(0.01, cell.lr + noise)
            
            cell.visits += sensory_factor
            cell.energy = min(1.0, cell.energy + reward * 0.12 * sensory_factor)
            
            cell.w_in += (dynamic_lr * 0.5 * sensory_factor) * (x_64d - cell.w_in)
            cell.A += (dynamic_lr * sensory_factor) * target_vec
            cell.A *= cell.a_decay
            cell.A /= (np.sum(cell.A) + 1e-12)
                                    
    return final_perception, final_image, path
# =========================================================
# 🧬 5. 代謝・新陳代謝コア(個性の遺伝と変異)
# =========================================================
def evolve_and_prune_space(memory_space):
    for cell in memory_space:
        cell.energy *= 0.90
        cell.recent_activity *= 0.50
        if cell.energy < 0.01: cell.energy = 0.01
        
    new_cells = []
    current_max_id = max([c.id for c in memory_space]) if memory_space else 0
    for cell in memory_space:
        if len(memory_space) + len(new_cells) >= MAX_CELLS: break
        
        if cell.energy > (DIVISION_THRESHOLD * (2.0 - cell.div_rate)) and cell.visits > 10:
            child = VisionMemoryCell(current_max_id + len(new_cells) + 1)
            child.w_in = np.clip(cell.w_in + np.random.normal(0, 0.05, INPUT_DIM), -3.0, 3.0)
            child.A = cell.A.copy()
            child.pos = cell.pos + np.random.normal(0, 0.1, 3)
            
            child.role = cell.role
            child.lr = cell.lr
            child.a_decay = cell.a_decay
            child.div_rate = cell.div_rate
            
            cell.energy *= 0.3
            cell.visits *= 0.5
            child.energy = 0.2
            new_cells.append(child)
            
    memory_space.extend(new_cells)
    
    survived_space = []
    id_map = {}
    for cell in memory_space:
        # 生存条件チェック
        if len(survived_space) > MIN_CELLS:
            if cell.energy < DEATH_THRESHOLD and cell.visits < 1.0:
                continue
        id_map[cell.id] = len(survived_space)
        cell.id = id_map[cell.id]
        survived_space.append(cell)
        
    # 生存した細胞たちのリンクインデックス書き換え(消滅した細胞へのリンクを排除)
    for cell in survived_space:
        cell.links = {id_map[old_id]: w for old_id, w in cell.links.items() if old_id in id_map}
        
    return survived_space
# =========================================================
# 👥 6. エコシステム・統合管理クラス
# =========================================================
class EnsembleVisionEcosystem:
    def __init__(self, n_estimators=3, total_cells=2500):
        self.n_estimators = n_estimators
        self.models = []
        for _ in range(n_estimators):
            space = [VisionMemoryCell(i) for i in range(total_cells)]
            update_topology_with_memory(space) 
            self.models.append({'space': space})
            
    def train_cycle(self, X, y, phase="day"):
        for model in self.models:
            indices = np.random.choice(len(X), len(X), replace=True)
            path_history = []
            
            for idx in indices:
                s_drive = 1.0 if phase == "day" else 0.3
                i_drive = 0.0 if phase == "day" else 0.7
                _, _, path = live_vision_cycle(model['space'], x_64d=X[idx], target_class=y[idx], 
                                              sensory_drive=s_drive, intrinsic_drive=i_drive)
                if path: path_history.append(path)
                
            update_cell_positions_fast(model['space'], path_history)
            update_topology_with_memory(model['space'])
    def sleep_cycle(self, steps=30):
        for model in self.models:
            path_history = []
            for _ in range(steps):
                _, _, path = live_vision_cycle(model['space'], x_64d=None, target_class=None, 
                                              sensory_drive=0.0, intrinsic_drive=1.0)
                if path: path_history.append(path)
            update_cell_positions_fast(model['space'], path_history)
            update_topology_with_memory(model['space'])
    def evolve(self):
        for model in self.models:
            model['space'] = evolve_and_prune_space(model['space'])
            update_topology_with_memory(model['space'])
    def predict(self, X):
        y_pred = []
        for idx in range(len(X)):
            ensemble_perceptions = []
            ensemble_confidences = []
            
            for model in self.models:
                perception, _, _ = live_vision_cycle(
                    model['space'], x_64d=X[idx], 
                    sensory_drive=1.0, intrinsic_drive=0.0, learning_gate=0.0
                )
                confidence = np.max(perception)
                ensemble_perceptions.append(perception)
                ensemble_confidences.append(confidence)
            
            weighted_perceptions = np.zeros(NUM_CLASSES)
            total_conf = sum(ensemble_confidences) + 1e-12
            
            for p, c in zip(ensemble_perceptions, ensemble_confidences):
                weighted_perceptions += p * (c / total_conf)
                
            y_pred.append(np.argmax(weighted_perceptions))
        return y_pred
# =========================================================
# 🚀 7. 巡礼シミュレーションの実行
# =========================================================
print("=== 🌐 構造記憶&細胞社会性を持つ自己組織化認知生態系 起動 ===")
ecosystem = EnsembleVisionEcosystem(n_estimators=3, total_cells=INIT_CELLS)
for cycle in range(epochs):
    ecosystem.train_cycle(X_train, y_train, phase="day")
    ecosystem.train_cycle(X_train, y_train, phase="evening")
    ecosystem.sleep_cycle(steps=30)
    ecosystem.evolve()
    
    y_pred = ecosystem.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    avg_cells = int(np.mean([len(m['space']) for m in ecosystem.models]))
    
    roles_count = defaultdict(int)
    for c in ecosystem.models[0]['space']: roles_count[c.role] += 1
    roles_str = ", ".join([f"{k}:{v}" for k, v in roles_count.items()])
    
    print(f"Cycle {cycle+1:02d}/{epochs} | 総細胞数: {avg_cells:>3} | 正解率: {acc:.4f} | 社会組成: [{roles_str}]")
# =========================================================
# 8. ダッシュボード:3D空間上の細胞役割の可視化
# =========================================================
print("\n[Visualizing Evolved Neural Social Topology...]")
fig = plt.figure(figsize=(9, 7))
ax = fig.add_subplot(111, projection='3d')
ax.set_title("Evolved Concept Space: Grid-optimized & Engram-linked")
first_space = ecosystem.models[0]['space']
role_markers = {"Explorer": "o", "Storage": "s", "Bridge": "^", "Default": "D"}
role_colors = {"Explorer": "cyan", "Storage": "orange", "Bridge": "magenta", "Default": "gray"}
for role in ["Explorer", "Storage", "Bridge", "Default"]:
    r_cells = [c for c in first_space if c.role == role]
    if not r_cells: continue
    ax.scatter([c.pos[0] for c in r_cells], 
               [c.pos[1] for c in r_cells], 
               [c.pos[2] for c in r_cells], 
               c=role_colors[role], marker=role_markers[role], s=50, label=role, edgecolors='black', alpha=0.8)
ax.legend()
plt.show()
    
      from collections import defaultdict
import matplotlib.pyplot as plt
import numpy as np
import random
from sklearn.datasets import load_digits
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
# =========================================================
# 1. 環境とデータの準備(手書き数字 64次元データ)
# =========================================================
np.random.seed(42)
random.seed(42)
digits = load_digits()
X_raw, y_raw = digits.data, digits.target
total_indices = np.random.choice(len(X_raw), 400, replace=False)
X_400, y_400 = X_raw[total_indices], y_raw[total_indices]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_400)
train_idx = []
for c in range(10):
    c_idxs = np.where(y_400 == c)[0]
    train_idx.extend(c_idxs[:1])
test_idx = [i for i in range(400) if i not in train_idx]
X_train, y_train = X_scaled[train_idx], y_400[train_idx]
X_test, y_test = X_scaled[test_idx], y_400[test_idx]
NUM_CLASSES = 10
INPUT_DIM = 64
# --- ハイパーパラメータ ---
INIT_CELLS = 350        # 最初から多めの細胞でスタート
MAX_CELLS = 4000
MIN_CELLS = 80
THOUGHT_STEPS = 9
DIVISION_THRESHOLD = 0.5
DEATH_THRESHOLD = 0.09
epochs = 30
# =========================================================
# 👥 2. 細胞の定義(4つの個性・役割分化の実装)
# =========================================================
class VisionMemoryCell:
    def __init__(self, cell_id):
        self.id = cell_id
        self.w_in = np.random.normal(0, 0.3, INPUT_DIM)
        self.A = np.ones(NUM_CLASSES) / NUM_CLASSES
        self.pos = np.random.uniform(-0.3, 0.2, 3)
        self.links = {} # 構造記憶を伴う動的シナプス
        
        self.visits = 0.0
        self.energy = 0.5
        self.recent_activity = 0.0
        
        # 役割(個性)の割り振り
        self.role = random.choice(["Explorer", "Storage", "Bridge", "Default"])
        
        if self.role == "Explorer":
            self.lr = 0.35          # 高い学習率
            self.a_decay = 0.70    # 忘却が早い
            self.div_rate = 1.2     # 分裂しやすい
        elif self.role == "Storage":
            self.lr = 0.08          # 慎重に学ぶ
            self.a_decay = 0.998    # ほぼ忘れない頑強なストレージ
            self.div_rate = 0.8
        elif self.role == "Bridge":
            self.lr = 0.20
            self.a_decay = 0.992
            self.div_rate = 1.0
            self.pos *= 0.5         # 橋渡し細胞は、初期配置を少し中心寄りに
        else: # Default
            self.lr = 0.20
            self.a_decay = 0.995
            self.div_rate = 1.0
def cosine_similarity(w, x):
    return np.dot(w, x) / (np.linalg.norm(w) * np.linalg.norm(x) + 1e-9)
def softmax(x, temp=1.0):
    x = np.array(x) / temp
    x = x - np.max(x)
    e = np.exp(x)
    return e / (np.sum(e) + 1e-12)
# =========================================================
# 🌐 3. 空間トポロジー力学(構造記憶 & グリッド高速化)
# =========================================================
def update_topology_with_memory(memory_space, radius_connect=1.5, decay=0.92):
    # 1. 既存リンクのマイルドな減衰(忘却)
    for cell in memory_space:
        cell.links = {k: v * decay for k, v in cell.links.items() if v * decay > 0.04}
        
    # 2. 現在の物理距離に基づくリンクの補強・新規開通
    num_cells = len(memory_space)
    for i in range(num_cells):
        for j in range(i + 1, num_cells):
            c1 = memory_space[i]
            c2 = memory_space[j]
            dist = np.linalg.norm(c1.pos - c2.pos)
            
            if dist < radius_connect:
                delta_w = (1.0 - (dist / radius_connect)) * 0.12
                c1.links[c2.id] = min(1.0, c1.links.get(c2.id, 0.0) + delta_w)
                c2.links[c1.id] = min(1.0, c2.links.get(c1.id, 0.0) + delta_w)
def update_cell_positions_fast(memory_space, path_history, grid_size=1.2):
    dt = 0.1
    num_cells = len(memory_space)
    if num_cells == 0: return
    forces = {c.id: np.zeros(3) for c in memory_space}
    
    # 1. 空間グリッドへ細胞を登録
    grid = defaultdict(list)
    for cell in memory_space:
        grid_key = tuple(np.floor(cell.pos / grid_size).astype(int))
        grid[grid_key].append(cell)
        
    # 2. 同一および隣接27マス内の近傍細胞間でのみ引力・斥力を計算
    for grid_key, cells_in_grid in grid.items():
        for dx in [-1, 0, 1]:
            for dy in [-1, 0, 1]:
                for dz in [-1, 0, 1]:
                    neighbor_key = (grid_key[0]+dx, grid_key[1]+dy, grid_key[2]+dz)
                    if neighbor_key not in grid: continue
                    
                    for c1 in cells_in_grid:
                        for c2 in grid[neighbor_key]:
                            if c1.id >= c2.id: continue
                            
                            direction = c2.pos - c1.pos
                            distance = np.linalg.norm(direction) + 1e-5
                            unit_dir = direction / distance
                            
                            repulsion = 0.03 / (distance ** 2)
                            sim_A = cosine_similarity(c1.A, c2.A)
                            
                            bridge_factor = 1.3 if (c1.role == "Bridge" or c2.role == "Bridge") else 1.0
                            
                            if sim_A > 0.6:
                                attraction = 0.08 * (sim_A - 0.6) * distance * bridge_factor
                                force_mag = -repulsion + attraction
                            else:
                                force_mag = -(repulsion + 0.05 * (0.6 - sim_A))
                                
                            forces[c1.id] += unit_dir * force_mag
                            forces[c2.id] -= unit_dir * force_mag
    # 3. ブラックホール化の防止:パスの隣接ノード間のみ引き合わせ
    for path in path_history:
        for i in range(len(path) - 1):
            u, v = path[i], path[i+1]
            if u not in forces or v not in forces: continue
            c_u = next((c for c in memory_space if c.id == u), None)
            c_v = next((c for c in memory_space if c.id == v), None)
            if not c_u or not c_v: continue
            
            dir_uv = c_v.pos - c_u.pos
            dist_uv = np.linalg.norm(dir_uv) + 1e-5
            forces[u] += (dir_uv / dist_uv) * 0.05 * dist_uv
            forces[v] -= (dir_uv / dist_uv) * 0.05 * dist_uv
                
    # 4. 位置更新
    for cell in memory_space:
        cell.pos += forces[cell.id] * dt
        cell.pos = np.clip(cell.pos, -4.0, 4.0)
# =========================================================
# 🔄 4. 融合生命ダイナミクス
# =========================================================
def live_vision_cycle(memory_space, x_64d=None, target_class=None, 
                      sensory_drive=1.0, intrinsic_drive=0.0, learning_gate=1.0):
    if len(memory_space) == 0: return np.zeros(NUM_CLASSES), np.zeros(INPUT_DIM), []
    id_to_cell = {c.id: c for c in memory_space}
    
    # --- 初期ノードの選択 ---
    start_probabilities = np.zeros(len(memory_space))
    if x_64d is not None and sensory_drive > 0.0:
        sims = np.array([cosine_similarity(cell.w_in, x_64d) for cell in memory_space])
        start_probabilities += softmax(sims, temp=0.1) * sensory_drive
    if intrinsic_drive > 0.0:
        activity_weights = np.array([cell.energy * (cell.recent_activity + 0.05) for cell in memory_space])
        start_probabilities += (activity_weights / (np.sum(activity_weights) + 1e-12)) * intrinsic_drive
        
    if np.sum(start_probabilities) == 0: 
        start_probabilities = np.ones(len(memory_space)) / len(memory_space)
    start_probabilities /= np.sum(start_probabilities)
    
    current_cell_id = np.random.choice(list(id_to_cell.keys()), p=start_probabilities)
    path = [current_cell_id]
    
    collected_signals = [id_to_cell[current_cell_id].A.copy()]
    imagined_pixels = [id_to_cell[current_cell_id].w_in.copy()]
    
    # --- 思考のグラフウォーク ---
    for step in range(THOUGHT_STEPS - 1):
        current_cell = id_to_cell[current_cell_id]
        current_cell.recent_activity += sensory_drive * 1.0
        
        all_ids = list(id_to_cell.keys())
        
        # Explorerのランダム探索
        if current_cell.role == "Explorer" and random.random() < 0.25:
            current_cell_id = random.choice(all_ids)
            path.append(current_cell_id)
            collected_signals.append(id_to_cell[current_cell_id].A.copy())
            imagined_pixels.append(id_to_cell[current_cell_id].w_in.copy())
            continue
            
        candidates = set(np.random.choice(all_ids, min(20, len(all_ids)), replace=False))
        candidates.update(current_cell.links.keys())
        
        scores = []
        c_ids = []
        for cid in candidates:
            if cid in path or cid not in id_to_cell: continue
            cell = id_to_cell[cid]
            
            score = current_cell.links.get(cid, 0.0) * 3.0
            if x_64d is not None:
                score += 2.0 * cosine_similarity(cell.w_in, x_64d) * sensory_drive
            
            score += 0.8 * cosine_similarity(current_cell.A, cell.A)
            
            if cell.role == "Bridge":
                score *= 2.5
                
            scores.append(score)
            c_ids.append(cid)
            
        if not scores: break
        probs = softmax(scores, temp=0.3)
        current_cell_id = np.random.choice(c_ids, p=probs)
        path.append(current_cell_id)
        
        collected_signals.append(id_to_cell[current_cell_id].A.copy())
        imagined_pixels.append(id_to_cell[current_cell_id].w_in.copy())
        
    final_perception = np.mean(np.stack(collected_signals), axis=0) if collected_signals else np.zeros(NUM_CLASSES)
    final_image = np.mean(np.stack(imagined_pixels), axis=0) if imagined_pixels else np.zeros(INPUT_DIM)
    
    sensory_factor = sensory_drive * learning_gate
    inferred_class = np.argmax(final_perception)
    target = target_class if target_class is not None else inferred_class
    
    target_vec = np.zeros(NUM_CLASSES)
    target_vec[target] = 1.0
    
    # --- 報酬設計(分類改善量) ---
    base_reward = min(1.0 / (np.linalg.norm(target_vec - final_perception) + 0.15), 2.5) * 1.5
    
    novelty_reward = 0.0
    for cid in path:
        if cid in id_to_cell and id_to_cell[cid].visits < 4.0:
            novelty_reward += 0.10
            
    info_gain = 0.0
    if len(collected_signals) > 1:
        first_error = np.linalg.norm(target_vec - collected_signals[0])
        final_error = np.linalg.norm(target_vec - final_perception)
        info_gain = max(0.0, first_error - final_error) * 2.0
        
    reward = base_reward + novelty_reward + info_gain
    
    # --- 側頭抑制 ---
    for cid in path:
        if cid in id_to_cell:
            for neighbor_id in id_to_cell[cid].links.keys():
                if neighbor_id not in path and neighbor_id in id_to_cell:
                    id_to_cell[neighbor_id].energy *= 0.96
    # --- 🧠 Aベクトル & w_inの更新(ユニーク化&揺らぎ) ---
    if x_64d is not None and sensory_factor > 0.0:
        unique_visited_ids = set(path)
        
        for cid in unique_visited_ids:
            if cid not in id_to_cell: continue
            cell = id_to_cell[cid]
            
            if random.random() < 0.10: # 10%でドロップアウト
                continue 
            
            if cell.role == "Explorer":
                noise = np.random.normal(0, 0.12)
                dynamic_lr = max(0.05, cell.lr + noise)
            else:
                noise = np.random.normal(0, 0.05)
                dynamic_lr = max(0.01, cell.lr + noise)
            
            cell.visits += sensory_factor
            cell.energy = min(1.0, cell.energy + reward * 0.12 * sensory_factor)
            
            cell.w_in += (dynamic_lr * 0.5 * sensory_factor) * (x_64d - cell.w_in)
            cell.A += (dynamic_lr * sensory_factor) * target_vec
            cell.A *= cell.a_decay
            cell.A /= (np.sum(cell.A) + 1e-12)
                                    
    return final_perception, final_image, path
# =========================================================
# 🧬 5. 代謝・新陳代謝コア(個性の遺伝と変異)
# =========================================================
def evolve_and_prune_space(memory_space):
    for cell in memory_space:
        cell.energy *= 0.90
        cell.recent_activity *= 0.50
        if cell.energy < 0.01: cell.energy = 0.01
        
    new_cells = []
    current_max_id = max([c.id for c in memory_space]) if memory_space else 0
    for cell in memory_space:
        if len(memory_space) + len(new_cells) >= MAX_CELLS: break
        
        if cell.energy > (DIVISION_THRESHOLD * (2.0 - cell.div_rate)) and cell.visits > 10:
            child = VisionMemoryCell(current_max_id + len(new_cells) + 1)
            child.w_in = np.clip(cell.w_in + np.random.normal(0, 0.05, INPUT_DIM), -3.0, 3.0)
            child.A = cell.A.copy()
            child.pos = cell.pos + np.random.normal(0, 0.1, 3)
            
            child.role = cell.role
            child.lr = cell.lr
            child.a_decay = cell.a_decay
            child.div_rate = cell.div_rate
            
            cell.energy *= 0.3
            cell.visits *= 0.5
            child.energy = 0.2
            new_cells.append(child)
            
    memory_space.extend(new_cells)
    
    survived_space = []
    id_map = {}
    for cell in memory_space:
        # 生存条件チェック
        if len(survived_space) > MIN_CELLS:
            if cell.energy < DEATH_THRESHOLD and cell.visits < 1.0:
                continue
        id_map[cell.id] = len(survived_space)
        cell.id = id_map[cell.id]
        survived_space.append(cell)
        
    # 生存した細胞たちのリンクインデックス書き換え(消滅した細胞へのリンクを排除)
    for cell in survived_space:
        cell.links = {id_map[old_id]: w for old_id, w in cell.links.items() if old_id in id_map}
        
    return survived_space
# =========================================================
# 👥 6. エコシステム・統合管理クラス
# =========================================================
class EnsembleVisionEcosystem:
    def __init__(self, n_estimators=3, total_cells=2500):
        self.n_estimators = n_estimators
        self.models = []
        for _ in range(n_estimators):
            space = [VisionMemoryCell(i) for i in range(total_cells)]
            update_topology_with_memory(space) 
            self.models.append({'space': space})
            
    def train_cycle(self, X, y, phase="day"):
        for model in self.models:
            indices = np.random.choice(len(X), len(X), replace=True)
            path_history = []
            
            for idx in indices:
                s_drive = 1.0 if phase == "day" else 0.3
                i_drive = 0.0 if phase == "day" else 0.7
                _, _, path = live_vision_cycle(model['space'], x_64d=X[idx], target_class=y[idx], 
                                              sensory_drive=s_drive, intrinsic_drive=i_drive)
                if path: path_history.append(path)
                
            update_cell_positions_fast(model['space'], path_history)
            update_topology_with_memory(model['space'])
    def sleep_cycle(self, steps=30):
        for model in self.models:
            path_history = []
            for _ in range(steps):
                _, _, path = live_vision_cycle(model['space'], x_64d=None, target_class=None, 
                                              sensory_drive=0.0, intrinsic_drive=1.0)
                if path: path_history.append(path)
            update_cell_positions_fast(model['space'], path_history)
            update_topology_with_memory(model['space'])
    def evolve(self):
        for model in self.models:
            model['space'] = evolve_and_prune_space(model['space'])
            update_topology_with_memory(model['space'])
    def predict(self, X):
        y_pred = []
        for idx in range(len(X)):
            ensemble_perceptions = []
            ensemble_confidences = []
            
            for model in self.models:
                perception, _, _ = live_vision_cycle(
                    model['space'], x_64d=X[idx], 
                    sensory_drive=1.0, intrinsic_drive=0.0, learning_gate=0.0
                )
                confidence = np.max(perception)
                ensemble_perceptions.append(perception)
                ensemble_confidences.append(confidence)
            
            weighted_perceptions = np.zeros(NUM_CLASSES)
            total_conf = sum(ensemble_confidences) + 1e-12
            
            for p, c in zip(ensemble_perceptions, ensemble_confidences):
                weighted_perceptions += p * (c / total_conf)
                
            y_pred.append(np.argmax(weighted_perceptions))
        return y_pred
# =========================================================
# 🚀 7. 巡礼シミュレーションの実行
# =========================================================
print("=== 🌐 構造記憶&細胞社会性を持つ自己組織化認知生態系 起動 ===")
ecosystem = EnsembleVisionEcosystem(n_estimators=3, total_cells=INIT_CELLS)
for cycle in range(epochs):
    ecosystem.train_cycle(X_train, y_train, phase="day")
    ecosystem.train_cycle(X_train, y_train, phase="evening")
    ecosystem.sleep_cycle(steps=30)
    ecosystem.evolve()
    
    y_pred = ecosystem.predict(X_test)
    acc = accuracy_score(y_test, y_pred)
    avg_cells = int(np.mean([len(m['space']) for m in ecosystem.models]))
    
    roles_count = defaultdict(int)
    for c in ecosystem.models[0]['space']: roles_count[c.role] += 1
    roles_str = ", ".join([f"{k}:{v}" for k, v in roles_count.items()])
    
    print(f"Cycle {cycle+1:02d}/{epochs} | 総細胞数: {avg_cells:>3} | 正解率: {acc:.4f} | 社会組成: [{roles_str}]")
# =========================================================
# 8. ダッシュボード:3D空間上の細胞役割の可視化
# =========================================================
print("\n[Visualizing Evolved Neural Social Topology...]")
fig = plt.figure(figsize=(9, 7))
ax = fig.add_subplot(111, projection='3d')
ax.set_title("Evolved Concept Space: Grid-optimized & Engram-linked")
first_space = ecosystem.models[0]['space']
role_markers = {"Explorer": "o", "Storage": "s", "Bridge": "^", "Default": "D"}
role_colors = {"Explorer": "cyan", "Storage": "orange", "Bridge": "magenta", "Default": "gray"}
for role in ["Explorer", "Storage", "Bridge", "Default"]:
    r_cells = [c for c in first_space if c.role == role]
    if not r_cells: continue
    ax.scatter([c.pos[0] for c in r_cells], 
               [c.pos[1] for c in r_cells], 
               [c.pos[2] for c in r_cells], 
               c=role_colors[role], marker=role_markers[role], s=50, label=role, edgecolors='black', alpha=0.8)
ax.legend()
plt.show()
    
投稿日:20日前
数学の力で現場を変える アルゴリズムエンジニア募集 - Mathlog served by OptHub

この記事を高評価した人

高評価したユーザはいません

この記事に送られたバッジ

バッジはありません。

投稿者

Owl
1
288

コメント

他の人のコメント

コメントはありません。
読み込み中...
読み込み中