Image Segmentation
Transformers
PyTorch
repcontur
feature-extraction
medical
radiology
ct
3d
tumor-segmentation
referring-segmentation
report-generation
visual-question-answering
custom_code
Instructions to use Oncosoft-Research/RepConTUR with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Oncosoft-Research/RepConTUR with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-segmentation", model="Oncosoft-Research/RepConTUR", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Oncosoft-Research/RepConTUR", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download attention.py from Oncosoft-Research/RepConTUR: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/Oncosoft-Research/RepConTUR/resolve/main/attention.py
- Command line
-
hf download hf://Oncosoft-Research/RepConTUR/attention.py
-
curl -L -o attention.py https://huggingface.co/Oncosoft-Research/RepConTUR/resolve/main/attention.py
10.6 kB
| import math | |
| import torch | |
| import torch.nn.functional as F | |
| from torch import nn, einsum | |
| from beartype import beartype | |
| from typing import Tuple | |
| from einops import rearrange, repeat | |
| # helpers | |
| def exists(val): | |
| return val is not None | |
| def default(val, d): | |
| return val if exists(val) else d | |
| def leaky_relu(p = 0.1): | |
| return nn.LeakyReLU(p) | |
| def l2norm(t): | |
| return F.normalize(t, dim = -1) | |
| # bias-less layernorm, being used in more recent T5s, PaLM, also in @borisdayma 's experiments shared with me | |
| # greater stability | |
| class LayerNorm(nn.Module): | |
| def __init__(self, dim): | |
| super().__init__() | |
| self.gamma = nn.Parameter(torch.ones(dim)) | |
| self.register_buffer("beta", torch.zeros(dim)) | |
| def forward(self, x): | |
| return F.layer_norm(x, x.shape[-1:], | |
| self.gamma.to(x.dtype), self.beta.to(x.dtype)) | |
| # feedforward | |
| class GEGLU(nn.Module): | |
| def forward(self, x): | |
| x, gate = x.chunk(2, dim = -1) | |
| return F.gelu(gate) * x | |
| def FeedForward(dim, mult = 4, dropout = 0.): | |
| inner_dim = int(mult * (2 / 3) * dim) | |
| return nn.Sequential( | |
| nn.LayerNorm(dim), | |
| nn.Linear(dim, inner_dim * 2, bias = False), | |
| GEGLU(), | |
| nn.Dropout(dropout), | |
| nn.Linear(inner_dim, dim, bias = False) | |
| ) | |
| # PEG - position generating module | |
| class PEG(nn.Module): | |
| def __init__(self, dim, causal = False): | |
| super().__init__() | |
| self.causal = causal | |
| self.dsconv = nn.Conv3d(dim, dim, 3, groups = dim) | |
| def forward(self, x, shape: Tuple[int, int, int, int] = None): | |
| needs_shape = x.ndim == 3 | |
| assert not (needs_shape and not exists(shape)) | |
| orig_shape = x.shape | |
| if needs_shape: | |
| x = x.reshape(*shape, -1) | |
| x = rearrange(x, 'b ... d -> b d ...') | |
| frame_padding = (2, 0) if self.causal else (1, 1) | |
| x = F.pad(x, (1, 1, 1, 1, *frame_padding), value = 0.) | |
| x = self.dsconv(x) | |
| x = rearrange(x, 'b d ... -> b ... d') | |
| if needs_shape: | |
| x = rearrange(x, 'b ... d -> b (...) d') | |
| return x.reshape(orig_shape) | |
| # attention | |
| class Attention(nn.Module): | |
| def __init__( | |
| self, | |
| dim, | |
| dim_context = None, | |
| dim_head = 64, | |
| heads = 8, | |
| causal = False, | |
| num_null_kv = 0, | |
| norm_context = True, | |
| dropout = 0., | |
| scale = 8 | |
| ): | |
| super().__init__() | |
| self.heads = heads | |
| self.causal = causal | |
| self.scale = scale | |
| inner_dim = dim_head * heads | |
| dim_context = default(dim_context, dim) | |
| if causal: | |
| self.rel_pos_bias = AlibiPositionalBias(heads = heads) | |
| self.attn_dropout = nn.Dropout(dropout) | |
| self.norm = LayerNorm(dim) | |
| self.context_norm = LayerNorm(dim_context) if norm_context else nn.Identity() | |
| self.num_null_kv = num_null_kv | |
| # Only create null_kv parameter if num_null_kv > 0 | |
| # Zero-element parameters cause DeepSpeed ZeRO partitioning issues | |
| if num_null_kv > 0: | |
| self.null_kv = nn.Parameter(torch.randn(heads, 2 * num_null_kv, dim_head)) | |
| else: | |
| self.register_buffer('null_kv', None) | |
| self.to_q = nn.Linear(dim, inner_dim, bias = False) | |
| self.to_kv = nn.Linear(dim_context, inner_dim * 2, bias = False) | |
| self.q_scale = nn.Parameter(torch.ones(dim_head)) | |
| self.k_scale = nn.Parameter(torch.ones(dim_head)) | |
| self.to_out = nn.Linear(inner_dim, dim, bias = False) | |
| def forward( | |
| self, | |
| x, | |
| mask = None, | |
| context = None, | |
| attn_bias = None | |
| ): | |
| batch, device, dtype = x.shape[0], x.device, x.dtype | |
| device=torch.device('cuda') | |
| if exists(context): | |
| context = self.context_norm(context) | |
| kv_input = default(context, x) | |
| x = self.norm(x) | |
| q, k, v = self.to_q(x), *self.to_kv(kv_input).chunk(2, dim = -1) | |
| q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = self.heads), (q, k, v)) | |
| # Only add null key-values if they exist | |
| if self.null_kv is not None: | |
| nk, nv = repeat(self.null_kv, 'h (n r) d -> b h n r d', b = batch, r = 2).unbind(dim = -2) | |
| k = torch.cat((nk, k), dim = -2) | |
| v = torch.cat((nv, v), dim = -2) | |
| q, k = map(l2norm, (q, k)) | |
| q = q * self.q_scale | |
| k = k * self.k_scale | |
| sim = einsum('b h i d, b h j d -> b h i j', q, k) * self.scale | |
| i, j = sim.shape[-2:] | |
| if exists(attn_bias): | |
| attn_bias = F.pad(attn_bias, (self.num_null_kv, 0), value = 0.) | |
| sim = sim + attn_bias | |
| if exists(mask): | |
| mask = F.pad(mask, (self.num_null_kv, 0), value = True) | |
| mask = rearrange(mask, 'b j -> b 1 1 j') | |
| sim = sim.masked_fill(~mask, -torch.finfo(sim.dtype).max) | |
| if self.causal: | |
| sim = sim + self.rel_pos_bias(sim) | |
| device=torch.device('cuda') | |
| causal_mask = torch.ones((i, j), device = device, dtype = torch.bool).triu(j - i + 1) | |
| sim = sim.masked_fill(causal_mask, -torch.finfo(sim.dtype).max) | |
| attn = sim.softmax(dim = -1) | |
| attn = self.attn_dropout(attn) | |
| out = einsum('b h i j, b h j d -> b h i d', attn, v) | |
| out = rearrange(out, 'b h n d -> b n (h d)') | |
| return self.to_out(out) | |
| # alibi positional bias for extrapolation | |
| class AlibiPositionalBias(nn.Module): | |
| def __init__(self, heads): | |
| super().__init__() | |
| self.heads = heads | |
| slopes = torch.Tensor(self._get_slopes(heads)) | |
| slopes = rearrange(slopes, 'h -> h 1 1') | |
| self.register_buffer('slopes', slopes, persistent = False) | |
| self.register_buffer('bias', None, persistent = False) | |
| def get_bias(self, i, j, device): | |
| device=torch.device('cuda') | |
| i_arange = torch.arange(j - i, j, device = device) | |
| j_arange = torch.arange(j, device = device) | |
| bias = -torch.abs(rearrange(j_arange, 'j -> 1 1 j') - rearrange(i_arange, 'i -> 1 i 1')) | |
| return bias | |
| def _get_slopes(heads): | |
| def get_slopes_power_of_2(n): | |
| start = (2**(-2**-(math.log2(n)-3))) | |
| ratio = start | |
| return [start*ratio**i for i in range(n)] | |
| if math.log2(heads).is_integer(): | |
| return get_slopes_power_of_2(heads) | |
| closest_power_of_2 = 2 ** math.floor(math.log2(heads)) | |
| return get_slopes_power_of_2(closest_power_of_2) + get_slopes_power_of_2(2 * closest_power_of_2)[0::2][:heads-closest_power_of_2] | |
| def forward(self, sim): | |
| h, i, j, device = *sim.shape[-3:], sim.device | |
| if exists(self.bias) and self.bias.shape[-1] >= j: | |
| return self.bias[..., :i, :j] | |
| device=torch.device('cuda') | |
| bias = self.get_bias(i, j, device) | |
| bias = bias * self.slopes | |
| num_heads_unalibied = h - bias.shape[0] | |
| bias = F.pad(bias, (0, 0, 0, 0, 0, num_heads_unalibied)) | |
| self.register_buffer('bias', bias, persistent = False) | |
| return self.bias | |
| class ContinuousPositionBias(nn.Module): | |
| """ from https://arxiv.org/abs/2111.09883 """ | |
| def __init__( | |
| self, | |
| *, | |
| dim, | |
| heads, | |
| num_dims = 2, # 2 for images, 3 for video | |
| layers = 2, | |
| log_dist = True, | |
| cache_rel_pos = False | |
| ): | |
| super().__init__() | |
| self.num_dims = num_dims | |
| self.log_dist = log_dist | |
| self.net = nn.ModuleList([]) | |
| self.net.append(nn.Sequential(nn.Linear(self.num_dims, dim), leaky_relu())) | |
| for _ in range(layers - 1): | |
| self.net.append(nn.Sequential(nn.Linear(dim, dim), leaky_relu())) | |
| self.net.append(nn.Linear(dim, heads)) | |
| self.cache_rel_pos = cache_rel_pos | |
| self.register_buffer('rel_pos', None, persistent = False) | |
| def forward(self, *dimensions, device = torch.device('cpu')): | |
| if not exists(self.rel_pos) or not self.cache_rel_pos: | |
| device=torch.device('cuda') | |
| positions = [torch.arange(d, device = device) for d in dimensions] | |
| grid = torch.stack(torch.meshgrid(*positions, indexing = 'ij')) | |
| grid = rearrange(grid, 'c ... -> (...) c') | |
| rel_pos = rearrange(grid, 'i c -> i 1 c') - rearrange(grid, 'j c -> 1 j c') | |
| if self.log_dist: | |
| rel_pos = torch.sign(rel_pos) * torch.log(rel_pos.abs() + 1) | |
| self.register_buffer('rel_pos', rel_pos, persistent = False) | |
| # Get the dtype of the model weights for consistent computation | |
| target_dtype = self.net[0][0].weight.dtype if len(self.net) > 0 else torch.float32 | |
| rel_pos = self.rel_pos.to(target_dtype) | |
| for layer in self.net: | |
| rel_pos = layer(rel_pos) | |
| return rearrange(rel_pos, 'i j h -> h i j') | |
| # transformer | |
| class Transformer(nn.Module): | |
| def __init__( | |
| self, | |
| dim, | |
| *, | |
| depth, | |
| dim_context = None, | |
| causal = False, | |
| dim_head = 64, | |
| heads = 8, | |
| ff_mult = 4, | |
| peg = False, | |
| peg_causal = False, | |
| attn_num_null_kv = 2, | |
| has_cross_attn = False, | |
| attn_dropout = 0., | |
| ff_dropout = 0. | |
| ): | |
| super().__init__() | |
| self.layers = nn.ModuleList([]) | |
| for _ in range(depth): | |
| self.layers.append(nn.ModuleList([ | |
| PEG(dim = dim, causal = peg_causal) if peg else None, | |
| Attention(dim = dim, dim_head = dim_head, heads = heads, causal = causal, dropout = attn_dropout), | |
| Attention(dim = dim, dim_head = dim_head, dim_context = dim_context, heads = heads, causal = False, num_null_kv = attn_num_null_kv, dropout = attn_dropout) if has_cross_attn else None, | |
| FeedForward(dim = dim, mult = ff_mult, dropout = ff_dropout) | |
| ])) | |
| self.norm_out = LayerNorm(dim) | |
| def forward( | |
| self, | |
| x, | |
| video_shape: Tuple[int, int, int, int] = None, | |
| attn_bias = None, | |
| context = None, | |
| self_attn_mask = None, | |
| cross_attn_context_mask = None | |
| ): | |
| for peg, self_attn, cross_attn, ff in self.layers: | |
| if exists(peg): | |
| x = peg(x, shape = video_shape) + x | |
| x = self_attn(x, attn_bias = attn_bias, mask = self_attn_mask) + x | |
| if exists(cross_attn) and exists(context): | |
| x = cross_attn(x, context = context, mask = cross_attn_context_mask) + x | |
| x = ff(x) + x | |
| return self.norm_out(x) | |