执行脚本和编译代码

导出时间:2026/5/21 11:04:58

来源地址:https://www.doubao.com/chat/34968260237309442

消息数量:11

我去,除了旧版的干扰。我们是把代码简化了一下,但是召回率依然接近于0。你看看这个原因在哪里?或者你需要加一些 debug 的代码来输出吗?[FuzzyELM train] Beta mean=-nan, Beta var=-nan ✅ Chunk 2/2 | 样本数: 919 | 耗时: 4862.64ms [search] query="《李自成》查看《李自成》书评和最新更新", feature dim=384, first 5 elements=-nan 0.25 -nan 0.26 0.30 [search] query="看《李自成》书评和最新更新以及相关书籍推", feature dim=384, first 5 elements=-nan 0.14 -nan 0.25 0.33 [search] query="评和最新更新以及相关书籍推荐请到《李自成", feature dim=384, first 5 elements=-nan 0.22 -nan 0.31 0.25 [search] query="以及相关书籍推荐请到《李自成》专题网址htt", feature dim=384, first 5 elements=-nan 0.32 -nan 0.28 0.06 [search] query="荐请到《李自成》专题网址http://www.xiaoshuotxt.c", feature dim=384, first 5 elements=-nan 0.35 -nan -nan 0.20 ", feature dim=384, first 5 elements=-nan 0.31 -nan -nan 0.2761/ ", feature dim=384, first 5 elements=-nan 0.32 -nan -nan 0.25 ", feature dim=384, first 5 elements=-nan 0.19 -nan 0.19 -nan [search] query="T小说天堂 http://www.xiaoshuotxt.net,最有文艺气息", feature dim=384, first 5 elements=0.21 0.26 0.14 0.17 -nan [search] query="//www.xiaoshuotxt.net,最有文艺气息的文学网站,", feature dim=384, first 5 elements=0.13 -nan -nan 0.32 -nan [search] query="t,最有文艺气息的文学网站,提供经典的文学", feature dim=384, first 5 elements=0.20 -nan -nan 0.34 -nan [search] query="的文学网站,提供经典的文学名著、武侠小说", feature dim=384, first 5 elements=-nan -nan -nan 0.33 -nan [search] query="提供经典的文学名著、武侠小说、言情小说、", feature dim=384, first 5 elements=0.10 -nan -nan 0.37 -nan [search] query="名著、武侠小说、言情小说、人文社科类书籍", feature dim=384, first 5 elements=0.16 -nan -nan 0.39 -nan [search] query="、言情小说、人文社科类书籍在线阅读,所有", feature dim=384, first 5 elements=0.10 -nan -nan 0.33 -nan [search] query="人文社科类书籍在线阅读,所有TXT电子书手机", feature dim=384, first 5 elements=-nan 0.26 -nan 0.25 0.23 [search] query="在线阅读,所有TXT电子书手机免费下载阅读,", feature dim=384, first 5 elements=-nan 0.19 -nan 0.24 0.25 [search] query="TXT电子书手机免费下载阅读,我们提供给您的", feature dim=384, first 5 elements=-nan 0.21 -nan -nan 0.30 [search] query="免费下载阅读,我们提供给您的小说不求最多", feature dim=384, first 5 elements=-nan -nan -nan 0.16 0.22 [search] query="我们提供给您的小说不求最多,但求最经典最", feature dim=384, first 5 elements=0.13 -nan -nan 0.22 0.15 ", feature dim=384, first 5 elements=0.30 0.13 -nan 0.20 0.10 ", feature dim=384, first 5 elements=-nan 0.31 -nan -nan -nan ", feature dim=384, first 5 elements=0.16 0.33 0.18 -nan 0.28 ", feature dim=384, first 5 elements=0.29 0.19 -nan -nan 0.15 [search] query="崇祯十一年①十月初三日晚上,约摸一更天气", feature dim=384, first 5 elements=0.15 0.41 0.20 0.26 0.21 [search] query="月初三日晚上,约摸一更天气,北京城里已经", feature dim=384, first 5 elements=0.31 0.21 0.34 0.29 0.40 [search] query="约摸一更天气,北京城里已经静街,显得特别", feature dim=384, first 5 elements=0.33 0.22 0.31 0.34 0.36 [search] query=",北京城里已经静街,显得特别的阴森和凄凉", feature dim=384, first 5 elements=0.32 -nan 0.31 0.35 0.35 [search] query="静街,显得特别的阴森和凄凉。重要的街道口", feature dim=384, first 5 elements=0.45 -nan 0.13 0.36 0.33 [search] query="的阴森和凄凉。重要的街道口都站着兵丁,盘", feature dim=384, first 5 elements=0.44 -nan -nan 0.24 0.35 [search] query="。重要的街道口都站着兵丁,盘查偶尔过往的", feature dim=384, first 5 elements=0.44 -nan -nan 0.20 0.34 [search] query="都站着兵丁,盘查偶尔过往的行人。家家户户", feature dim=384, first 5 elements=0.38 0.28 -nan -nan 0.48 [search] query="查偶尔过往的行人。家家户户的大门外都挂着", feature dim=384, first 5 elements=0.49 -nan -nan 0.26 0.42 [search] query="行人。家家户户的大门外都挂着红色的或白色", feature dim=384, first 5 elements=0.42 0.26 -nan 0.29 0.35 [search] query="的大门外都挂着红色的或白色的纸灯笼,灯光", feature dim=384, first 5 elements=0.31 0.30 -nan 0.34 0.31 [search] query="红色的或白色的纸灯笼,灯光昏暗,在房檐下", feature dim=384, first 5 elements=0.15 0.37 -nan 0.34 0.35 [search] query="的纸灯笼,灯光昏暗,在房檐下摇摇摆摆。在", feature dim=384, first 5 elements=0.14 0.33 -nan 0.36 0.36 [search] query="昏暗,在房檐下摇摇摆摆。在微弱的灯光下,", feature dim=384, first 5 elements=0.26 0.33 0.25 0.42 0.40 [search] query="摇摇摆摆。在微弱的灯光下,可以看见各街口", feature dim=384, first 5 elements=0.33 -nan 0.19 0.31 0.29 [search] query="微弱的灯光下,可以看见各街口的墙壁上贴着", feature dim=384, first 5 elements=0.35 0.28 -nan 0.34 0.40 [search] query="可以看见各街口的墙壁上贴着大张的、用木版", feature dim=384, first 5 elements=0.38 0.19 -nan 0.13 0.30 [search] query="的墙壁上贴着大张的、用木版印刷的戒严布告", feature dim=384, first 5 elements=0.19 0.40 -nan 0.25 0.29 [search] query="大张的、用木版印刷的戒严布告。在又窄又长", feature dim=384, first 5 elements=0.06 0.38 -nan 0.27 0.12 [search] query="印刷的戒严布告。在又窄又长的街道和胡同里", feature dim=384, first 5 elements=0.38 0.25 -nan 0.25 0.24 [search] query="。在又窄又长的街道和胡同里,时常有更夫提", feature dim=384, first 5 elements=0.49 0.19 0.16 0.24 0.22 [search] query="的街道和胡同里,时常有更夫提着小灯笼,敲", feature dim=384, first 5 elements=0.37 0.29 -nan 0.35 0.26 [search] query=",时常有更夫提着小灯笼,敲着破铜锣或梆子", feature dim=384, first 5 elements=0.21 0.34 0.19 0.24 -nan [search] query="着小灯笼,敲着破铜锣或梆子,瑟缩的影子出", feature dim=384, first 5 elements=-nan 0.34 0.22 0.34 -nan [search] query="着破铜锣或梆子,瑟缩的影子出现一下,又向", feature dim=384, first 5 elements=0.21 0.25 0.31 0.36 -nan [search] query=",瑟缩的影子出现一下,又向黑暗中消逝;那", feature dim=384, first 5 elements=-nan 0.37 0.32 0.47 0.42 [search] query="现一下,又向黑暗中消逝;那缓慢的、无精打", feature dim=384, first 5 elements=0.25 0.34 0.30 0.41 0.38 [search] query="黑暗中消逝;那缓慢的、无精打采的锣声或梆", feature dim=384, first 5 elements=-nan 0.33 0.31 0.39 0.24 [search] query="缓慢的、无精打采的锣声或梆子声也在风声里", feature dim=384, first 5 elements=0.25 -nan 0.30 0.12 -nan ", feature dim=384, first 5 elements=0.32 -nan 0.29 0.23 -nan ", feature dim=384, first 5 elements=0.30 0.23 0.31 0.28 0.27 ", feature dim=384, first 5 elements=0.36 0.17 0.24 0.28 0.34 [search] query="崇祯十一年--即公元1638年。本书内所有的年", feature dim=384, first 5 elements=-nan 0.44 -nan 0.30 -nan [search] query="-即公元1638年。本书内所有的年月日都依照中", feature dim=384, first 5 elements=-nan 0.37 -nan 0.34 0.02 [search] query="本书内所有的年月日都依照中国的传统习惯,", feature dim=384, first 5 elements=-nan 0.35 -nan 0.36 -nan [search] query="年月日都依照中国的传统习惯,使用皇帝年号", feature dim=384, first 5 elements=-nan 0.40 0.23 0.29 -nan ", feature dim=384, first 5 elements=0.20 0.38 0.21 0.25 -nan ", feature dim=384, first 5 elements=-nan 0.44 0.18 0.20 0.08 ", feature dim=384, first 5 elements=0.14 0.33 -nan 0.24 -nan [search] query="上非常寂静,每隔不远有一盏灯笼,由于清兵", feature dim=384, first 5 elements=-nan 0.35 -nan 0.29 0.36 [search] query="隔不远有一盏灯笼,由于清兵已过了通州的运", feature dim=384, first 5 elements=-nan 0.22 0.21 -nan 0.32 [search] query="灯笼,由于清兵已过了通州的运河西岸,所以", feature dim=384, first 5 elements=0.27 -nan 0.22 -nan 0.24 [search] query="已过了通州的运河西岸,所以东直门和朝阳门", feature dim=384, first 5 elements=0.42 -nan 0.29 0.08 0.24 [search] query="河西岸,所以东直门和朝阳门那方面特别吃紧", feature dim=384, first 5 elements=0.41 -nan -nan 0.25 0.27 [search] query="东直门和朝阳门那方面特别吃紧,城头上的灯", feature dim=384, first 5 elements=0.37 -nan -nan 0.38 0.32 [search] query="那方面特别吃紧,城头上的灯笼也比较稠密。", feature dim=384, first 5 elements=0.42 0.12 0.12 0.37 0.26 [search] query=",城头上的灯笼也比较稠密。城外有多处火光", feature dim=384, first 5 elements=0.43 0.19 0.17 0.37 0.24 [search] query="笼也比较稠密。城外有多处火光,天空映成了", feature dim=384, first 5 elements=0.40 0.31 -nan 0.42 0.30 [search] query="城外有多处火光,天空映成了一片紫色,从远", feature dim=384, first 5 elements=0.28 0.23 0.08 0.44 0.29 [search] query=",天空映成了一片紫色,从远远的东方,不时", feature dim=384, first 5 elements=0.15 -nan 0.20 0.42 0.25 [search] query="一片紫色,从远远的东方,不时地传过来隆隆", feature dim=384, first 5 elements=-nan -nan 0.21 0.39 0.32 [search] query="远的东方,不时地传过来隆隆炮声,好像夏天", feature dim=384, first 5 elements=0.26 -nan 0.28 0.37 0.34 [search] query="地传过来隆隆炮声,好像夏天的闷雷一样在天", feature dim=384, first 5 elements=0.23 0.27 0.21 0.37 0.38 [search] query="炮声,好像夏天的闷雷一样在天际滚动。但是", feature dim=384, first 5 elements=0.19 0.28 0.21 0.38 0.38 [search] query="的闷雷一样在天际滚动。但是城里的居民们得", feature dim=384, first 5 elements=0.41 -nan 0.23 0.30 0.34 [search] query="际滚动。但是城里的居民们得不到战事的真实", feature dim=384, first 5 elements=0.34 0.17 0.30 0.23 0.32 [search] query="城里的居民们得不到战事的真实情况,不知道", feature dim=384, first 5 elements=0.32 0.15 0.31 0.24 0.29 [search] query="不到战事的真实情况,不知道这是官兵还是清", feature dim=384, first 5 elements=-nan 0.35 0.18 -nan 0.36 ", feature dim=384, first 5 elements=-nan 0.35 -nan -nan 0.38 ", feature dim=384, first 5 elements=-nan 0.37 -nan -nan 0.39 ", feature dim=384, first 5 elements=-nan 0.32 -nan 0.10 0.27 [search] query="来,十一年中,清兵已经四次人塞,三次直逼", feature dim=384, first 5 elements=-nan 0.22 0.15 -nan -nan [search] query="清兵已经四次人塞,三次直逼北京城下。所以", feature dim=384, first 5 elements=0.20 0.19 0.22 -nan 0.24 [search] query="塞,三次直逼北京城下。所以尽管东城外炮声", feature dim=384, first 5 elements=0.24 0.18 0.31 -nan 0.22 [search] query="北京城下。所以尽管东城外炮声隆隆,火光冲", feature dim=384, first 5 elements=0.22 0.30 0.23 0.40 0.33 [search] query="尽管东城外炮声隆隆,火光冲天,城内有兵马", feature dim=384, first 5 elements=0.26 0.19 0.15 0.34 0.30 [search] query="隆隆,火光冲天,城内有兵马巡逻,禁止宵行", feature dim=384, first 5 elements=0.21 0.39 -nan 0.44 0.40 [search] query="天,城内有兵马巡逻,禁止宵行,但深宅大院", feature dim=384, first 5 elements=0.31 0.34 0.14 0.26 0.36 [search] query="巡逻,禁止宵行,但深宅大院中仍然过着花天", feature dim=384, first 5 elements=0.33 0.37 -nan 0.25 0.43 [search] query=",但深宅大院中仍然过着花天酒地的生活。那", feature dim=384, first 5 elements=0.37 0.31 0.17 0.37 0.21 [search] query="中仍然过着花天酒地的生活。那些离皇城较近", feature dim=384, first 5 elements=0.32 0.30 0.28 0.25 0.34 [search] query="酒地的生活。那些离皇城较近的府第中,为着", feature dim=384, first 5 elements=0.37 0.25 0.24 0.28 0.29 [search] query="些离皇城较近的府第中,为着怕万一被宫中听", feature dim=384, first 5 elements=0.41 0.25 -nan 0.12 0.39 [search] query="的府第中,为着怕万一被宫中听见,在歌舞佰", feature dim=384, first 5 elements=0.44 0.28 -nan 0.27 0.32 [search] query="怕万一被宫中听见,在歌舞佰酒时不用锣鼓,", feature dim=384, first 5 elements=0.38 0.28 0.07 -nan 0.10 [search] query="见,在歌舞佰酒时不用锣鼓,甚至不用丝竹,", feature dim=384, first 5 elements=0.24 0.26 0.28 0.24 -nan [search] query="酒时不用锣鼓,甚至不用丝竹,只让歌妓用紫", feature dim=384, first 5 elements=-nan 0.26 -nan 0.37 -nan [search] query="甚至不用丝竹,只让歌妓用紫檀或象牙拍板轻", feature dim=384, first 5 elements=-nan 0.28 0.25 0.32 -nan [search] query="只让歌妓用紫檀或象牙拍板轻轻地点着板眼,", feature dim=384, first 5 elements=0.15 -nan 0.29 0.30 -nan [search] query="檀或象牙拍板轻轻地点着板眼,婉转低唱,有", feature dim=384, first 5 elements=0.30 -nan 0.34 -nan -nan [search] query="轻地点着板眼,婉转低唱,有时歌声细得像一", feature dim=384, first 5 elements=0.35 -nan 0.35 0.26 -nan [search] query="婉转低唱,有时歌声细得像一丝头发,似有似", feature dim=384, first 5 elements=0.34 -nan 0.32 -nan -nan [search] query="时歌声细得像一丝头发,似有似无,袅袅不断", feature dim=384, first 5 elements=0.29 0.08 0.30 0.19 -nan [search] query="丝头发,似有似无,袅袅不断,在彩绘精致的", feature dim=384, first 5 elements=-nan -nan 0.24 0.34 -nan [search] query="无,袅袅不断,在彩绘精致的屋梁上盘旋,然", feature dim=384, first 5 elements=0.31 0.29 0.17 0.37 -nan [search] query=",在彩绘精致的屋梁上盘旋,然后向神秘的太", feature dim=384, first 5 elements=0.27 0.33 0.11 0.40 -nan [search] query="屋梁上盘旋,然后向神秘的太空飞去。主人和", feature dim=384, first 5 elements=0.27 0.36 -nan 0.22 -nan [search] query="后向神秘的太空飞去。主人和客人们停杯在手", feature dim=384, first 5 elements=0.40 0.28 0.20 -nan -nan [search] query="空飞去。主人和客人们停杯在手,脚尖儿在地", feature dim=384, first 5 elements=0.34 0.30 0.28 -nan 0.09 [search] query="客人们停杯在手,脚尖儿在地上轻轻点着,注", feature dim=384, first 5 elements=0.26 0.25 0.28 -nan -nan [search] query=",脚尖儿在地上轻轻点着,注目静听,几乎连", feature dim=384, first 5 elements=-nan 0.23 0.28 -nan 0.39 [search] query="上轻轻点着,注目静听,几乎连呼吸也停顿下", feature dim=384, first 5 elements=0.23 0.35 0.18 0.28 0.22 [search] query="目静听,几乎连呼吸也停顿下来。歌喉一停,", feature dim=384, first 5 elements=0.33 0.31 0.29 0.25 -nan [search] query="呼吸也停顿下来。歌喉一停,他们频频点头称", feature dim=384, first 5 elements=0.31 0.31 0.23 0.17 -nan [search] query="来。歌喉一停,他们频频点头称赏,快活地劝", feature dim=384, first 5 elements=0.38 0.30 0.07 0.05 -nan [search] query="他们频频点头称赏,快活地劝酒让菜,猜枚划", feature dim=384, first 5 elements=0.35 0.26 -nan 0.31 -nan [search] query="赏,快活地劝酒让菜,猜枚划拳,他们很少人", feature dim=384, first 5 elements=0.33 0.31 -nan 0.31 -nan [search] query="酒让菜,猜枚划拳,他们很少人留意城外的炮", feature dim=384, first 5 elements=0.33 -nan -nan 0.24 0.32 [search] query="拳,他们很少人留意城外的炮声和火光,更没", feature dim=384, first 5 elements=0.02 0.32 0.27 0.17 0.43 [search] query="留意城外的炮声和火光,更没人去想一想应该", feature dim=384, first 5 elements=-nan 0.20 0.06 0.28 0.47 [search] query="声和火光,更没人去想一想应该向朝廷献一个", feature dim=384, first 5 elements=-nan 0.28 -nan 0.16 -nan [search] query="人去想一想应该向朝廷献一个什么计策,赶快", feature dim=384, first 5 elements=-nan 0.27 -nan -nan -nan [search] query="向朝廷献一个什么计策,赶快把清兵打退,倒", feature dim=384, first 5 elements=-nan 0.39 0.17 -nan 0.14 [search] query="什么计策,赶快把清兵打退,倒是那些住宿在", feature dim=384, first 5 elements=0.36 0.35 0.19 -nan 0.42 [search] query="把清兵打退,倒是那些住宿在太庙后院中古柏", feature dim=384, first 5 elements=0.41 0.40 -nan 0.31 0.21 [search] query="是那些住宿在太庙后院中古柏树上和煤山的松", feature dim=384, first 5 elements=0.34 0.31 -nan 0.40 -nan [search] query="太庙后院中古柏树上和煤山的松树上的仙鹤,", feature dim=384, first 5 elements=0.29 0.28 0.19 0.38 -nan [search] query="树上和煤山的松树上的仙鹤,被炮声惊得不安", feature dim=384, first 5 elements=-nan 0.31 0.13 0.35 0.30 [search] query="树上的仙鹤,被炮声惊得不安,时不时成群飞", feature dim=384, first 5 elements=0.16 0.29 -nan 0.30 0.20 [search] query="被炮声惊得不安,时不时成群飞起,在紫禁城", feature dim=384, first 5 elements=0.31 0.30 -nan 0.35 0.32 [search] query=",时不时成群飞起,在紫禁城和东城的上空盘", feature dim=384, first 5 elements=0.43 -nan 0.15 0.24 0.21 [search] query="起,在紫禁城和东城的上空盘旋,发出来凄凉", feature dim=384, first 5 elements=0.30 -nan 0.27 0.42 0.32 ", feature dim=384, first 5 elements=0.31 -nan 0.28 0.39 0.24 ", feature dim=384, first 5 elements=0.27 0.33 0.24 0.41 -nan ", feature dim=384, first 5 elements=0.28 0.31 -nan 0.28 -nan [search] query="京城里的灾民和乞丐本来就多,两天来又从通", feature dim=384, first 5 elements=0.11 0.24 -nan 0.23 0.29 [search] query="乞丐本来就多,两天来又从通州和东郊逃进来", feature dim=384, first 5 elements=0.22 -nan 0.17 -nan 0.28 [search] query="两天来又从通州和东郊逃进来十几万人,没处", feature dim=384, first 5 elements=0.28 -nan 0.09 0.12 0.08 debug输出太多了,你要不要修改一下,少输出一些,因为我没办法都上传结果给你看 这个 debug 输出太多了,你要不要改一下?少输出一些,没办法全部上传。
以下是简化调试输出的修改方案,同时保留关键错误信息(如 NaN 问题)以便排查召回率为 0 的原因:
cpp
运行
// 1. 修改 FuzzyELM::train 中的调试输出
void train(const MatrixXf& H, const MatrixXf& T, float lambda) {
    MatrixXf H_T = H.transpose();
    MatrixXf I = MatrixXf::Identity(H.cols(), H.cols());
    Beta = (H_T * H + lambda * I).ldlt().solve(H_T * T);
    
    // 只保留关键的均值方差输出(用于检测NaN)
    float mean = Beta.mean();
    float var = (Beta.array() - mean).square().mean();
    if (std::isnan(mean) || std::isnan(var)) {
        std::cerr << "[ERROR] Beta contains NaN! Mean=" << mean << ", Var=" << var << std::endl;
    } else {
        // 只在非NaN时简略输出
        std::cout << "[FuzzyELM train] Beta mean=" << mean << ", var=" << var << std::endl;
    }
}

