Browse Source

Merge branch 'dev_david' of anweiguo/algorithm_platform into dev_awg

liudawei 2 weeks ago
parent
commit
19b7fbc8b1
2 changed files with 71 additions and 3 deletions
  1. 28 1
      models_processing/model_tf/losses.py
  2. 43 2
      models_processing/model_tf/tf_lstm_zone.py

+ 28 - 1
models_processing/model_tf/losses.py

@@ -35,6 +35,32 @@ class MSE(tf.keras.losses.Loss):
         loss = tf.reduce_mean(squared_difference, axis=-1) * coefficient
         return loss
 
+class MSE_ZONE(tf.keras.losses.Loss):
+    """
+    自定义损失函数模板
+    功能:实现名称设置、参数保存、张量运算分离
+    """
+
+    def __init__(self,
+                 name,  # 设置损失名称
+                 reduction='mean',
+                 **kwargs):
+        super().__init__(name=name, reduction=reduction)
+
+        # 可添加自定义参数(自动序列化)
+        self.param = kwargs.get('param', 1.0)
+
+    def call(self, y_true, y_pred):
+        """核心计算逻辑(分离张量运算和非张量运算)"""
+        # 非张量运算(预处理)
+        coefficient = tf.constant(self.param, dtype=y_pred.dtype)
+
+        # 张量运算(保持计算图兼容性)
+        squared_difference = tf.square(y_pred - y_true)
+        mse_loss = tf.reduce_mean(squared_difference, axis=-1) * coefficient
+        sum_loss = tf.reduce_mean(tf.square(tf.reduce_sum(y_pred, axis=-1) - tf.reduce_sum(y_true, axis=-1)))
+        loss = mse_loss + 0.2 * sum_loss
+        return loss
 
 class RMSE(Loss):
     """Root Mean Squared Error 损失函数(兼容单变量/多变量回归)"""
@@ -171,7 +197,8 @@ class SouthLoss(Loss):
 
 region_loss_d = {
     'northeast': lambda region: RMSE(region),
-    'south': lambda cap, region: SouthLoss(cap, region)
+    'south': lambda cap, region: SouthLoss(cap, region),
+    'zone': lambda region: MSE_ZONE(region) # 分区建模损失:MSE + 分区总和一致性约束
 }
 
 

+ 43 - 2
models_processing/model_tf/tf_lstm_zone.py

@@ -5,7 +5,7 @@
 # @Author    :David
 # @Company: shenyang JY
 
-from tensorflow.keras.layers import Input, Dense, LSTM, concatenate, Conv1D, Conv2D, MaxPooling1D, Reshape, Flatten
+from tensorflow.keras.layers import Input, Dense, LSTM, concatenate, Conv1D, Conv2D, MaxPooling1D, Reshape, Flatten, Add, Multiply, Concatenate
 from tensorflow.keras.models import Model, load_model
 from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, TensorBoard, ReduceLROnPlateau
 from tensorflow.keras import optimizers, regularizers
@@ -37,7 +37,7 @@ class TSHandler(object):
             self.logger.info("加载模型权重失败:{}".format(e.args))
 
     @staticmethod
-    def get_keras_model(opt, time_series=1, lstm_type=1):
+    def get_keras_model_20250515(opt, time_series=1, lstm_type=1):
         loss = region_loss(opt)
         l1_reg = regularizers.l1(opt.Model['lambda_value_1'])
         l2_reg = regularizers.l2(opt.Model['lambda_value_2'])
@@ -59,6 +59,47 @@ class TSHandler(object):
 
         return model
 
+    @staticmethod
+    def get_keras_model(opt, time_series=1, lstm_type=1):
+        loss = region_loss(opt)
+        l1_reg = regularizers.l1(opt.Model['lambda_value_1'])
+        l2_reg = regularizers.l2(opt.Model['lambda_value_2'])
+        nwp_input = Input(shape=(opt.Model['time_step'] * time_series, opt.Model['input_size']), name='nwp')
+
+        con1 = Conv1D(filters=64, kernel_size=1, strides=1, padding='valid', activation='relu',
+                      kernel_regularizer=l2_reg)(nwp_input)
+        con1_p = MaxPooling1D(pool_size=1, strides=1, padding='valid', data_format='channels_last')(con1)
+        nwp_lstm = LSTM(units=opt.Model['hidden_size'], return_sequences=True, kernel_regularizer=l2_reg)(con1_p)
+        # 分区A/B独立特征提取
+        zone_a = LSTM(units=32, return_sequences=True, kernel_regularizer=l2_reg)(nwp_lstm)  # 独立LSTM分支
+        zone_b = LSTM(units=32, return_sequences=True, kernel_regularizer=l2_reg)(nwp_lstm)
+
+        # 动态权重门控
+        gate = Dense(2, activation='softmax')(nwp_lstm)  # 自动学习分区重要性
+        weighted_zone = Add()([
+            Multiply()([gate[:, :, 0:1], zone_a]),
+            Multiply()([gate[:, :, 1:2], zone_b])
+        ])
+
+        zone_pred = Dense(len(opt.zone), name='zone')(weighted_zone)
+        zone_flat = Flatten()(zone_pred)
+        # 在zone_flat后添加交叉层
+        cross_input = Concatenate()([zone_flat, nwp_lstm[:, -1, :]])  # 融合分区特征和LSTM最后时刻状态
+        cross_layer = Dense(64, activation='relu')(cross_input)
+
+        # 最终输出层
+        if lstm_type == 2:
+            output = Dense(opt.Model['time_step'], name='cdq_output')(cross_layer)
+        else:
+            output = Dense(opt.Model['time_step'] * time_series, name='cdq_output')(cross_layer)
+
+        model = Model(nwp_input, [zone_pred, output])
+        adam = optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-7, amsgrad=True)
+        model.compile(loss={"zone": loss, "cdq_output": loss}, loss_weights={"zone": 0.7, "cdq_output": 0.3},
+                      optimizer=adam)
+
+        return model
+
     def train_init(self):
         try:
             # 进行加强训练,支持修模