qic999's picture
Upload folder using huggingface_hub
28e6f98 verified
Raw
History Blame Contribute Delete
5.64 kB
import math
from collections import deque
import numpy as np
import torch
from torch import nn
import torch.nn.functional as F
from torchvision import models
class SelfAttention(nn.Module):
"""
A vanilla multi-head masked self-attention layer with a projection at the end.
"""
def __init__(self, n_embd, n_head, attn_pdrop, resid_pdrop):
super().__init__()
assert n_embd % n_head == 0
# key, query, value projections for all heads
self.key = nn.Linear(n_embd, n_embd)
self.query = nn.Linear(n_embd, n_embd)
self.value = nn.Linear(n_embd, n_embd)
# regularization
self.attn_drop = nn.Dropout(attn_pdrop)
self.resid_drop = nn.Dropout(resid_pdrop)
# output projection
self.proj = nn.Linear(n_embd, n_embd)
self.n_head = n_head
def forward(self, x):
B, T, C = x.size()
# calculate query, key, values for all heads in batch and move head forward to be the batch dim
k = self.key(x).view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
q = self.query(x).view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
v = self.value(x).view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
# self-attend: (B, nh, T, hs) x (B, nh, hs, T) -> (B, nh, T, T)
att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))
att = F.softmax(att, dim=-1)
att = self.attn_drop(att)
y = att @ v # (B, nh, T, T) x (B, nh, T, hs) -> (B, nh, T, hs)
y = y.transpose(1, 2).contiguous().view(B, T, C) # re-assemble all head outputs side by side
# output projection
y = self.resid_drop(self.proj(y))
return y
class Block(nn.Module):
""" an unassuming Transformer block """
def __init__(self, n_embd, n_head, block_exp, attn_pdrop, resid_pdrop):
super().__init__()
self.ln1 = nn.LayerNorm(n_embd)
self.ln2 = nn.LayerNorm(n_embd)
self.attn = SelfAttention(n_embd, n_head, attn_pdrop, resid_pdrop)
self.mlp = nn.Sequential(
nn.Linear(n_embd, block_exp * n_embd),
nn.ReLU(True), # changed from GELU
nn.Linear(block_exp * n_embd, n_embd),
nn.Dropout(resid_pdrop),
)
def forward(self, x):
B, T, C = x.size()
x = x + self.attn(self.ln1(x))
x = x + self.mlp(self.ln2(x))
return x
class TransFuse_layer(nn.Module):
""" the full GPT language model, with a context size of block_size """
def __init__(self, n_embd, n_head, block_exp, n_layer,
num_anchors, seq_len=1,
embd_pdrop=0.1, attn_pdrop=0.1, resid_pdrop=0.1):
super().__init__()
self.n_embd = n_embd
self.seq_len = seq_len
self.vert_anchors = num_anchors
self.horz_anchors = num_anchors
# positional embedding parameter (learnable), image + lidar
self.pos_emb = nn.Parameter(torch.zeros(1, 2 * seq_len * self.vert_anchors * self.horz_anchors, n_embd))
self.drop = nn.Dropout(embd_pdrop)
# transformer
self.blocks = nn.Sequential(*[Block(n_embd, n_head,
block_exp, attn_pdrop, resid_pdrop)
for layer in range(n_layer)])
# decoder head
self.ln_f = nn.LayerNorm(n_embd)
self.block_size = seq_len
self.apply(self._init_weights)
def get_block_size(self):
return self.block_size
def _init_weights(self, module):
if isinstance(module, nn.Linear):
module.weight.data.normal_(mean=0.0, std=0.02)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.LayerNorm):
module.bias.data.zero_()
module.weight.data.fill_(1.0)
def forward(self, m1, m2):
"""
Args:
m1 (tensor): B*seq_len, C, H, W
m2 (tensor): B*seq_len, C, H, W
"""
bz = m2.shape[0] // self.seq_len
h, w = m2.shape[2:4]
# forward the image model for token embeddings
m1 = m1.view(bz, self.seq_len, -1, h, w)
m2 = m2.view(bz, self.seq_len, -1, h, w)
# pad token embeddings along number of tokens dimension
token_embeddings = torch.cat([m1, m2], dim=1).permute(0,1,3,4,2).contiguous()
token_embeddings = token_embeddings.view(bz, -1, self.n_embd) # (B, an * T, C)
# add (learnable) positional embedding for all tokens
x = self.drop(self.pos_emb + token_embeddings) # (B, an * T, C)
x = self.blocks(x) # (B, an * T, C)
x = self.ln_f(x) # (B, an * T, C)
x = x.view(bz, 2 * self.seq_len, self.vert_anchors, self.horz_anchors, self.n_embd)
x = x.permute(0,1,4,2,3).contiguous() # same as token_embeddings
m1_out = x[:, :self.seq_len, :, :, :].contiguous().view(bz * self.seq_len, -1, h, w)
m2_out = x[:, self.seq_len:, :, :, :].contiguous().view(bz * self.seq_len, -1, h, w)
print("modality1 output:", m1_out.max(), m1_out.min())
print("modality2 output:", m2_out.max(), m2_out.min())
return m1_out, m2_out
if __name__ == "__main__":
feature1 = torch.randn((4, 512, 20, 20))
feature2 = torch.randn((4, 512, 20, 20))
model = TransFuse_layer(n_embd=512, n_head=4, block_exp=4, n_layer=8, num_anchors=20, seq_len=1)
print("TransFuse_layer:", model)
feat1, feat2 = model(feature1, feature2)
print(feat1.shape, feat2.shape)