// 初始化画布
let PaintArray = Array.from({ length: 28 }, () => Array(28).fill(0));
let cursor = 0;
let blockChar = 0; // 等边模式
// 训练相关
let trainingData = [];
let isTraining = true;
let currentDigit = 0;
let samplesCollected = 0;
// 简单神经网络参数
let weights = Array.from({ length: 10 }, () => Array(784).fill(0));
let biases = Array(10).fill(0);
// 转换函数
function intToXY(int) { return [int % 28, Math.floor(int / 28)]; }
function xyToInt([x, y]) { return x + y * 28; }
// 界面显示
function displayConfidence(probs) {
const maxLen = 20;
return probs.map((p, i) =>
`${i}: ${'■'.repeat(Math.round(p * maxLen))} ${(p * 100).toFixed(1)}%`
).join('\n');
}
// 神经网络函数
function softmax(logits) {
const maxLogit = Math.max(...logits);
const exps = logits.map(l => Math.exp(l - maxLogit));
const sum = exps.reduce((a, b) => a + b, 0);
return exps.map(e => e / sum);
}
function predict(image) {
const inputs = image.flat();
const logits = weights.map((w, i) =>
w.reduce((sum, val, j) => sum + val * inputs[j], 0) + biases[i]
);
return softmax(logits);
}
// 训练函数
function train() {
const learningRate = 0.01;
// 随机初始化权重
weights = weights.map(w => w.map(() => Math.random() * 0.1 - 0.05));
biases = biases.map(() => Math.random() * 0.1 - 0.05);
// 简单梯度下降
for (let epoch = 0; epoch < 50; epoch++) {
trainingData.forEach(({ input, label }, index) => {
console.log(`[迭代 ${epoch + 1} / 50] 正在 Predict 训练数据 ${label} 的第 ${index} 项`);
const probs = predict(input);
// 计算梯度
const gradients = probs.map((p, i) =>
(i === label ? 1 : 0) - p
);
// 更新参数
weights = weights.map((w, i) =>
w.map((val, j) =>
val + learningRate * gradients[i] * input.flat()[j]
)
);
biases = biases.map((b, i) =>
b + learningRate * gradients[i]
);
});
}
}
// 绘制界面
function outputPaint() {
console.clear();
const [curX, curY] = intToXY(cursor);
const canvas = PaintArray
.map((row, y) => row
.map((val, x) =>
(x === curX && y === curY) ? (val ? '■' : '□') :
val ? '█' : ' '
)
.map((char) => {
return char.repeat((blockChar && char.length == 1) ? 2 : 1)
})
.join('')
).join('\n');
// 右侧信息面板
let rightPanel = '';
if (isTraining) {
rightPanel = `训练模式\n当前数字: ${currentDigit}\n已收集样本: ${samplesCollected}(至少3)\n收集完成后按下 t\n\nWSAD移动\nSpace输入\n\n\n绘画板显示错误?\n按下 q 试试`;
} else {
const probs = predict(PaintArray);
rightPanel = `识别模式\n${displayConfidence(probs)}\n结果: ${probs.indexOf(Math.max(...probs))}`;
}
// 分栏显示
const leftLines = canvas.split('\n');
const rightLines = rightPanel.split('\n');
const combined = leftLines.map((line, i) =>
line + ' ' + (rightLines[i] || '')
).join('\n');
console.log(combined);
}
// 输入处理
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', (key) => {
if (key === '\x03') process.exit(); // Ctrl+C
// 训练模式逻辑
if (isTraining) {
if (key === 't') {
if (samplesCollected >= 3) {
if (currentDigit < 9) {
currentDigit++;
samplesCollected = 0;
} else {
train();
isTraining = false;
console.log('训练完成! 进入识别模式');
}
}
return outputPaint();
}
if (key >= '0' && key <= '9') {
const digit = parseInt(key);
if (digit === currentDigit) {
trainingData.push({
input: PaintArray.map(row => [...row]),
label: digit
});
samplesCollected++;
PaintArray = PaintArray.map(row => row.fill(0));
outputPaint();
}
}
}
// 光标控制
switch(key.toLowerCase()) {
case 'w': cursor = Math.max(0, cursor - 28); break;
case 's': cursor = Math.min(783, cursor + 28); break;
case 'a': cursor = Math.max(0, cursor - 1); break;
case 'd': cursor = Math.min(783, cursor + 1); break;
case ' ':
const [x, y] = intToXY(cursor);
PaintArray[y][x] = 1 - PaintArray[y][x];
break;
case 'q':
blockChar = !blockChar;
break;
}
outputPaint();
});
// 初始化界面
console.log('训练模式说明:\n1. 绘制数字\n2. 按下数字键保存样本\n3. 按t完成当前数字训练');
outputPaint();
代码是人+ai整的,但是整出来的准确率……基本上没正确的哈哈哈
求大佬指教