Vision-Transformer re-shaping the input

Mohamed_Farag: <p>Hi everyone,</p>
<p>I am using a pre-trained vision transformer from Pytorch available models. The question now, if I am using the pre-trained weights and I am applying the same transformations applied to the during training on Image-Net as an example, does is by nature do the reshaping of the input data?</p>
<pre><code class="lang-auto">pre_trained_weights = ViT_L_16_Weights.IMAGENET1K_V1

transforms = pre_trained_weights.transforms()
</code></pre>
<p>I mean something like this.</p>
<p>Thanks <img src="https://discuss.pytorch.org/images/emoji/apple/heart.png?v=12" title=":heart:" class="emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>

ptrblck: <p>Unsure, if I understand the question properly, but if you are wondering if the transformation contains a <code>Resize</code>, just print it.</p>

Mohamed_Farag: <p>Yeah, but not exactly. we need to do patching thing to make the data suitable for the transformer, is it done automatically?</p>

J_Johnson: <p>In a ViT model, the model takes in dimensions (batch_size, channels, height, width), just like any standard vision model.</p>

Mohamed_Farag: <p>Yeah, but I remember that we need to do the patching and the positional encoding thing with our hands right?<br>
I implemented the TransUnet architecture before, yet I don’t if the VIT in pytorch is doing it somehow, I was investigating the architecture and I found this conv-proj which was actually some CNN with specific kernel size and stride to do the reshaping thing. Also, I see your post taking about the “Stem” thing before. Can you just explain more what are the differences?</p>
<p>Is there positional encoding?</p>
<p>Thanks<br>
<img src="https://discuss.pytorch.org/images/emoji/apple/heart.png?v=12" title=":heart:" class="emoji only-emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>

J_Johnson: <p>A typical ViT in PyTorch will already handle patching the image. So the minimum input size will be specified with the model:</p>
<p><a href="https://pytorch.org/vision/main/models/generated/torchvision.models.vit_b_16.html#torchvision.models.vit_b_16" class="onebox" target="_blank" rel="noopener nofollow ugc">https://pytorch.org/vision/main/models/generated/torchvision.models.vit_b_16.html#torchvision.models.vit_b_16</a></p>
<p>The STEM just adds some additional conv2d layers in the front before the ViT. You might think of it as preparing the patches to be more easily “recognized” by the embedding layer.</p>

Mohamed_Farag: <p>what is more puzzling the positional encoding part, I can’t understand how is it happening?</p>
<pre><code class="lang-auto">class Encoder(nn.Module):
    """Transformer Model Encoder for sequence to sequence translation."""

    def __init__(
        self,
        seq_length: int,
        num_layers: int,
        num_heads: int,
        hidden_dim: int,
        mlp_dim: int,
        dropout: float,
        attention_dropout: float,
        norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
    ):
        super().__init__()
        # Note that batch_size is on the first dim because
        # we have batch_first=True in nn.MultiAttention() by default
        self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02))  # from BERT
        self.dropout = nn.Dropout(dropout)
        layers: OrderedDict[str, nn.Module] = OrderedDict()
        for i in range(num_layers):
            layers[f"encoder_layer_{i}"] = EncoderBlock(
                num_heads,
                hidden_dim,
                mlp_dim,
                dropout,
                attention_dropout,
                norm_layer,
            )
        self.layers = nn.Sequential(layers)
        self.ln = norm_layer(hidden_dim)

    def forward(self, input: torch.Tensor):
        torch._assert(input.dim() == 3, f"Expected (batch_size, seq_length, hidden_dim) got {input.shape}")
        input = input + self.pos_embedding
        return self.ln(self.layers(self.dropout(input)))
</code></pre>
<p>I can see what you are saying, I checked the implementation <code>self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02))</code>. Thanks a lot it was too interesting to have this talk!<img src="https://discuss.pytorch.org/images/emoji/apple/heart.png?v=12" title=":heart:" class="emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>
<p>And for the patchify stem is utilized for enhancing the transformer performance. Right?</p>

J_Johnson: <p>The embedding layer is just being initialized in the init, giving some random values before training begins. That is used to assign some position information to the transformer, such as first patch, second patch, etc. Similar to how a positional encoder is used in a language model.</p>
<p>STEM is a way to improve the accuracy of a ViT model, but requires additional training if added later.</p>

Mohamed_Farag: <pre><code class="lang-auto">lass Encoder(nn.Module):
    """Transformer Model Encoder for sequence to sequence translation."""

    def __init__(
        self,
        seq_length: int,
        num_layers: int,
        num_heads: int,
        hidden_dim: int,
        mlp_dim: int,
        dropout: float,
        attention_dropout: float,
        norm_layer: Callable[..., torch.nn.Module] = partial(nn.LayerNorm, eps=1e-6),
    ):
        super().__init__()
        # Note that batch_size is on the first dim because
        # we have batch_first=True in nn.MultiAttention() by default
        self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02))  # from BERT
        self.dropout = nn.Dropout(dropout)
        layers: OrderedDict[str, nn.Module] = OrderedDict()
        for i in range(num_layers):
            layers[f"encoder_layer_{i}"] = EncoderBlock(
                num_heads,
                hidden_dim,
                mlp_dim,
                dropout,
                attention_dropout,
                norm_layer,
            )
        self.layers = nn.Sequential(layers)
        self.ln = norm_layer(hidden_dim)

    def forward(self, input: torch.Tensor):
        torch._assert(input.dim() == 3, f"Expected (batch_size, seq_length, hidden_dim) got {input.shape}")
        input = input + self.pos_embedding
        return self.ln(self.layers(self.dropout(input)))
</code></pre>
<p>I can see what you are saying, I checked the implementation <code>self.pos_embedding = nn.Parameter(torch.empty(1, seq_length, hidden_dim).normal_(std=0.02))</code>. Thanks a lot it was too interesting to have this talk!<img src="https://discuss.pytorch.org/images/emoji/apple/heart.png?v=12" title=":heart:" class="emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>
<p>And for the patchify stem is utilized for enhancing the transformer performance. Right?</p>
<p>​​</p>
<p>​​</p>