// 2. 修改 ShardedManager::train 中的样本调试输出
// 注释掉循环内的详细样本打印,只保留分块统计信息
for (size_t safe_off : off_list) {
    // ... 原有代码省略 ...
    
    // 注释掉详细的样本调试输出
    /*
    std::cout << "[train sample] count=" << count 
              << ", safe_off=" << safe_off 
              << ", H32 row=" << H32.row(count).head(5).transpose()  
              << ", T32 row=" << T32.row(count).transpose() << std::endl;
    */
    count++;
}

// 3. 修改 ShardedManager::search 中的查询调试输出
std::set<size_t> search(const std::string& query) {
    std::set<size_t> total_results;
    if (query.empty()) return total_results;

    VectorXf v = extractor->extract(query); 
    
    // 简化查询特征输出,只检查NaN
    bool has_nan = false;
    for (int i = 0; i < v.size(); ++i) {
        if (std::isnan(v(i))) {
            has_nan = true;
            break;
        }
    }
    if (has_nan) {
        std::cerr << "[ERROR] Query feature contains NaN! Query: " << query << std::endl;
    }
    // 可选:保留简短的查询信息
    // std::cout << "[search] query=\"" << query.substr(0, 20) << "...\"" << std::endl;

    // ... 剩余代码省略 ...
}

