基于MovieLens数据集的电影评分预测模型Loss与精度无变化求助
问题
尝试使用MovieLens数据集构建机器学习模型预测电影评分,但模型的Loss和指标始终维持在约0.4800左右,无论调整正则化、Dropout、学习率或模型复杂度都没有变化。数据集包含10万条数据,以下是代码:
import pandas as pd import tensorflow as tf from sklearn.preprocessing import MinMaxScaler from keras.layers import Dense from keras.optimizers import SGD, Adam, Adagrad import numpy as np from sklearn.model_selection import train_test_split from scipy import stats from keras import regularizers from keras.layers import Dropout # load in the dataset dataset = pd.read_csv(r'C:\Users\danie\Desktop\Book11.csv') # reshaping the data scaler = MinMaxScaler() dataset['rating'] = scaler.fit_transform(dataset['rating'].values.reshape(-1, 1)) # remove outliers z = np.abs(stats.zscore(dataset)) dataset = dataset[(z < 3).all(axis=1)] # initializing the X and Y variable x = dataset.drop(columns=['rating']) y = dataset['rating'] # initialise training and testing sets x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) # creating the model model = tf.keras.models.Sequential() # reshape input data for a conv2d layer x_train = np.reshape(x_train.values, (x_train.shape[0], x_train.shape[1], 1, 1)) x_test = np.reshape(x_test.values, (x_test.shape[0], x_test.shape[1], 1, 1)) # create the model model.add(tf.keras.layers.Conv2D(filters=4, kernel_size=(3, 3), input_shape=(x_train.shape[1], 1, 1), activation='relu', padding='same', strides=(1, 1), kernel_regularizer=regularizers.l2(0.001))) model.add(tf.keras.layers.Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(512, activation='relu')) model.add(Dropout(0.05)) model.add(Dense(1, activation='relu')) # compile the model model.compile(optimizer=Adam(learning_rate=0.01), loss='mean_squared_error', metrics=['mean_squared_error']) model.fit(x_train, y_train, epochs=100) # evaluate the model model.evaluate(x_test, y_test)
问题分析与解决方案
核心问题定位
模型Loss不下降的核心原因是输入数据处理逻辑错误和模型结构与任务不匹配,以下是具体改进步骤:
1. 替换不合理的Conv2D层,改用推荐任务适配的结构
MovieLens的核心输入是用户ID、电影ID这类离散特征,2D卷积仅适用于空间网格类数据(如图片),强行将扁平特征reshape为4D张量会让卷积层无法提取有效模式。推荐使用**嵌入层(Embedding)**处理离散ID,这是评分预测任务的标准方案:
# 假设x包含user_id和movie_id两列,先统计特征维度 user_count = dataset['user_id'].nunique() movie_count = dataset['movie_id'].nunique() # 构建多输入嵌入模型 user_input = tf.keras.layers.Input(shape=(1,), name='user_input') movie_input = tf.keras.layers.Input(shape=(1,), name='movie_input') user_embedding = tf.keras.layers.Embedding(user_count, 64)(user_input) movie_embedding = tf.keras.layers.Embedding(movie_count, 64)(movie_input) # 合并嵌入特征并后续连接全连接层 concatenated = tf.keras.layers.Concatenate()([tf.keras.layers.Flatten()(user_embedding), tf.keras.layers.Flatten()(movie_embedding)])
2. 修正输出层激活函数
输出层使用relu会导致:当模型预测值低于0时输出被截断为0,引发梯度消失。由于rating已被MinMaxScaler缩放到[0,1]区间,可改用sigmoid激活,或直接移除激活函数(回归任务无需激活,输出可反向缩放回原始评分范围):
model.add(Dense(1)) # 回归任务优先选择无激活,或用sigmoid匹配[0,1]标签范围
3. 降低学习率
当前Adam的学习率0.01过高,会导致模型在最优值附近震荡无法收敛,建议调整为0.001或更低:
model.compile(optimizer=Adam(learning_rate=0.001), loss='mean_squared_error', metrics=['mean_squared_error'])
4. 修正数据处理顺序
先对rating做归一化再移除异常值的逻辑错误,异常值判断应基于原始数据:
# 修正后的数据处理流程 dataset = pd.read_csv(r'C:\Users\danie\Desktop\Book11.csv') # 第一步:移除原始数据的异常值 z = np.abs(stats.zscore(dataset)) dataset = dataset[(z < 3).all(axis=1)] # 第二步:对rating做归一化 scaler = MinMaxScaler() dataset['rating'] = scaler.fit_transform(dataset['rating'].values.reshape(-1, 1))
5. 增加训练监控与数据有效性检查
在训练时加入验证集,实时观察训练集和验证集的Loss变化,确认模型是否真的没有学习:
model.fit(x_train, y_train, epochs=100, validation_data=(x_test, y_test), batch_size=256)
同时打印x.head()确认特征是否有效——如果x仅包含无意义的索引列,模型自然无法学习。
6. 先从简单模型验证收敛性
当前全连接层规模过大(256+256+512),易导致模型不稳定。先从简单模型开始验证:
model = tf.keras.models.Sequential() model.add(Dense(64, activation='relu', input_shape=(x_train.shape[1],))) model.add(Dense(32, activation='relu')) model.add(Dense(1))
等简单模型能正常收敛Loss下降后,再逐步增加复杂度。
内容的提问来源于stack exchange,提问作者Daniel Person
相关产品推荐
相关产品推荐

