discovery-unicamp / Minerva

Minerva is a framework for training machine learning models for researchers.
https://discovery-unicamp.github.io/Minerva/
MIT License
3 stars 7 forks source link

Transforms #6

Open GabrielBG0 opened 6 months ago

GabrielBG0 commented 6 months ago

Responsible for creating data augmentations

Features to be implemented

otavioon commented 6 months ago

Sugestão de API para Transformações

Ao criar uma API para transformações, é essencial considerar a utilização de padrões estabelecidos e bem-documentados. Neste caso, fiz uma busca sobre como implemetar transformações em alguns projetos do campo de visão computational, incluindo: MONAI, lightly, ClassyVision, MMCV (alicerce utilizdo pelo MMSegmentation e MMDetection) e nas recomendações do Pytorch.

Um ponto importante que vale ressaltar, visto em todos os projetos, é que as transformações são aplicadas a nível de amostra e não a nível de batch. Isso significa que a transformação é aplicada a cada amostra individualmente, e não a um batch de amostras ou no conjunto de dados como um todo.

Motivações para Utilizar APIs Conhecidas:

  1. Interoperabilidade: Ao aderir aos padrões sugeridos por projetos populares, como PyTorch, MONAI, lightly, ClassyVision e MMCV, garantimos que as transformações possam ser facilmente integradas em diferentes ecossistemas e frameworks.

  2. Documentação Abundante: Projetos amplamente utilizados tendem a oferecer documentação abrangente, o que simplifica o entendimento e a utilização das transformações por parte dos desenvolvedores.

  3. Comunidade Ativa: Ao alinhar-se com APIs conhecidas, beneficiamo-nos de uma comunidade ativa e engajada, facilitando a obtenção de suporte e contribuições externas.

Estrutura Comum de APIs de Transformações:

A estrutura básica da API de transformações pode seguir o padrão estabelecido pelo projeto PyTorch. Nela utiliza-se uma classe base abstrata que implementa o método __call__. Essa é mostrada abaixo:

class BaseTransform:
    def __call__(self, sample):
        raise NotImplementedError

Aqui, sample representa a entrada da transformação. Entretanto, o pytorch não especifica o tipo de entrada e saída, e isso pode levar a ambiguidades e dificuldades na utilização. sample pode ser um simples tensor, uma imagem, um dicionário ou qualquer outra estrutura de dados.

De fato, implementações em diferentes projetos podem variar em relação à estrutura e funcionalidade:

Assim, vale ressaltar que a estrutura da API de transformações pode variar de acordo com o projeto, mas é importante que ela seja clara e consistente em seu uso e na definição de seus subpacotes, para que os desenvolvedores possam utilizá-la de forma intuitiva, mas também para que seja fácil de integrar em diferentes ecossistemas e frameworks.

Desta forma, sugiro que a estrutura da API de transformações siga o padrão estabelecido pelo PyTorch, mas que os tipos de entrada e saída sejam especificados e que transformações as sejam aplicadas a nível de amostra e não a nível de batch. Desta forma, as transformações devem ser implementadas como classes, e não como funções, para que possam ser facilmente integradas em pipelines de transformações. Além disso, as transformações podem ser agrupaadas em subpacotes, de acordo com o tipo de entrada e saída/nicho, como, por exemplo, transforms.signal_1d, .transforms.spatial.

Definição Clara de Tipos

Para abordar esse problema, é fundamental fornecer uma definição clara dos tipos esperados na entrada e saída da transformação. O uso de anotações de tipo (Type Hints) na assinatura do método __call__ torna explícito o que a transformação espera e retorna.

from PIL import Image

def __call__(self, sample: Dict[str, Union[np.ndarray, Image.Image]]) -> Dict[str, Union[np.ndarray, np.ndarray]]:
    # ...

Aqui, Dict[str, Union[np.ndarray, np.ndarray]] indica que a entrada sample é um dicionário com chaves de string, contendo valores que podem ser np.ndarray ou qualquer subtipo compatível.

Considerações sobre Tipos Mistos

Em casos em que tipos mistos são comuns, como dicionários contendo diferentes tipos de dados, é essencial documentar claramente a estrutura esperada. Além disso, posteriormente, a API pode incluir verificações ou tratamentos condicionais para lidar com diferentes tipos de entrada.

GabrielBG0 commented 6 months ago

Nossa achei super legal, por mim é isso aí. A menos que o @fernandoGubiMarques tenha algo a complementar acho que a gente pode fechar esse estilo mesmo. Acho importante a gente ter uma definição de tipos pra todo o código, tipagem dinâmica é a receita pra problema mais pra frente.