资讯详情

166,700 个真实果蝇神经元在浏览器里玩 Flappy Bird

📅 2026/9/24 6:19:26 | 华诺云谱 👁 阅读
166,700 个真实果蝇神经元在浏览器里玩 Flappy Bird
玩到一个很有意思的项目果蝇大脑玩 Flappy Bird这不是一个游戏 demo这是一次神经科学实验——把真实的果蝇连接组接入游戏世界看它能不能自己学会飞行。这个项目到底解决了什么问题如果你问一个神经科学家果蝇的大脑能不能学会玩电子游戏他大概率会告诉你——这个问题本身就没有意义。果蝇没有玩的概念它的神经系统演化出来是为了在真实世界中觅食、求偶、逃避天敌不是为了在一根管道中间钻来钻去。但这个问题背后藏着一个真正硬核的技术挑战你能不能把一个完整的、真实的、未经修改的生物大脑放进浏览器里让它接收人工感觉信号然后产生自主行为这不是训练一个神经网络去玩游戏。那种事情我们已经见得太多了——PPO、DQN、NEAT随便哪个强化学习算法都能在 Flappy Bird 上刷到几百分。那些是人工智能不是生物智能。这个项目做的事情完全不同连接组是冻结的。166,700 个神经元、25,088,107 条突触连接全部来自 MaleCNS v1.0 真实果蝇大脑扫描数据。没有任何一条连接的权重被修改过。这不是训练这是移植。计算在浏览器里完成。不是 GPU 集群不是云端推理——是你的浏览器里的一个 Web Worker以 50Hz 的频率模拟整个果蝇大脑的神经活动。行为从神经活动中涌现。没有if bird.y gap.y then flap()这样的硬编码规则。游戏画面被编码成果蝇能看到的神经刺激经过 16 万个神经元的传播和计算最终从下行神经元的活动中解码出拍翅指令。一句话总结创新点这是世界上第一个在浏览器中运行的完整果蝇连接组行为实验。创新点一把游戏画面翻译成果蝇能看见的东西果蝇没有视网膜上的像素。它的复眼由大约 800 个小眼组成每个小眼感知一个方向的光强变化。所以我们不能简单地把 Flappy Bird 的截图喂给果蝇大脑——那就像把一本量子力学教材塞进一台收音机。我们需要一个编码器FlyEncoder把游戏状态翻译成特定视觉神经元的刺激信号。这个编码器的设计不是拍脑袋想出来的而是基于果蝇视觉系统的神经科学文献。LC4 和 LPLC2碰撞检测器果蝇有一套精密的 looming detection系统。当你用手快速接近果蝇的眼睛时它会在几毫秒内启动逃避反应。这套反应由 LC4Lobula Columnar type 4和 LPLC2Lobula Plate Columnar type 2神经元介导。它们对快速逼近的物体特别敏感——物体在视野中越大、越近这些神经元就越活跃。在编码器中我们把水管到果蝇的距离映射成 LC4/LPLC2 的刺激强度approachIntensity clamp(1 - distance / 300, 0, 1)当水管距离 300 像素时刺激几乎为零——对果蝇来说那个水管还看不见。当水管距离 30 像素时刺激达到最大值 1.0——这就像水管已经怼到果蝇脸上了。水管距离LC4 刺激生物学类比 300px0.05物体在视野边缘几乎无感200px0.25物体进入中央视野100px0.60物体快速逼近逃避系统激活 30px1.00imminent collision全力逃避LC10a-L / LC10a-R方向感知仅仅知道有东西在逼近是不够的。果蝇还需要知道洞口在上方还是下方。我们用 LC10a 神经元的左右两个通道来编码垂直误差error gapCenterY - birdY if error 0: // 果蝇低于洞口 LC10a-L normalizedError // 目标在上方信号 LC10a-R 0 else: // 果蝇高于洞口 LC10a-L 0 LC10a-R normalizedError // 目标在下方信号这不是随意选择的映射。LC10a 在果蝇大脑中参与视觉追踪和目标定向行为将它映射为方向误差是有神经科学依据的。速度通道惯性感知果蝇不只需要知道在哪还需要知道往哪走。一个正在高速上升的果蝇即使位置还低于洞口也不应该再拍翅膀——否则就会冲出顶部边界。编码器用两个辅助通道编码速度信息velocityY 0 → UPWARD 通道激活 velocityY 0 → DOWNWARD 通道激活 强度 clamp(|velocityY| / 520, 0, 1)这四个通道LC4、LPLC2、LC10a-L/R、UPWARD/DOWNWARD共同构成了果蝇对游戏世界的全部感知。没有全局视野没有像素级输入只有六个标量信号——就像果蝇在真实世界中依赖的有限感觉线索。创新点二在浏览器 Web Worker 里跑 16 万个 LIF 神经元有了感觉输入下一步是让这些信号在果蝇大脑中传播。这里的核心是LIFLeaky Integrate-and-Fire神经元模型——计算神经科学中最经典、最广泛使用的简化模型。LIF 模型简单但不简陋每个神经元的状态更新方程是这样的v[t1] decay × v[t] gain × current[t] tonic drive其中v[t]是神经元当前的膜电位0 到 1 之间decay exp(-dt/tau)是漏电衰减因子模拟细胞膜的被动放电current[t]是上游神经元传来的突触电流总和tonic是基础张力电流让神经元保持一定的自发活动drive是外部感觉刺激来自编码器的 LC4/LPLC2/LC10a 输入当膜电位v 1时神经元发放一个动作电位spike膜电位重置为 0。这个 spike 会通过突触连接传递给下游神经元形成级联反应。25M 条连接的稀疏表示166,700 个神经元之间的连接矩阵有 25,088,107 条有效突触。如果用稠密矩阵表示需要 166,700 × 166,700 278 亿个元素——这显然不现实。项目采用了一种精心设计的压缩稀疏列CSC格式配合自定义的 FLYW 二进制编码colPtr每列的非零元素累积数量varint 编码rowIdx每个非零元素的行索引varint delta 编码code8-bit 量化权重码通过 256 项查找表LUT映射回浮点值整个 25M 条连接的权重数据被压缩到57.6 MB两个 .bin 文件。权重量化的平均误差仅为 0.023最大误差 0.047——对于生物神经网络的模拟来说这个精度绰绰有余。Web Worker不能让游戏卡成幻灯片16 万个神经元的模拟每步需要遍历 2500 万条连接进行电流传播。如果在主线程上执行游戏帧率会从 60 FPS 直接掉到个位数。解决方案是把整个神经模拟放进一个Web Worker主线程60 FPS Web Worker50 Hz ┌──────────────┐ ┌──────────────────┐ │ 游戏物理更新 │ │ 连接组加载 │ │ 游戏画面渲染 │ ─STEP→ │ LIF 神经模拟 │ │ 神经活动可视化│ │ 感觉刺激注入 │ │ HUD 状态更新 │ ←RESULT │ 运动神经元读取 │ └──────────────┘ │ 读出层推理 │ └──────────────────┘主线程每 20ms 发送一次STEP消息携带当前游戏状态Worker 完成一次神经模拟后返回BRAIN_RESULT包含决策和神经活动数据。两个时钟完全独立互不阻塞。如果浏览器支持SharedArrayBuffer需要 COOP/COEP 响应头神经活动数组会通过共享内存直接暴露给主线程避免每步都拷贝 166,700 字节的数据。不支持时自动降级为Transferable模式——性能略有损失但功能完全不受影响。创新点三三种模式一个核心约束这个项目最精妙的设计在于它的核心约束连接组永远冻结只有读出层可以学习。这不是技术限制而是设计哲学。我们想回答的问题是“一个真实的生物大脑在只允许调整输出接口的情况下能不能适应一个全新的任务环境”围绕这个约束项目提供了三种实验模式模式一PURE BRAIN纯脑模式最原始的模式。不训练任何东西直接从 DNp01一个真实的果蝇下行神经元的活动水平解码拍翅决策DNp01 spike count in 100ms 2 → FLAP cooldown 120ms防止连续拍翅飞出天际DNp01 在果蝇大脑中参与起飞和逃避行为。在纯脑模式下我们观察的是一个未经任何训练的真实生物神经网络如何对人工感觉刺激做出反应。结果果蝇会动但飞得乱七八糟。它偶尔会拍翅膀有时能躲过一根管道但很快就撞墙。这完全符合预期——一个从真实果蝇大脑扫描出来的连接组本来就没有玩 Flappy Bird的经验。模式二ONLINE TRAIN在线训练模式这是默认模式也是最有趣的模式。连接组依然冻结但我们在下行神经元活动和最终决策之间加了一个逻辑回归读出层Logistic ReadoutDN 活动向量 → 标准化 → 逻辑回归 → FLAP 概率 → 阈值比较 → FLAP/WAIT这个读出层在每次飞行中实时更新一个教师策略根据游戏状态决定应该拍翅吗收集下行神经元的活动特征12 组 DN 群体的放电率用梯度下降更新逻辑回归权重w - lr × (pred - label) × x 正则化学习率 0.018带 L2 正则化防止过拟合关键细节安全边界永远不可覆盖。无论读出层怎么学以下规则始终生效果蝇位于目标上方 → 禁止拍翅果蝇正在快速上升 → 禁止二次拍翅这些安全约束确保了即使读出层还没学好果蝇也不会一上来就冲出顶部。大约 1000 个样本约 2-3 轮飞行后读出层就会收敛到一个合理的决策阈值果蝇的飞行能力显著提升。模式三FAST TRAIN快速训练模式点击⚡ FAST TRAIN后Worker 会在后台快速模拟 1200 帧游戏生成训练样本然后进行完整的逻辑回归训练120 个 epoch带验证集早停。训练完成后切换到FAST MODEL模式权重冻结直接使用训练好的模型推理。原来的在线学习进度会被保存切回ONLINE TRAIN时可以恢复。两套模型完全独立不会互相覆盖。创新点四16 万个神经元的实时可视化如果说神经模拟是这个项目的大脑那 WebGL 可视化就是它的脸面。左栏的神经星空效果不是预先录制的动画——它是 166,700 个神经元的实时活动映射。Fibonacci 螺旋映射怎么把 16 万个神经元排列到一个圆形画布上项目使用了一种Fibonacci 螺旋也叫黄金角分布for(leti0;i166700;i){constthetai*2.3999632297;// 黄金角弧度constrMath.sqrt((i0.5)/166700)*0.92;xMath.cos(theta)*r*0.82;yMath.sin(theta)*r;}这种排列方式让每个神经元均匀分布在圆盘上没有聚簇也没有空隙视觉上非常美观。WebGL 点精灵渲染每个神经元是一个 WebGL 点精灵Point Sprite大小和亮度由活动水平决定// 顶点着色器 gl_PointSize 1.2 activity * 3.0; // 片元着色器 float d distance(gl_PointCoord, vec2(0.5)); if (d 0.5) discard; // 圆形裁剪 color vec4(0.25 v*0.6, 0.65 v*0.35, 0.54 v*0.35, 0.17 v*0.83);静息神经元是暗淡的小绿点发放动作电位的神经元是明亮的大光点。整个画面看起来像一片呼吸着的星空——当水管逼近时大片神经元同时亮起就像一波神经海啸席卷了整个大脑。渲染频率控制在 25 FPS每 40ms 更新一次远低于游戏的 60 FPS。这是有意为之——神经活动的变化速度本来就比游戏慢更高的渲染频率只会浪费 GPU 性能。创新点五从 fly.ai 到浏览器——自定义二进制格式MaleCNS v1.0 连接组的原始数据格式是为 Python 科学计算生态设计的。要在浏览器中高效加载和解析需要一套全新的二进制格式。项目设计了两种自定义格式FLYM神经元元数据┌────────┬────────┬───────────┬──────────┬──────────┬───────────┬──────────┐ │ Magic │Version │ N(neurons)│ JSON Len │ JSON │ typeIdx │ classIdx │ │ FLYM │ u32 │ u32 │ u32 │ (types, │ u16[N] │ u8[N] │ │ 4B │ 4B │ 4B │ 4B │ params) │ │ side │ └────────┘────────┴───────────┴──────────┴──────────┴───────────┴──────────┘JSON 部分包含types所有神经元类型名称如 “LC4”, “DNp01”, “DNg111”superclasses superclass 分类paramsLIF 模拟参数dt, tau, gain, tonic, noise_hz, noise_amp后面的二进制数组为每个神经元存储类型索引u16、类别索引u8、左右侧别u8。FLYW稀疏连接权重┌────────┬────────┬──────┬────────┬──────────────┬──────────────┬──────────┐ │ Magic │Version │ N │ NNZ │ ln_min │ colPtr │ rowIdx │ │ FLYW │ u32 │ u32 │ u32 │ f32 │ varint[N] │ varint │ │ 4B │ 4B │ 4B │ 4B │ 4B │ │ [NNZ] │ ├────────┬────────┴──────┴────────┴──────────────┴──────────────┴──────────┤ │ LUT │ weights (u8[NNZ]) │ │ f32[256]│ │ └────────┘────────────────────────────────────────────────────────────────┘关键设计决策Varint 编码列指针和行索引使用可变长度整数编码大幅减少小数字的存储空间Delta 编码同一列内的行索引存储差值而非绝对值进一步压缩8-bit 权重量化256 项查找表将每个权重从 32-bit 浮点压缩到 8-bit压缩比 4:1指数量化查找表使用exp(ln_min * (1 - q/127))映射对小数值的精度更高最终57.6 MB 的权重文件在浏览器中只需几秒钟就能加载完毕配合 Cache Storage第二次打开几乎是瞬间。创新点六三时钟异步架构这个项目最容易被忽视、但技术上最精妙的设计是它的三时钟异步架构。游戏、大脑和渲染各自运行在不同的时钟频率上游戏时钟60 FPS16.67ms/帧 大脑时钟50 Hz20ms/步 渲染时钟25 FPS40ms/帧它们之间的关系不是简单的 1:1:1而是一个累积器模式// 主循环while(brainClock0.02){// 每 20ms 执行一次大脑步进brainClock-0.02;brain.step(game.capture(),mode,elapsed);}// 渲染节流if(now-renderClock40){// 每 40ms 渲染一次大脑可视化brainRenderer.render(brain.activity);renderClocknow;}这意味着一个大脑步进周期内游戏可能已经更新了 1-2 帧大脑可视化每两帧才更新一次但肉眼完全看不出差异三个时钟完全独立任何一个卡顿都不会拖垮其他两个SLOW BRAIN 模式时间放大镜当用户点击SLOW BRAIN按钮时项目并不是降低了大脑的模拟频率——它只是把游戏时钟的缩放因子设为 0.1constscalethis.slow?0.1:1;constdtMath.min(0.033,(now-this.last)/1000)*scale;游戏世界变慢了 10 倍但大脑依然以 50Hz 运行。这就创造了一个时间放大镜效果——用户可以清楚地观察到水管接近 → LC4/LPLC2 亮起视觉输入检测信号在连接组中传播 → 中间神经元活动扩散DNp01 激活 → 下行神经元发出运动指令决策变为 FLAP → 果蝇拍翅在正常速度下整个过程不到 100 毫秒肉眼根本来不及分辨。SLOW BRAIN 模式把这个过程拉长到 1 秒让神经信号的传播路径清晰可见。实验记录系统科学从可复现开始每个严肃的科学实验都需要可复现性。项目通过种子随机数实现了完整的实验可复现// 水管生成、神经噪声、训练采样——全部使用同一个种子rng(Math.imul(rng,1664525)1013904223)0;在 URL 中添加?seed12345参数就能精确复现某次实验的全部条件相同的水管位置序列、相同的神经噪声序列、相同的训练样本顺序。实验历史自动保存在浏览器的localStorage中记录每次飞行的Fly ID递增编号运行模式得分通过的管道数存活时间总 spike 数页面右侧的BEST FLIES排行榜展示本浏览器中成绩最好的 5 只果蝇。死亡也是科学的一部分果蝇在 Flappy Bird 中有四种死法每种都对应一个有趣的死因分析碰撞位置死因描述神经学解读撞上水管上沿“THE FLY PANICKED.”视觉刺激过强DNp01 过度激活撞上水管下沿“THE FLY DID NOT FLAP.”决策延迟该拍翅时没拍飞出顶部“THE FLY FLAPPED TOO EARLY.”连续拍翅冷却机制失效撞上地面“THE FLY DID NOT FLAP.”完全没反应DN 活动不足这些死因当然是娱乐性质的——但它们确实反映了神经解码器的不同失败模式。技术细节Cache Storage 让二次加载秒开166,700 个神经元的数据总量接近 60 MB。如果每次打开页面都要从服务器下载用户体验会很差。项目使用浏览器的Cache Storage API实现智能缓存constCACHEfly-connectome-v1;constcacheawaitcaches.open(CACHE);consthitawaitcache.match(url);if(hit)returnhit;// 缓存命中直接使用constresponseawaitfetch(url);awaitcache.put(url,response.clone());// 缓存副本第一次加载时所有 .bin 文件从 Vite 开发服务器下载并缓存。第二次打开时直接从 Cache Storage 读取加载页面会显示 “WAKING UP CACHED BRAIN…”几乎瞬间完成。训练模型的安全边界一个非常巧妙的设计是安全边界不可训练functiontrainedFlapRequest(state,learned,threshold){constbelowTargetstate.birdYstate.gapCenterY8-adaptiveMargin;constnotClimbingFaststate.birdVelocityY-70;returnlearnedthresholdbelowTargetnotClimbingFast;}无论逻辑回归读出层学到什么以下规则永远生效果蝇已经在目标上方 → 不拍翅防止飞出顶部果蝇正在快速上升 → 不二次拍翅防止惯性叠加失控这意味着训练只能在安全走廊内微调拍翅时机不可能学出危险行为。这是一个非常实用的工程约束——它保证了即使训练还没收敛果蝇也不会做出荒谬的动作。模型导出与共享训练好的读出模型可以导出为 JSON 文件{format:fly-brain-readout-v3,exportedAt:2024-01-15T10:30:00Z,model:{features:[TARGET_DN L,TARGET_DN R,...],weights:[0.823,-0.912,...],bias:-0.156,threshold:0.38,trainingSamples:2847,trainingLoss:0.412}}其他人可以导入这个模型在自己的浏览器中加载——跳过训练过程直接使用已经学会飞行的模型。这创造了一种有趣的模型共享生态你可以比较不同训练条件下产生的模型看看哪些特征权重最高、哪些 DN 群体对决策贡献最大。效果展示下面是一系列从实际运行中录制的 GIF 动图展示果蝇大脑玩 Flappy Bird 的完整过程。 大脑加载过程首次打开页面时浏览器需要从本地服务器加载约 60MB 的连接组数据。加载过程分为多个阶段神经元元数据 → 稀疏权重解压 → 神经状态构建 → 视觉/下行神经元初始化。完成后显示 “166,700 NEURONS ONLINE” 和 “WAKE UP FLY” 按钮。 游戏开始果蝇起飞点击 “WAKE UP FLY” 后果蝇开始自主飞行。注意观察右侧神经数据面板——LC4 和 LPLC2 的强度随着水管接近而逐渐升高这是视觉 looming 系统在工作。✨ 神经活动全景左栏的 WebGL 神经活动地图是本项目最震撼的视觉效果。166,700 个神经元以 Fibonacci 螺旋排列每个点的大小和亮度对应其活动水平。当感觉刺激注入时可以看到活动波前从一侧传播到另一侧——就像真实的脑成像一样。 成功穿越管道当果蝇成功穿过一组管道时SCORE 计数器加 1。在 ONLINE TRAIN 模式下每一次成功的飞行都在为读出层提供训练样本——果蝇越飞越好。 死亡与重生果蝇死亡后画面覆盖实验终止信息得分、存活时间、总 spike 数、死因分析。点击 “REVIVE FLY” 或等待 AUTO REVIVE 自动开始下一次实验。每次重生 Fly ID 递增种子也随之变化。 SLOW BRAIN 模式开启 SLOW BRAIN 后游戏速度降到 0.1 倍但大脑仍以 50Hz 运行。这让你可以清楚地看到神经信号从视觉输入到运动输出的完整传播过程。左上角的序列指示器会显示当前阶段“VISUAL INPUT DETECTED → SIGNAL PROPAGATING…” 或 “DESCENDING NEURON ACTIVE → MOTOR COMMAND”。 PURE BRAIN 模式切换到 PURE BRAIN 模式后不再使用训练好的读出层而是直接从 DNp01 的 spike 计数解码决策。果蝇的动作变得更加随机和不可预测——因为这是未经训练的真实大脑活动。⚡ FAST TRAIN 训练过程点击 FAST TRAIN 后Worker 在后台快速生成 1200 帧训练样本。进度条显示训练进度和当前 loss 值。训练完成后自动切换到 FAST MODEL 模式果蝇的飞行能力显著提升。 AUTO REVIVE 连续实验开启 AUTO REVIVE 后果蝇死亡 2 秒后自动开始下一次实验。你可以把页面放在一边让果蝇持续飞行和训练。经过几轮训练后读出层收敛果蝇的平均得分稳步提升。 神经数据实时变化右栏的神经数据面板是理解果蝇想法的窗口。LC4/LPLC2 反映视觉威胁强度LC10a-L/R 反映目标方向DNp01 反映运动意图。DECISION 指示器在 FLAP 和 WAIT 之间切换FLAP PROBABILITY 显示读出层的置信度。项目基于 fly.ai 的 MaleCNS v1.0 果蝇连接组数据。连接组数据采用 CC BY 4.0 许可。本项目的感觉编码和运动解码是人工设计的实验接口不代表真实果蝇能够理解 Flappy Bird。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。