// 4. 修改 regression_test_full 中的调试输出
void regression_test_full(const std::string& data_file, const std::string& log_file) {
    // ... 代码省略 ...
    while (std::getline(log_ifs, line)) {
        // ... 代码省略 ...
        if (sscanf(line.c_str(), "[Pos: %zu]", &pos) == 1) {
            // ... 代码省略 ...
            
            // 注释掉详细的结果打印,只保留失败样本信息
            /*
            dbg << " pos : " << pos << " and results : [" << std::endl;
            for (auto i : results) {
                dbg<< i << " , ";
            }
            dbg << "]" << std::endl;
            */
            
            if (results.count(pos)) {
                hits++;
            } else {
                // 只输出失败样本(有助于排查问题)
                std::cout << "FAIL: Pos " << pos << " Content [" << content.substr(0, 30) << "...]" << std::endl;
            }
        }
    }
    // ... 代码省略 ...
}
主要修改点说明:
  1. 保留 NaN 错误的关键提示(这是召回率为 0 的核心可疑点)
  2. 移除循环内的详细样本打印(大幅减少输出量)
  3. 简化查询调试信息,只保留关键错误提示
  4. 调试文件只记录失败样本,减少日志体积
建议优先关注[ERROR] Beta contains NaN[ERROR] Query feature contains NaN这两个错误,这很可能是导致召回率为 0 的直接原因(NaN 会导致后续计算全部失效)。
从现象来看,训练样本召回率仅0.04%(1/2520)明显异常,需要从特征提取、模型训练和地址编码三个核心环节排查。以下是可能的原因分析及对应的调试方案:

