引自免费微信小程序:皆我百晓生
在处理一个序列响应与预测变量具有相同序列长度的序列响应问题时,我们需要确保以下几点:
-
序列长度:序列响应通常包含一组连续的数字,其每个值都对应着一个预测变量(例如,'Y')的位置。如果我们尝试将这些值映射到原始的
X输入矩阵(表示的是样本向量),我们可能会发现某些位置的X是空的或只包含有限个元素,导致length(XrTrain)小于length(YrTrain)。 -
序列长度:根据上述步骤,序列响应的长度通常是预测变量的行数。如果序列响应的长度不等于预测变量的行数,则这可能意味着我们在构建CNN-LSTM模型时,序列响应被剪切或转换成了单个元素(即
Z[i])。这就导致了sequenceLength为1或sequenceLength > length(YrTrain)的情况,从而使得训练数据中的预测变量位于一个序列长度较小的位置上,而序列响应中的其他部分则没有与其对应的需求。
要解决这个问题,我们可以采取以下策略:
解决方案一:预处理序列响应
- 缺失值填充:
如果序列响应中的某个位置上的所有元素都是空的或只有一个元素,我们可以使用填充技术(例如,零填充、随机填充等)来替换这些空值。在NumPy中,可以使用
numpy.nanmean()函数或numpy.random.randn()函数实现这个任务。
# 填充序列响应
for i in range(len(XrTrain)):
if np.isnan(XrTrain[i]):
XrTrain[i] = np.random.randn()
- 进行数据缩放:
虽然通过填充已知或期望值可以填补缺失值,但可能对不同的数据集效果不同。因此,对于特征较少的数据集,我们可能希望将其缩放到一个更小的范围内,以便更好地适应模型结构和需求。这里,我们将设置
shape(XrTrain),即XrTrain的形状为(XrTrain.shape[0], numFeatures),然后使用arraymap()函数应用一个固定的缩放系数:
def scale_data(XrTrain):
scaled_XrTrain = arraymap(lambda x: x / np.max(XrTrain), XrTrain)
return scaled_XrTrain.reshape(shape(XrTrain))
scaled_XrTrain = scale_data(XrTrain)
解决方案二:正则化预处理
在CNN-LSTM模型中,正则化是一种防止过拟合的技术,它通过对模型权重进行惩罚,降低复杂度,使模型更容易泛化到未见过的新数据上。在这种情况下,我们可以使用L1正则化或L2正则化来优化输入序列响应的权重,并减少预测变量之间的依赖性:
- L1正则化:
lambda_1 = 0.01:设置一个权重衰减项。在lr参数中设置1e-4,以使用默认的学习率进行训练。
options.L1Regularization = 1e-4
# L1正则化训练
net = trainNetwork(scaled_XrTrain,YrTrain,layers,options)
- L2正则化:
lambda_2 = 0.001:设置另一个权重衰减项。在lr参数中设置1e-6,同样可以使用默认的学习率进行训练。
options.L2Regularization = 1e-6
# L2正则化训练
net = trainNetwork(scaled_XrTrain,YrTrain,layers,options)
解决方案三:截断多态解码器(MLP)
考虑到CNN-LSTM模型结合了LSTM层和卷积神经网络(CNN),如果CNN层采用固定大小的卷积核和隐藏层,当预测变量的宽度不足以覆盖所有的特征时,可能会产生维度变高的情况,导致模型陷入局部最优解并影响性能。为此,我们可以使用多态解码器(MLP)进行数据切片,将序列响应分割成多个较小的片段,然后分别对其进行计算和更新。
- 多态解码器架构:
# 设定每个CNN模块的嵌套深度 max_depth = 2 # 使用递归方式创建多态解码器的嵌套结构 for depth in range(max_depth): net_layers.append([ feature_extractor_layer, recurrent_encoder_layer, decoder_layer, ]) feature_extractor_layer = feature_extraction_layer + ('FC', (max_features, )) recurrent_encoder_layer = recurrent_encoder_layer + ('FC', (max_features, )) decoder_layer = decoder_layer + ('FC', (max_features, )) input_layer = sequence_input_layer for n_in, n_out in zip(input_layer.shape[1:], [ n_in * feature_extractor_layer.n_features, # 卷积层输入特征的通道数 n_in * recurrent_encoder_layer.n_features, # 隐藏层输入特征的通道数 n_in * decoder_layer.n_features, # 隐藏层输出特征的通道数 ]): net_layers[-depth].append( linear_classifier_layer(n_in * max_features, n_out), ) # 应用多态解码器至整个模型 net = multi_tensor_stack(net_layers) # 在最后一个非编码层添加批次大小校验层 net = residual_block(net, 'batch_size', 16, activation='relu') # 构建多层馈送网络 for n_in, n_out in zip(input_layer.shape[1:], [ n_in * feature_extractor_layer.n_features, # 卷积层输入特征的通道数 n_in * recurrent_encoder_layer.n_features, # 隐藏层输入特征的通道数 n_in * decoder_layer.n_features, # 隐藏层输出特征的通道数 n_in * dense_layer_n_in, # 卷积层隐藏层输出特征的通道数 ]): net = add_twooutputs(inputs=[net_layers[-depth][n_in]], outputs=[net[-1][n_in]]) # 编译模型 optimizer = Adam(lr=learningrate) loss_function = nn.CrossEntropyLoss() criterion = nn.MSELoss() model = Model(inputs=input_layer, outputs=output_layer, losses=[criterion, loss_function]) model.compile(optimizer=optimizer, loss=criterion)
这段代码定义了一个多层的多态解码器架构,该架构首先使用递归方法(如`feature_extraction_layer`、`recurrent_encoder_layer`和`decoder_layer`)对输入序列响应进行切割,生成几个较小的片段,然后使用MPLP进行每个片段的计算和更新。最后,在编码层添加批次大小校验层,以便在每一帧的序列响应上进行平滑采样,从而得到单个像素级别的预测值。这与传统的CNN-LSTM架构不同,其中序列响应会被分块处理并一次性进行预测,而不是每次更新模型时才进行预测。
