如何修改代码让训练后的模型为每个类别生成不同预测值?
问题:所有类别预测值相同的模型修复方案
针对你遇到的模型对所有类别输出相同预测值的问题,以下是具体的问题分析和代码修改方案:
核心问题分析
- 类别预处理逻辑冗余:你用
Tokenizer处理离散类别属于误用,Tokenizer适用于文本序列,而你的category是独立离散值,直接用标签编码更高效。 - 训练参数不合理:过大的
batch_size(1000)会导致梯度更新不充分,模型无法学到类别间的差异;固定100轮epochs可能出现欠拟合或过拟合。 - 未处理数据集不平衡:如果某个
value的样本占比过高,模型会倾向于预测该类别,导致所有输出一致。
具体修改方案
1. 修正类别预处理逻辑
替换原有的Tokenizer流程,用LabelEncoder对离散类别进行编码:
from sklearn.preprocessing import LabelEncoder # 对category进行标签编码 le_category = LabelEncoder() categories_encoded = le_category.fit_transform(categories) categories_encoded = categories_encoded.reshape(-1, 1) # 调整为模型可接受的形状
2. 调整模型结构
针对离散类别输入,简化模型并适配标签编码的输入格式:
model = tf.keras.Sequential([ tf.keras.layers.Embedding(input_dim=len(le_category.classes_), output_dim=32, input_length=1), tf.keras.layers.Flatten(), tf.keras.layers.Dense(32, activation='relu'), tf.keras.layers.Dense(len(value_labels), activation='softmax') ])
3. 优化训练参数
- 减小
batch_size让梯度更新更频繁 - 添加早停回调防止过拟合,同时保留最优权重
- 计算类别权重处理数据集不平衡:
from tensorflow.keras.callbacks import EarlyStopping from sklearn.utils.class_weight import compute_class_weight # 计算类别权重 class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) class_weight_dict = {i: class_weights[i] for i in range(len(class_weights))} # 早停回调 early_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) # 训练模型 model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_test, y_test), callbacks=[early_stop], class_weight=class_weight_dict)
4. 修正预测函数
适配标签编码的输入流程,避免重复计算映射关系:
# 提前创建value的反向映射(只执行一次) value_inv_mapping = {i: value for i, value in enumerate(value_labels)} def generate_prediction(input_category, le_category, model, value_inv_mapping): # 对输入类别编码 category_encoded = le_category.transform([input_category]).reshape(-1, 1) # 生成预测(关闭日志输出) prediction = model.predict(category_encoded, verbose=0) predicted_label = np.argmax(prediction) # 映射回原始value predicted_value = value_inv_mapping[predicted_label] return predicted_value
完整修改后的代码
import numpy as np import pandas as pd import tensorflow as tf import random from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from tensorflow.keras.callbacks import EarlyStopping from sklearn.utils.class_weight import compute_class_weight # 读取数据集 data = pd.read_csv('dataset.csv') # 数据预处理 categories = data['category'].tolist() values = data['value'].tolist() # 对category进行标签编码 le_category = LabelEncoder() categories_encoded = le_category.fit_transform(categories) categories_encoded = categories_encoded.reshape(-1, 1) # 编码目标变量 value_labels = np.unique(values) value_mapping = {value: i for i, value in enumerate(value_labels)} encoded_values = np.array([value_mapping[value] for value in values]) value_inv_mapping = {i: value for i, value in enumerate(value_labels)} # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split( categories_encoded, encoded_values, test_size=0.2, random_state=42 ) # 计算类别权重 class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) class_weight_dict = {i: class_weights[i] for i in range(len(class_weights))} # 构建模型 model = tf.keras.Sequential([ tf.keras.layers.Embedding(input_dim=len(le_category.classes_), output_dim=32, input_length=1), tf.keras.layers.Flatten(), tf.keras.layers.Dense(32, activation='relu'), tf.keras.layers.Dense(len(value_labels), activation='softmax') ]) # 编译模型 model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 早停回调 early_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) # 训练模型 model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_test, y_test), callbacks=[early_stop], class_weight=class_weight_dict) # 保存模型 model.save('model/category_predictor') model.save('model/category_predictor.h5') # 预测函数 def generate_prediction(input_category, le_category, model, value_inv_mapping): category_encoded = le_category.transform([input_category]).reshape(-1, 1) prediction = model.predict(category_encoded, verbose=0) predicted_label = np.argmax(prediction) predicted_value = value_inv_mapping[predicted_label] return predicted_value # 测试预测 categories_test = list(set(data['category'].tolist())) keywords = [] prompts = [] for _ in range(10): input_category = random.choice(categories_test) predicted_value = generate_prediction(input_category, le_category, model, value_inv_mapping) keywords.append(input_category) prompts.append(predicted_value) # 打印结果 for keyword, prompt in zip(keywords, prompts): print(f'Input category: {keyword} | Predicted value: {prompt}')
内容的提问来源于stack exchange,提问作者Teodor G.
相关产品推荐
相关产品推荐

