无监督LSTM异常检测无有效重构问题排查求助
问题背景
我采用无监督LSTM进行数据异常检测,核心逻辑为重构结果与输入差异过大则判定为异常。数据集包含Day和Result两个字段,训练集全部为正常数据,测试集混入部分异常数据点。
数据形状
trainX shape: (46779, 50) | trainY shape: (46779,) testX shape: (12447, 50) | testY shape: (12447,)
序列生成代码
seq_size = 50 def to_sequences_per_day(df, seq_size=1): x_values = [] y_values = [] for day, group in df.groupby('Day'): day_results = group['Result'].values for i in range(len(day_results) - seq_size): x_values.append(day_results[i:(i+seq_size)]) y_values.append(day_results[i+seq_size]) return np.array(x_values), np.array(y_values)
模型结构
# Define the model model = Sequential() # Encoder model.add(LSTM(64, input_shape=(seq_size, 1), return_sequences=True)) model.add(LSTM(32, return_sequences=True)) model.add(LSTM(16, return_sequences=False)) # Decoder model.add(Dense(32, activation='relu')) model.add(Dense(64, activation='relu')) model.add(Dense(1, activation='sigmoid')) # Compile the model optimizer = Adam(learning_rate=0.001) model.compile(optimizer=optimizer, loss='mae') early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) history = model.fit(trainX, trainX, epochs=100, batch_size=32, validation_split=0.1, callbacks=[early_stopping], verbose=1)
示例数据集(非实际使用)
data = pd.DataFrame({ 'Day': [1, 1, 2, 3, 3, 3,...], 'Result': [150, 158, 114, 120, 160, 125,...] }) # This result will later be normalised to range from 0 to 1
当前问题与原因分析
目前遇到的核心问题是验证损失极低且快速进入平台期,模型无法有效学习Result的序列模式完成重构。可能的原因如下:
输入数据维度不匹配:LSTM要求输入为3D张量
(样本数, 时间步, 特征数),但你生成的trainX是2D数组(46779, 50),缺少特征维度。模型实际会把每个样本当成50个独立特征的静态数据处理,而非序列数据,导致轻易拟合简单统计规律,损失快速下降。解决方式是给输入增加特征维度:trainX = trainX.reshape(trainX.shape[0], trainX.shape[1], 1)。重构任务目标错误:当前训练时用
trainX同时作为输入和标签,但你的序列生成逻辑是用前50个点预测下1个点,而模型最后一层仅输出1个值,和输入的50步序列维度不匹配。这种任务混淆会让模型只能拟合输入的均值或固定值,无法学习序列依赖。若要做序列重构,需调整模型输出为50步序列;若做单步预测,应将trainY作为训练标签,而非trainX。归一化与数据分布问题:若
Result归一化后分布过于集中(比如大部分值接近),模型只需输出固定值就能得到低损失,无需学习序列模式。建议检查归一化后的数据波动情况,确保数据有足够的方差让模型捕捉序列规律。模型结构与任务不匹配:如果目标是序列重构,当前解码器结构完全不适用。编码器输出的16维向量需要还原为50步序列,应添加
RepeatVector(seq_size)将向量复制50次,再接LSTM层做序列解码,最后用TimeDistributed(Dense(1))输出每个时间步的重构值。早停机制触发过早:patience=5的设置可能让模型在学习到简单规律后就停止训练,还没来得及捕捉复杂序列模式。可以先移除早停,观察训练损失和验证损失的变化,若后期出现验证损失上升再调整patience参数。
内容的提问来源于stack exchange,提问作者Anonymous01