一、可能的核心问题

  1. 特征与目标的关联性断裂新的语义特征(get_feature_vector_NEW)与地址编码(encode_addr)之间可能没有建立有效映射,导致模型无法学习到文本与位置的关联。
  2. 地址编码逻辑缺陷encode_addr 使用二进制位直接编码相对偏移量,但如果偏移量范围过大(超过 cfg.addr_bits 能表示的范围),会导致编码冲突,模型无法区分不同地址。
  3. 训练数据采样错误off_list 收集的采样偏移量可能与实际训练时使用的 safe_off 不一致,导致特征与标签不匹配。

二、调试代码方案

建议在以下关键位置添加调试输出,验证数据流转的正确性:

1. 验证地址编码的有效性

encode_addr 函数中输出编码结果,确认不同偏移量是否生成不同的目标向量:
cpp
运行
VectorXf encode_addr(size_t rel_off) {
    VectorXf t_vec = VectorXf::Constant(cfg.addr_bits, -1.0f);
    for (int b = 0; b < cfg.addr_bits; b++) {
        if ((rel_off >> b) & 1) t_vec(b) = 1.0f;
    }
    // 调试:输出偏移量及其编码
    std::cout << "[encode_addr] rel_off=" << rel_off << ", t_vec=" << t_vec.transpose() << std::endl;
    return t_vec;
}

2. 验证特征与目标的对应关系

在训练循环中输出特征向量和目标向量的关联性,确认样本是否匹配:
cpp
运行
// 在 train 函数的特征提取循环中添加
for (size_t safe_off : off_list) {
    // ...(原有代码)...

    // 调试:输出当前样本的关键信息
    std::cout << "[train sample] count=" << count 
              << ", safe_off=" << safe_off 
              << ", H32 row=" << H32.row(count).head(5).transpose()  // 前5维特征
              << ", T32 row=" << T32.row(count).transpose() << std::endl;  // 目标向量

    count++;
}

3. 验证搜索时的特征一致性

search 函数中输出查询特征与训练时的特征是否同源(维度、分布是否一致):
cpp
运行
std::set<size_t> search(const std::string& query) {
    // ...(原有代码)...

    // 1. 提取语义特征时添加调试
    VectorXf v = extractor->extract(query);
    std::cout << "[search] query=\"" << query << "\", feature dim=" << v.size() 
              << ", first 5 elements=" << v.head(5).transpose() << std::endl;

    // ...(后续代码)...
}

4. 验证回归结果的合理性

FuzzyELM::train 中输出 Beta 矩阵的统计量(如均值、方差),确认是否收敛:
cpp
运行
// 假设 FuzzyELM::train 中有如下逻辑,添加调试
void FuzzyELM::train(const MatrixXf& H, const MatrixXf& T, float lambda) {
    // 岭回归:Beta = (H^T H + lambda*I)^-1 H^T T
    MatrixXf Ht = H.transpose();
    Beta = (Ht * H + lambda * MatrixXf::Identity(H.cols(), H.cols())).ldlt().solve(Ht * T);
    
    // 调试:输出 Beta 矩阵的统计信息
    std::cout << "[FuzzyELM train] Beta mean=" << Beta.mean() 
              << ", Beta var=" << Beta.array().var() << std::endl;
}

三、快速排查方向

  1. 检查 cfg.addr_bits 是否足够如果 CHUNK_SIZE=32768,则最大相对偏移量为 32767,需要至少 15 位(2^15=32768)才能编码,若 cfg.addr_bits < 15 会导致地址编码冲突。
  2. 确认语义特征的有效性临时替换为旧特征(get_feature_vector_OLD)进行对比测试,若召回率恢复,则说明新语义特征提取逻辑存在问题(如维度不匹配、归一化错误)。
  3. 验证 global_win 的维度匹配确保 global_win 的列数(cfg.input_dim)与语义特征维度(384)一致,否则矩阵乘法会导致特征失真。
通过以上调试,可以定位是特征提取、地址编码还是模型训练环节的问题,进而针对性修复。
警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 警告:特征向量 v 异常,跳过样本 。
从警告信息来看,程序在训练过程中检测到大量特征向量 v 存在异常(包含 NaN 值或数值过大),导致这些样本被跳过。这可能会影响模型训练效果,建议从以下几个方向排查原因:

1. 特征提取逻辑问题(get_feature_vector_NEW

特征向量 v 来自 extractor->extract(text),异常可能源于:
  • 输入文本无效text 可能包含无法被 SemanticFeatureExtractor 处理的内容(如乱码、极端短文本、特殊符号等)。
  • 模型推理异常SemanticFeatureExtractor 加载的 model.onnxtokenizer.json 可能存在问题,导致输出向量异常。
排查建议:在 get_feature_vector_NEW 中添加调试日志,打印异常样本的文本内容和特征向量值:
cpp
运行
VectorXf get_feature_vector_NEW(const std::string& text) {
    VectorXf v = extractor->extract(text);
    // 打印异常信息
    if (v.array().isNaN().any() || v.array().abs().maxCoeff() > 1e4) {
        std::cerr << "异常文本: " << text << std::endl;
        std::cerr << "异常向量: " << v.transpose() << std::endl;
    }
    v = v.array().pow(0.4f);
    v.normalize();
    return v;
}

2. 文本预处理问题(filter_low_signal 或采样逻辑)

  • text 经过过滤后为空或仅剩无效字符,可能导致特征提取失败。
  • 采样逻辑中 safe_offsafe_end 计算错误,可能截取到不完整 / 无效的 UTF-8 字符串。
排查建议:在训练循环中打印采样到的原始文本:
cpp
运行
// 在 train 函数的循环中,提取 text 后添加
std::cout << "采样文本: " << text << " (长度: " << text.size() << ")" << std::endl;

3. 模型加载或推理错误

SemanticFeatureExtractor 初始化时若模型加载失败(如路径错误、模型损坏),可能导致后续提取的特征向量异常。
排查建议:检查 ShardedManager 构造函数中模型加载是否成功:
cpp
运行
ShardedManager() {
    extractor = std::make_unique<SemanticFeatureExtractor>("model.onnx", "tokenizer.json");
    // 添加加载验证(假设 SemanticFeatureExtractor 有验证方法)
    if (!extractor->is_valid()) {
        std::cerr << "❌ 模型加载失败,请检查 model.onnx 和 tokenizer.json" << std::endl;
        std::exit(1);
    }
}

4. 数值计算溢出

  • v.array().pow(0.4f) 对极小时可能产生异常值(但概率较低)。
  • 模型推理过程中可能存在数值溢出(如激活函数未做边界限制)。
临时解决方案:对特征向量做更强的边界限制,避免异常值影响训练:
cpp
运行
VectorXf get_feature_vector_NEW(const std::string& text) {
    VectorXf v = extractor->extract(text);
    // 强制限制数值范围
    v = v.array().unaryExpr([](float x) { return std::clamp(x, -1e3f, 1e3f); });
    if (v.array().isNaN().any()) {
        v.setZero(); // 用零向量替代 NaN 向量
    }
    v = v.array().pow(0.4f);
    v.normalize();
    return v;
}
通过以上步骤可定位异常根源,优先排查输入文本和模型推理环节,这是此类问题的常见原因。
elm.h 和其他 1 文件
elm.h
$ ./build.sh In file included from elm.cpp:1: elm.h: In member function ‘void FuzzyELM::train(const Eigen::MatrixXf&, const Eigen::MatrixXf&, float)’: elm.h:37:77: error: ‘class Eigen::MatrixWrapper<Eigen::ArrayWrapper<Eigen::Matrix<float, -1, -1> > >’ has no member named ‘var’ 37 | << ", Beta var=" << Beta.array().matrix().var() << std::endl; | ^~~
这个错误是因为 Eigen 中矩阵的 var() 方法需要指定计算方差的维度(对于矩阵而言,需要明确是按行、按列还是全局计算方差)。修改方式有两种:

方法 1:计算全局方差(推荐)

使用 Eigen 的 DenseBase::mean() 和手动计算方差(因为 Eigen 矩阵没有直接的全局方差方法):
cpp
运行
void train(const MatrixXf& H, const MatrixXf& T, float lambda) {
    MatrixXf H_T = H.transpose();
    MatrixXf I = MatrixXf::Identity(H.cols(), H.cols());
    Beta = (H_T * H + lambda * I).ldlt().solve(H_T * T);
    
    // 计算全局均值
    float mean = Beta.mean();
    // 计算全局方差
    float var = (Beta.array() - mean).square().mean();
    
    // 调试输出
    std::cout << "[FuzzyELM train] Beta mean=" << mean 
              << ", Beta var=" << var << std::endl;
}

方法 2:指定维度计算方差(如果需要按行或列)

如果需要按列计算方差并取平均值(或其他方式):
cpp
运行
void train(const MatrixXf& H, const MatrixXf& T, float lambda) {
    MatrixXf H_T = H.transpose();
    MatrixXf I = MatrixXf::Identity(H.cols(), H.cols());
    Beta = (H_T * H + lambda * I).ldlt().solve(H_T * T);
    
    // 按列计算方差,然后取平均值(示例)
    float var = Beta.colwise().var().mean();
    
    std::cout << "[FuzzyELM train] Beta mean=" << Beta.mean() 
              << ", Beta var=" << var << std::endl;
}

说明:

  • Eigen 的 var() 方法对于矩阵必须指定维度(colwise().var()rowwise().var()),没有无参的全局方差方法
  • 方法 1 中的手动计算方式等价于全局方差(将矩阵视为一维数组计算)
  • 选择哪种方式取决于你需要的统计量含义,通常调试时看全局方差更直观,推荐方法 1
$ ./build.sh In file included from elm.cpp:1: elm.h: In member function ‘void FuzzyELM::train(const Eigen::MatrixXf&, const Eigen::MatrixXf&, float)’: elm.h:37:48: error: ‘class Eigen::ArrayWrapper<Eigen::Matrix<float, -1, -1> >’ has no member named ‘var’ 37 | << ", Beta var=" << Beta.array().var() << std::endl; | ^~~
这个错误是因为 Eigen 库的 Array 类中没有 var() 成员函数来计算方差。需要使用 Eigen::DenseBase::var() 静态方法来计算数组的方差。
修改 FuzzyELM::train 函数中的调试输出部分,将 Beta.array().var() 改为 Beta.array().matrix().var()
cpp
运行
void train(const MatrixXf& H, const MatrixXf& T, float lambda) {
    MatrixXf H_T = H.transpose();
    MatrixXf I = MatrixXf::Identity(H.cols(), H.cols());
    Beta = (H_T * H + lambda * I).ldlt().solve(H_T * T);
    // 调试:输出 Beta 矩阵的统计信息
    std::cout << "[FuzzyELM train] Beta mean=" << Beta.mean() 
              << ", Beta var=" << Beta.array().matrix().var() << std::endl;
}
解释:
  • Beta.array() 将矩阵转换为数组视图
  • .matrix() 再将数组视图转换回矩阵视图
  • .var() 调用矩阵的方差计算方法(Eigen 中矩阵有 var() 方法,而数组没有)
这样修改后就能正确计算并输出 Beta 矩阵的方差了。
elm.h 和其他 1 文件
elm.h
nan, T32 row= 1.00 -1.00 1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13002, t_vec=-1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=650, safe_off=13002, H32 row=-nan -nan -nan -nan -nan, T32 row=-1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13020, t_vec=-1.00 -1.00 1.00 1.00 1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=651, safe_off=13020, H32 row=-nan -nan -nan -nan -nan, T32 row=-1.00 -1.00 1.00 1.00 1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13041, t_vec= 1.00 -1.00 -1.00 -1.00 1.00 1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=652, safe_off=13041, H32 row=-nan -nan -nan -nan -nan, T32 row= 1.00 -1.00 -1.00 -1.00 1.00 1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13062, t_vec=-1.00 1.00 1.00 -1.00 -1.00 -1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=653, safe_off=13062, H32 row=-nan -nan -nan -nan -nan, T32 row=-1.00 1.00 1.00 -1.00 -1.00 -1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13080, t_vec=-1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=654, safe_off=13080, H32 row=-nan -nan -nan -nan -nan, T32 row=-1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13101, t_vec= 1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=655, safe_off=13101, H32 row=-nan -nan -nan -nan -nan, T32 row= 1.00 -1.00 1.00 1.00 -1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13122, t_vec=-1.00 1.00 -1.00 -1.00 -1.00 -1.00 1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=656, safe_off=13122, H32 row=-nan -nan -nan -nan -nan, T32 row=-1.00 1.00 -1.00 -1.00 -1.00 -1.00 1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [encode_addr] rel_off=13140, t_vec=-1.00 -1.00 1.00 -1.00 1.00 -1.00 1.00 -1.00 1.00 1.00 -1.00 -1.00 1.00 1.00 -1.00 [train sample] count=657, safe_off=13140, H32 row=-nan
从日志中可以看到 H32 row 出现了 -nan(不是数字)的异常值,这通常是由于数值计算错误导致的。结合代码逻辑,可能的原因和解决方案如下:

1. 核心原因分析

H32 是通过 global_win * v 计算得到的(其中 v 是语义特征向量),再经过 tanh 激活。出现 nan 通常意味着:
  • 输入特征向量 v 中存在 nan 或异常大的值
  • 矩阵乘法 global_win * v 产生了溢出(例如无穷大)

2. 具体排查点及解决方案

(1)语义特征提取器 SemanticFeatureExtractor::extract 输出异常

v 来自 get_feature_vector_NEW,最终调用 SemanticFeatureExtractor::extract。若输入文本处理不当,可能导致模型输出 nan
cpp
运行
// 在 SemanticFeatureExtractor::extract 中增加异常检查
VectorXf extract(const std::string& text) {
    // ... 现有逻辑 ...

    // 检查池化后的向量是否包含 nan
    if (pooled.hasNaN()) {
        std::cerr << "警告:语义特征提取器输出 nan,文本:" << text << std::endl;
        return VectorXf::Zero(EMBED_DIM); // 返回零向量避免传播错误
    }

    return pooled;
}

(2)全局投影矩阵 global_win 初始化异常

global_win 使用正态分布初始化,若参数不当可能导致值过大:
cpp
运行
// 在 ShardedManager::init_win 中调整分布参数
void init_win() {
    std::mt19937 gen(cfg.seed);
    // 缩小标准差(例如从 0.01 调整为 0.001),避免矩阵值过大
    std::normal_distribution<float> dist(0, 0.001); 
    // ... 现有逻辑 ...
}

(3)矩阵乘法溢出

global_win(4096x384)与 v(384x1)相乘时,若 v 有大值可能导致溢出:
cpp
运行
// 在计算 H32 前检查 v 的范围
VectorXf v = get_feature_vector_NEW(text);
if (v.array().isNaN().any() || v.array().abs().maxCoeff() > 1e4) {
    std::cerr << "警告:特征向量 v 异常,跳过样本" << std::endl;
    continue; // 跳过异常样本
}
// 计算 H32 时增加数值限制
H32.row(count) = (global_win * v).unaryExpr([](float x) { 
    // 限制输入到 tanh 的值范围,避免溢出
    x = std::clamp(x, -1e4f, 1e4f); 
    return std::tanh(x); 
});

3. 总结

nan 问题的根源是数值计算异常,建议优先检查 语义特征提取器的输出全局投影矩阵的初始化。通过增加异常值检查和限制数值范围,可以有效避免 nan 的产生和传播。