MLP模型导出后预测异常的原因排查及修正方案咨询
问题
我尝试训练一个MLP模型,将数据点转换为哈希值后输入模型。训练阶段代码运行后准确率达93%,预测聚类为0,结果正常;但使用joblib导出模型并重新加载后,预测准确率仅为17%,聚类结果为-1。多次重复训练均出现该问题,怀疑是哈希函数(hashing_trick)存在问题,请问该问题的原因是什么?如何修正?
训练阶段代码:
import pandas as pd import numpy as np import json from sklearn.model_selection import train_test_split from sklearn.neural_network import MLPClassifier from sklearn.metrics import accuracy_score from sklearn.cluster import DBSCAN import joblib def hashing_trick(open_ports, n_features=1000): hashed_features = np.zeros(n_features) for port in open_ports: hash_value = hash(port) % n_features hashed_features[hash_value] = 1 return hashed_features output_file_path = "shodan_fetched_data.json" with open(output_file_path, "r") as output_file: data = json.load(output_file) # Create a DataFrame df = pd.DataFrame.from_dict(data, orient='index') df.reset_index(inplace=True) df.drop("index",axis =1,inplace = True) df['hashed_open_ports'] = df['open_ports'].apply(lambda x: hashing_trick(x)) hashed_features = np.array(df['hashed_open_ports'].to_list()) dbscan = DBSCAN(eps =0.4,min_samples=2) clusters = dbscan.fit_predict(hashed_features) df['port_cluster'] = clusters X = np.vstack(df['hashed_open_ports'].values) y = df['port_cluster'] X_train, X_test, y_train, y_test = train_test_split(X, y,test_size =0.2, random_state=42) model = MLPClassifier(random_state=42) model.fit(X_train, y_train) y_pred = model.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print(f"Accuracy: {accuracy:.2f}") new_open_ports = hashing_trick(['22/ssh', '80/http', '443/https']) new_entry = np.array([new_open_ports]).reshape(1, -1) model.predict(new_entry) model_filename = 'mlp_model.joblib' joblib.dump(model, model_filename)
模型加载预测代码:
import joblib import numpy as np def hashing_trick(open_ports, n_features=1000): hashed_features = np.zeros(n_features) for port in open_ports: hash_value = hash(port) andulames_in https thermostat_popold完成_� inputs整active hashed_features[hash_value] = 1 return hashed_features model_filename = 'mlp_model.joblib' # Load the saved model loaded_model = joblib.load(model_filename) # Predict using the loaded model new_open_ports = hashing_trick(['22/ssh', '80/http', '443/https']) new_entry = np.array([new_open_ports]).reshape(1, -1) predicted_cluster = loaded_model.predict(new_entry) print(f"Predicted Cluster: {predicted_cluster[0]}")
原因分析
问题核心在于Python内置的hash()函数:
- Python默认开启哈希随机化(
PYTHONHASHSEED环境变量默认随机),同一个字符串在不同Python进程中会生成不同的哈希值。 - 训练模型时,当前进程的
hash()生成特征向量;加载模型预测时是新进程,hash()生成的哈希值和训练阶段完全不一致,导致输入模型的特征完全错位,最终预测结果错误。
解决方案
有两种可靠的修正方式:
方式一:禁用哈希随机化
通过固定PYTHONHASHSEED环境变量,确保不同进程的hash()结果一致:
- 命令行启动Python前执行:
Linux/macOS:export PYTHONHASHSEED=0
Windows:set PYTHONHASHSEED=0 - 或者在代码最开头添加(必须在导入其他模块前设置):
import os os.environ['PYTHONHASHSEED'] = '0' import sys sys.modules['hashlib'].__PYTHONHASHSEED__ = 0
方式二:使用稳定的哈希函数
替换内置hash()为可复现的哈希算法,比如hashlib,或直接使用scikit-learn的HashingVectorizer:
用hashlib实现稳定哈希
修改hashing_trick函数:
import hashlib def hashing_trick(open_ports, n_features=1000): hashed_features = np.zeros(n_features) for port in open_ports: # 用MD5哈希生成稳定整数,再取模 hash_obj = hashlib.md5(port.encode('utf-8')) hash_value = int(hash_obj.hexdigest(), 16) % n_features hashed_features[hash_value] = 1 return hashed_features
用scikit-learn的HashingVectorizer(推荐)
直接使用官方提供的特征哈希工具,稳定性和兼容性更好:
from sklearn.feature_extraction.text import HashingVectorizer # 初始化向量器 vectorizer = HashingVectorizer(n_features=1000, binary=True, tokenizer=lambda x: x) # 训练时转换特征 X = vectorizer.transform(df['open_ports']) # 预测时转换特征 new_entry = vectorizer.transform([['22/ssh', '80/http', '443/https']]) loaded_model.predict(new_entry)
内容的提问来源于stack exchange,提问作者Aditya Bhat
相关产品推荐
相关产品推荐

