Je travaille sur un problème de prédiction spatio-temporelle où je veux prévoir une valeur scalaire par nœud spatial au fil du temps. Mes données s’étendent sur plusieurs emplacements de grille spatiale avec des observations quotidiennes.
Configuration des données
- La région spatiale est divisée en sous-régions, chacune avec une structure graphique.
- Chaque nœud représente une cellule de grille avec des caractéristiques d’entrée: variable_value_t, lat, lon
- Les bords sont statiques pour une sous-région et se forment en fonction de la distance et de la corrélation
- Les caractéristiques de bord comprennent la direction et la distance.
- Chaque sous-région est normalisée indépendamment en utilisant la normalisation des scores Z (moyenne / std à partir de la division d’entraînement).
Modèle
class GNNLayer(nn.Module): def __init__(self, node_in_dim, edge_in_dim, hidden_dim): ... self.attention = nn.MultiheadAttention(embed_dim=hidden_dim, num_heads=2, batch_first=True) def forward(self, x, edge_index, edge_attr): row, col = edge_index src, tgt = x(row), x(col) edge_messages = self.edge_net(edge_attr, src, tgt) agg_msg = torch.zeros_like(x).index_add(0, col, edge_messages) x_updated = self.node_net(x, agg_msg) attn_out, _ = self.attention(x_updated.unsqueeze(0), x_updated.unsqueeze(0), x_updated.unsqueeze(0)) return x_updated + attn_out.squeeze(0), edge_messages class GNNLSTM(nn.Module): def __init__(self, ...): ... self.gnn_layers = nn.ModuleList((...)) self.lstm = nn.LSTM(input_size=hidden_dim, hidden_size=128, num_layers=2, dropout=0.2, batch_first=True) self.pred_head = nn.Sequential( nn.Linear(128, 64), nn.LeakyReLU(0.1), nn.Linear(64, 2 * pred_len) ) def forward(self, batch): ... for t in range(T): x_t = graph.x # batched node features for gnn in self.gnn_layers: x_t, _ = gnn(x_t, graph.edge_index, graph.edge_attr) x_stack.append(x_t) x_seq = torch.stack(x_stack, dim=1) # (B, T, N, hidden_dim) lstm_out, _ = self.lstm(x_seq.reshape(B*N, T, -1)) out = self.pred_head(lstm_out(:, -1)).view(B, N, 2) mean, logvar = out(..., 0), out(..., 1) return mean, torch.exp(logvar) + 1e-3
Détails de la formation
Perte: perte de MSE
Optimiseur: Adam, LR = 1E-4
Planificateur: réducelronplateau
Formation par sougion (chaque sous-région est formée indépendamment)
J’ai également essayé d’utiliser l’apprentissage du curriculum: commencez avec 50 lots et augmentez progressivement chaque époque jusqu’à ce que l’ensemble de formation complet soit utilisé. J’ai 500 lots au total dans la scission du train
Problème: Lorsqu’il est entraîné sur un petit nombre de lots, le modèle converge et donne des résultats raisonnables. Cependant, lorsqu’il est formé sur l’ensemble de données complet, le modèle:
- Montre une perte de validation incohérente ou aggravée après quelques époques
- Semble compter trop sur le LSTM (par exemple, lstm.weight_hh_ * a des mises à jour de paramètres beaucoup plus élevées que les couches GNN)
- Continue à prédire mal sur les mêmes quelques cellules de grille au fil du temps
J’ai essayé:
- Augmentation de la profondeur GNN (actuellement 4 couches)
- Coupure de dégradé
- Attention + résidus + norme de couche dans GNN
Qu’est-ce qui pourrait faire échouer le modèle GNN-LSTM avec les données de formation complètes malgré le succès avec des sous-ensembles plus petits? Je suis à la fin de mon esprit.
C’était pour un chèque de santé mentale – je me suis entraîné sur 40 lots et validé sur 10.