Skip to content

Conversation

@gabrielbosse1
Copy link

Esse pull request adiciona a policy act-language

@gabrielbosse1 gabrielbosse1 added the enhancement New feature or request label Mar 24, 2025
@gabrielbosse1 gabrielbosse1 self-assigned this Mar 24, 2025
@thecodergus
Copy link

thecodergus commented Apr 2, 2025

Achei muito massa que você usou do type system do python, ajuda muito na hora de fazer manutenções.

Revi o código e anotei possíveis melhorias:

1. Uso correto do decorador torch.no_grad

  • Uso correto é chamando a função como decorador:
@torch.no_grad()
def some_fn() -> Tensor:
    pass

2. Uso correto do Type System

  • Usar union int | None é incorreto para os casos quando uma variável pode ter alguma coisa ou nada.

  • Correto é usar typing.Optional, como no exemplo abaixo:

from typing import Optional

variavel: Optional[int] = None
  • Explicação: Optional[int] é mais claro e comunica melhor a intenção: "esta variável normalmente é um inteiro, mas pode estar ausente". Além disso, funciona em versões mais antigas do Python.

3. Docstrings padronizadas nos métodos

def process_data(self, data: list[float], normalize: bool = True) -> np.ndarray:
    """Processa e transforma dados de entrada em um formato padronizado.
    
    Args:
        data: Lista de valores numéricos para processamento.
        normalize: Se True, normaliza os valores entre 0 e 1.
    
    Returns:
        Array NumPy contendo os dados processados.
        
    Raises:
        ValueError: Se a lista de entrada estiver vazia.
    """
    pass
  • Por que isso importa: Boas docstrings são como instruções de uso. Elas permitem que outros programadores (incluindo você no futuro) entendam rapidamente para que serve a função sem precisar ler todo o código.

4. Nomes de variáveis auto-explicativos

  • Exemplo ruim:
q = k = x if pos_embed is None else x + pos_embed
  • Exemplo melhor:
query = key = input_tensor if pos_embed is None else input_tensor + pos_embed
  • Explicação: Nomes claros são como etiquetas em uma caixa de ferramentas. Se você escrever apenas "F" na caixa, precisará abri-la para descobrir o que tem dentro. Com nomes descritivos, você sabe o conteúdo sem precisar "abrir a caixa".

5. Evitar código repetitivo (princípio DRY - Don't Repeat Yourself)

  • Exemplo com repetição:
if self.pre_norm:
    x = self.norm1(x)
    # código...
else:
    # código...
    if not self.pre_norm:
        x = self.norm2(x)		
  • Exemplo refatorado:
def _apply_normalization(self, x: Tensor, norm_layer, pre_norm: bool) -> Tensor:
    if pre_norm:
        return norm_layer(x)
    return x
    
def _apply_post_normalization(self, x: Tensor, norm_layer, pre_norm: bool) -> Tensor:
    if not pre_norm:
        return norm_layer(x)
    return x
  • Explicação: Código repetido é como copiar e colar um texto - se você encontrar um erro, precisará corrigir em todos os lugares. Extraindo para funções, você corrige em um só lugar!

6. Funções Focadas: Uma Responsabilidade por Vez

  • Problema: Métodos como forward() acumulam múltiplas responsabilidades, tornando o código difícil de manter e testar.

  • Cada função deve fazer apenas uma coisa e fazê-la bem (Princípio da Responsabilidade Única).

# Antes: Método excessivamente longo com múltiplas responsabilidades
def forward(self, x: Tensor, encoder_out: Tensor, decoder_pos_embed: Optional[Tensor] = None, 
            encoder_pos_embed: Optional[Tensor] = None) -> Tensor:
    # 30+ linhas de código realizando self-attention, cross-attention, normalização e feed-forward
    # ...
    return x
  • Refatoração para funções menores e específicas:
def forward(self, x: Tensor, encoder_out: Tensor, decoder_pos_embed: Optional[Tensor] = None, 
            encoder_pos_embed: Optional[Tensor] = None) -> Tensor:
    """Processa a entrada através do bloco decoder.
    
    Args:
        x: Tensor de entrada.
        encoder_out: Saída do encoder.
        decoder_pos_embed: Embedding posicional opcional para o decoder.
        encoder_pos_embed: Embedding posicional opcional para o encoder.
        
    Returns:
        Tensor processado.
    """
    x = self._apply_self_attention(x, decoder_pos_embed)
    x = self._apply_cross_attention(x, encoder_out, encoder_pos_embed)
    return self._apply_feed_forward(x)

def _apply_self_attention(self, x: Tensor, pos_embed: Optional[Tensor] = None) -> Tensor:
    """Aplica mecanismo de self-attention."""
    # 8-10 linhas específicas para self-attention
    return x
    
def _apply_cross_attention(self, x: Tensor, encoder_out: Tensor, 
                          pos_embed: Optional[Tensor] = None) -> Tensor:
    """Aplica mecanismo de cross-attention entre decoder e encoder."""
    # 8-10 linhas específicas para cross-attention
    return x
    
def _apply_feed_forward(self, x: Tensor) -> Tensor:
    """Aplica rede feed-forward."""
    # 5-8 linhas específicas para feed-forward
    return x
  • Explicação: Funções grandes são como instruções de montagem de móveis com 100 passos em um único parágrafo. Dividir em funções menores é como organizar essas instruções em etapas claras e numeradas - muito mais fácil de seguir!

  • Benefícios: código mais legível, testável, reutilizável e mais fácil de depurar. Cada função pequena pode ser testada individualmente.

@gabrielbosse1
Copy link
Author

Eu estou terminando de melhorar o código nesses pontos, mas encontrei alguns problemas quando rodo as simulações como pusht, e vou tentar resolvê-los antes de fazer outro commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants