为何使用Brain.js LSTM 预测文本分类时输出非JSON预设的随机结果?
核心问题根源
当前实现和Brain.js LSTM的内置逻辑存在本质不匹配,是导致乱码输出的根本原因:
- Brain.js的
recurrent.LSTM默认是序列生成模型,会将你传入的output值拆解为逐字符的序列做学习,本质是拟合“根据输入文本生成最匹配的字符串序列”的概率规律,而非“从固定分类标签集合中选择一个匹配项输出”的分类任务。 - 你直接将完整的分类字符串(比如"current year profits")作为输出值喂入网络时,网络只会学习字符间的拼接转移概率,不会建立“输出必须严格落在预设20个标签范围内”的约束。随着迭代次数增加,网络会逐渐将不同标签的字符混排拼接,最终生成类似
retaicometrses、curued expenses current)这类带部分原标签字符特征、但完全无意义的字符串。 - 初期设置10次迭代的低配置会导致模型欠拟合,但这不是乱码的核心诱因——哪怕将迭代拉高到5000次,因为任务映射逻辑从根上错了,依然会生成自由拼接的无效字符串。
针对性修复方案
1. 调整训练数据结构,触发模型的分类输出模式
将原有的字符串输出替换为独热编码结构,让LSTM自动识别为固定维度的分类任务,不再逐字符生成字符串:
- 第一步先对所有分类标签去重,得到固定长度的标签集合
- 训练数据的output字段不再放字符串,改为对象结构:仅将当前样本对应的分类标签键值设为1,其余所有标签的键值为0
- 预测完成后,取概率值最高的标签作为最终输出,全程不会生成超出标签集的内容
修正后的核心代码示例:
const brain = require('brain.js'); const data = require('./balancesheet.json'); // 提取去重后的固定分类标签集合 const uniqueCategories = [...new Set(data.map(item => item.category))]; // 初始化LSTM网络 const network = new brain.recurrent.LSTM(); // 改造训练数据为独热编码格式 const trainingData = data.map(item => { const outputMap = {}; outputMap[item.category] = 1; return { input: item.text, output: outputMap }; }); // 配置合理的训练参数 network.train(trainingData, { iterations: 200, log: currentError => console.log(`当前训练误差: ${currentError.toFixed(4)}`), errorThresh: 0.01 // 误差达到阈值后自动停止训练 }); // 运行预测 const prediction = network.run('net income'); // 从预测结果中取概率最高的分类标签 const bestMatchedCategory = Object.keys(prediction).reduce((prev, curr) => prediction[prev] > prediction[curr] ? prev : curr ); console.log(`Category: ${bestMatchedCategory}`);
2. 训练参数适配调整
- 无需盲目拉高迭代次数:搭配独热编码结构后,100-300次迭代足够支撑1000条样本、20个分类规模的训练需求,过高迭代反而会引发过拟合,降低模型对新文本的泛化能力。
- 建议开启误差阈值配置,让网络在训练误差降到合理范围后自动停止,减少无意义的训练时长。
- 训练完成后可先用数据集内已标注的文本做回归测试,确认输出完全匹配预设标签后,再用来处理新输入文本。
3. 场景适配优化
如果处理的是这类短文本资产负债表条目分类,不需要依赖序列记忆能力,也可以将LSTM网络替换为Brain.js内置的brain.NeuralNetwork模型,训练速度更快,分类稳定性更高。
内容的提问来源于stack exchange,提问作者AzusOCE
相关产品推荐
相关产品推荐

