小恶意代码识别器(4)

📅 发布时间:2026/10/14 17:17:12
小恶意代码识别器(4)
让程序会判断归一化、逻辑回归与模型文件前两篇把数据读进来了也检查过了这篇写程序真正做判断的部分怎么把特征值变成 0 到 1 之间的概率。为什么需要归一化五个特征的量级差得太远文件大小是几万甚至几十万比例是零点几。如果直接拿去加权求和大的数会把小的数完全压过去模型等于只看文件大小另外四个特征成了摆设。解决办法是把每个特征按比例缩放到相近的范围公式是x (原始值 - min) / (max - min)min 和 max 是这一列在训练集上的最小值和最大值。比如 file_size 这一列最小 18432、最大 266240那么 18432 缩放后是 0266240 是 1中间的值落在 0 到 1 之间。关键在于训练和预测必须用同一组 min 和 max否则标准变了结果就不可比。所以模型文件里要把它们存下来。权重和偏置是什么判断的依据是五个特征的加权和再加一个偏置z bias w0*x0 w1*x1 w2*x2 w3*x3 w4*x4权重表示每个特征的重要程度。老师给的模型里信息熵的权重是 4.319最大说明这个特征最能说明问题文件大小的权重只有 0.166参考价值最小。权重为负说明这个特征越大反而越不像可疑。偏置可以理解成判定的门槛。我们这个模型的偏置是 -2.494是个负数意味着证据的分数必须先填平这个坑总分才能回到 0概率才能到 0.5。相当于默认假定良性证据足够强才改判可疑。这个值是训练时机器在训练集上试出来的不是人工拍的。从总分到概率总分 z 可能是很大的正数也可能是很小的负数不方便解读用 Sigmoid 压到 0 到 1 之间p 1 / (1 e^(-z))z 为 0 时 p 正好是 0.5大于 0.5 判可疑小于 0.5 判良性。读模型文件模型文件一共六行分别是标识、特征数、五个权重、偏置、五个最小值、五个最大值。用fscanf按顺序读它会自动跳过空白和换行。FILE*fpfopen(path,r);if(fpNULL){printf(open failed\n);return1;}chartag[64];fscanf(fp,%63s,tag);if(strcmp(tag,TEACHMODEL_V1)!0){printf(bad model\n);fclose(fp);return1;}intk;fscanf(fp,%d,k);if(k!FEATURE_COUNT){printf(bad feature count\n);fclose(fp);return1;}for(intj0;jFEATURE_COUNT;j){fscanf(fp,%lf,model-weights[j]);}fscanf(fp,%lf,model-bias);for(intj0;jFEATURE_COUNT;j){fscanf(fp,%lf,scaler-minv[j]);}for(intj0;jFEATURE_COUNT;j){fscanf(fp,%lf,scaler-maxv[j]);}model-trained1;第一行标识要先验证遇到不是这个格式的文件直接拒收。第二行的特征数也要核对防止读到错位的数据。最后那句model-trained 1是设一个标记骨架的菜单里在预测前会检查这个标记没加载模型就拒绝预测。预测函数三步合起来就这几行doublezmodel-bias;for(intj0;jFEATURE_COUNT;j){doublerangescaler-maxv[j]-scaler-minv[j];doublex;if(range0){x0;}else{x(raw_features[j]-scaler-minv[j])/range;}zzmodel-weights[j]*x;}return1.0/(1.0exp(-z));range是这一列的跨度也就是 max 减 min。要用一个 if 单独判断它是不是 0因为万一训练集里某列所有值都一样除零会让程序直接崩掉约定这种情况归一化结果算 0。z一开始等于偏置然后循环里把每个特征的加权结果累加进去循环结束时就是完整的总分。最后一行是 Sigmoid。这里有个容易忽略的细节常数要写成1.0而不是1。C 语言里两个整数相除会直接丢掉小数部分1 / 2的结果是 0 而不是 0.5。对答案老师给了一份sample_expected.csv里面是八条样本的标准预测概率第一条是 0.0742812554。我的程序读sample.csv加载模型预测第一条输出 0.074281和标准答案一致。这说明归一化、加权求和、Sigmoid 这三步每一步都算对了。八条样本的结果也符合预期良性样本的概率都在 0.33 以下可疑样本都在 0.61 以上分得比较开。归一化参数也可以自己算进阶选做里有一项是fit_scaler就是不看老师给的参数自己从训练集里把每列的最小值和最大值找出来。算法是打擂台先拿第一条样本当初始的最大值和最小值后面每条样本逐列比较比当前最小值小就更新最小值比当前最大值大就更新最大值。for(intj0;jFEATURE_COUNT;j){scaler-minv[j]data-samples[0].features[j];scaler-maxv[j]data-samples[0].features[j];}for(inti1;idata-count;i){for(intj0;jFEATURE_COUNT;j){doublevdata-samples[i].features[j];if(vscaler-minv[j])scaler-minv[j]v;if(vscaler-maxv[j])scaler-maxv[j]v;}}用train.csv跑出来的结果和模型文件里存的那两行一致说明计算过程是对的。这里有个原则要注意只能在训练集上算不能在测试集上算标准如果参照了考试卷本身结果就没有意义了。