Tenbatsu24
add: missing files
a10ce46
Raw
History Blame Contribute Delete
3.31 kB
# References:
# https://github.com/facebookresearch/dino/blob/master/vision_transformer.py
# https://github.com/rwightman/pytorch-image-models/tree/master/timm/models/vision_transformer.py
import os
from torch import Tensor
from torch import nn
XFORMERS_ENABLED = os.environ.get("XFORMERS_DISABLED") is None
try:
if XFORMERS_ENABLED:
from xformers.ops import memory_efficient_attention, unbind
XFORMERS_AVAILABLE = True
else:
raise ImportError
except ImportError:
XFORMERS_AVAILABLE = False
class Attention(nn.Module):
def __init__(
self,
dim: int,
num_heads: int = 8,
qkv_bias: bool = False,
proj_bias: bool = True,
attn_drop: float = 0.0,
proj_drop: float = 0.0,
) -> None:
super().__init__()
self.num_heads = num_heads
head_dim = dim // num_heads
self.scale = head_dim**-0.5
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
self.attn_drop = nn.Dropout(attn_drop)
self.proj = nn.Linear(dim, dim, bias=proj_bias)
self.proj_drop = nn.Dropout(proj_drop)
def forward(self, x: Tensor, return_attn=False) -> Tensor:
"""
Adapted from https://gitlab.com/ziegleto-machine-learning/dino/-/tree/main/
"""
B, N, C = x.shape
qkv = (
self.qkv(x)
.reshape(B, N, 3, self.num_heads, C // self.num_heads)
.permute(2, 0, 3, 1, 4)
)
q, k, v = qkv[0] * self.scale, qkv[1], qkv[2]
attn = q @ k.transpose(-2, -1)
attn = attn.softmax(dim=-1)
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
x = self.proj_drop(x)
# Adaptation for returing attentions
if return_attn:
return attn
return x
class MemEffAttention(Attention):
"""
Adapted from https://gitlab.com/ziegleto-machine-learning/dino/-/tree/main/
"""
def forward(self, x: Tensor, attn_bias=None, return_attn=False) -> Tensor:
if not XFORMERS_AVAILABLE:
assert attn_bias is None, "xFormers is required for nested tensors usage"
# Change this line
# return super().forward(x)
# Adaptation for returing attentions
return super().forward(x, return_attn)
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads)
q, k, v = unbind(qkv, 2)
x = memory_efficient_attention(q, k, v, attn_bias=attn_bias)
if return_attn:
# Support for XFORMERS to return attention
# Adapted from https://github.com/facebookresearch/dinov2/issues/90#issuecomment-1574001076
attn = x.permute(0, 2, 1, 3) @ v.permute(0, 2, 3, 1)
return attn
x = x.reshape([B, N, C])
x = self.proj(x)
x = self.proj_drop(x)
return x
if __name__ == "__main__":
import torch
_att = MemEffAttention(dim=32, num_heads=4).to("cuda")
print(_att(torch.randn(4, 16, 32, device="cuda"), return_attn=True).shape)
print(_att(torch.randn(4, 16, 32, device="cuda")).shape)