model_network.py

一、处理流程

1.  class STTrajSimEncoder(nn.Module)---时空轨迹相似性编码器
  
(1) 初始化函数 ---self.stEncoder = ST_Encoder()
  (2) forward前向传播函数---
st_emb = self.stEncoder(network, traj_seqs, time_seqs)
2.
class ST_Encoder(nn.Module)---时空轨迹编码器
  
(1) 初始化函数 ---创建空间编码、时间编码、联合注意力、时空序列编码对象
   
 self.embedding_S = TrajEmbedding(feature_size, embedding_size, device)
    self.embedding_T = TimeEmbedding(date2vec_size, device)
    self.co_attention = Co_Att(date2vec_size).to(device)
    self.encoder_ST = ST_LSTM(embedding_size+date2vec_size, hidden_size, num_layers, dropout_rate, device)
  (2) forward前向传播函数---st_emb = self.stEncoder(network, traj_seqs, time_seqs)

    s_input, seq_lengths = self.embedding_S(network, traj_seqs) # 获取空间嵌入表示

    t_input = self.embedding_T(time_seqs) # 获取时间嵌入表示
    att_s, att_t = self.co_attention(s_input, t_input) # 获取时空融合注意力表示

    st_input = torch.cat((att_s, att_t), dim=2) # 连接空间、时间注意力结果
    # 将变长序列(padded sequence)转换为压缩的序列(packed sequence)
    packed_input = pack_padded_sequence(st_input, seq_lengths, batch_first=True, enforce_sorted=False) # 将填充后的序列数据按照实际长度进行压缩,即去除填充部分,并将其转换为一个压缩后的序列对象,该对象包含两个属性:data 和 batch_sizes。

    att_output = self.encoder_ST(packed_input) # 获取最终的序列表示

    return att_output # 返回最终的序列表示结果

二、重点函数解读

1. class TrajEmbedding(nn.Module)

    seq_lengths = list(map(len, traj_seqs)) # 计算列表 traj_seqs 中每个元素的长度,并将这些长度存储在 seq_lengths 列表中

 

  ① 对序列进行填充,使得所有序列的长度相等

    for traj_one in traj_seqs:

       traj_one += [0]*(max(seq_lengths)-len(traj_one))  # 对于每个序列 traj_one,它会使用 [0] 来填充序列,直到其长度等于最长序列的长度

               操作目的:这种操作通常在处理可变长度序列时很有用,例如在准备数据进行批处理时,需要将序列长度对齐以便输入到神经网络中。填充通常使用特定的值(通常是零)进行,以确保填充不会影响模型的学习过程。

  ②通过GCN模型获取节点嵌入表示---输入为network,由节点、边、边权重构建的路网结构

    node_embeddings = self.gcn(network)

  ③ 道路网络拓扑结构信息与轨迹序列信息进行“融合”

   for idx, (seq, seqlen) in enumerate(zip(traj_seqs, seq_lengths)): # 将节点嵌入填充到嵌入后的轨迹序列张量中,以便将轨迹序列嵌入到网络拓扑结构中

    embedded_seq_tensor[idx, :seqlen] = node_embeddings.index_select(0, seq[:seqlen])

 

2. class TimeEmbedding(nn.Module)

  基本同TrajEmbedding操作,唯一不同TimeEmbedding没有“通过GCN模型获取节点嵌入表示”过程

3. class Co_Att(nn.Module)

 整体实现原理同Transformer模型的多头注意力机制 

def __init__(self, dim):
super(Co_Att, self).__init__()
self.Wq = nn.Linear(dim, dim, bias=False)
self.Wk = nn.Linear(dim, dim, bias=False)
self.Wv = nn.Linear(dim, dim, bias=False)
self.temperature = dim ** 0.5
self.FFN = nn.Sequential(
nn.Linear(dim, int(dim*0.5)),
nn.ReLU(),
nn.Linear(int(dim*0.5), dim),
nn.Dropout(0.1)
)
self.layer_norm = nn.LayerNorm(dim, eps=1e-6)

def forward(self, seq_s, seq_t):
h = torch.stack([seq_s, seq_t], 2) # [n, 2, dim]
q = self.Wq(h)
k = self.Wk(h)
v = self.Wv(h)
attn = torch.matmul(q / self.temperature, k.transpose(2, 3))
attn = F.softmax(attn, dim=-1)
attn_h = torch.matmul(attn, v)

attn_o = self.FFN(attn_h) + attn_h
attn_o = self.layer_norm(attn_o)

att_s = attn_o[:, :, 0, :]
att_t = attn_o[:, :, 1, :]

return att_s, att_t

4.class ST_LSTM(nn.Module)

  ① 调用双向LSTM模型

  ② 将变长序列转换为压缩的序列,可以在使用循环神经网络(RNN)、长短期记忆网络(LSTM)或者门控循环单元(GRU)等模型时,提高计算效率,同时避免不必要的填充部分对模型造成影响。

    outputs, seq_lengths = pad_packed_sequence(packed_output, batch_first=True)

  ③ 输入的实际序列长度生成了一个掩码,用于在处理变长序列时屏蔽填充部分的影响---mask = self.getMask(seq_lengths)

  ④ 注意力机制

# Attention...
# (batch_size, seq_len, 2 * num_hiddens)
u = torch.tanh(torch.matmul(outputs, self.w_omega))
# (batch_size, seq_len)
att = torch.matmul(u, self.u_omega).squeeze()
# add mask
att = att.masked_fill(mask == 0, -1e10)
# (batch_size, seq_len,1)
att_score = F.softmax(att, dim=1).unsqueeze(2)
# normalization attention weight
# (batch_size, seq_len, 2 * num_hiddens)
scored_outputs = outputs * att_score
# weighted sum as output
# (batch_size, 2 * num_hiddens)
out = torch.sum(scored_outputs, dim=1)
return out


class ST_LSTM(nn.Module)
posted @ 2025-05-07 14:32  才品  阅读(36)  评论(0)    收藏  举报