Olá, pessoal. Tudo bem? Espero que sim.

Conforme prometi, vou concluir a série de três publicações sobre como organizar o seu projeto de machine learning e deep learning com Pytorch. Eu demorei a escrever este último post porque eu tenho trabalhado na área de TinyML (https://www.plugandplaytechcenter.com/resources/tinyml-making-smart-devices-tinier-ever/) e otimização de modelos para dispositivos com recursos limitados (resource-constrained devices). Aprendi C++… e tem sido isso. E não: eu não sabia C++. Eu trabalhei mais de dez anos com C# (e eu gosto dela).

Ah! Lembrando que o código completo está aqui oh: https://github.com/adrianosantospb/estrutura_base_pytorch. Uma coisa que eu gostaria de enfatizar aqui: se voc realizar todas essas melhorias em seu projeto, você melhorará consideravelmente a acurácia do seu modelo.

Vamos lá. Eu prometi no post passado que falaria sobre:

a) Como utilizar GPU no treinamento do nosso modelo;

A primeira coisa que você deverá fazer é a instalação do pacote apropriado (com suporte ao CUDA). No momento em que eu escrevo este post, o comando para a instalacao eh o seguinte:

conda install pytorch torchvision torchaudio cudatoolkit=11.0 -c pytorch

Para que o nosso exemplo anterior utilize a GPU no processo de treinamento, precisamos, apenas, fazer pequenas modificações em nosso código. A primeira coisa que você deve fazer é verificar se existe GPU em seu computador. Se sim, basta que você modifique os seguintes trechos de códigos:

GPU :)

b) Alteraremos o nosso modelo para um modelo de CNN;

Com base na estrutura que criamos nos projetos anteriores, fica fácil criar um modelo de CNN. Na verdade, em termos de estrutura, não vai mudar nada! Incrível, não é mesmo? Claro que estamos criando uma arquitetura simples, “puramente didática”, e que existem diversas outras técnicas que podem ser inseridas em nosso modelo. Mas não será o nosso caso de agora, tudo bem?

A minha ideia aqui é fazer com que você tenha uma noção de continuidade. Isso mesmo: continuidade. Em nossos primeiros exemplos, nós trabalhamos com organização estrutural do projeto, criamos um modelo com base em uma rede simples e o testamos. Agora estamos entrando no contexto de CNN.

Se você ainda não é familiarizado com CNN, eu o aconselho a dar uma olhada aqui (https://medium.com/neuronio-br/entendendo-redes-convolucionais-cnns-d10359f21184) . Eu até pensei em escrever sobre elas, apresentar toda a teoria, mas eu encontrei esse material aí e achei que foi bem escrito, didático, e eu vou focar em coisas que não encontro de forma didática.

O nosso modelo terá três camadas CNN e duas fully connected layer (FC). Simples, simples, simples. Mas você verá que, para o domínio explorado neste exemplo, ela apresentará resultados mais interessantes do que os exemplos anteriores. Utilizaremos a função de ativação ReLU (https://machinelearningmastery.com/rectified-linear-activation-function-for-deep-learning-neural-networks/) e a função de regularização Dropout (https://machinelearningmastery.com/dropout-for-regularizing-deep-neural-networks/). Na saída da nossa rede (devido, inclusive, ao domínio de nossa aplicação), utilizaremos a função log_softmax (https://pytorch.org/docs/stable/generated/torch.nn.LogSoftmax.html).

Voilà! Este é o resultado de nossas alterações:

Nosso novo modelo.

c) Otimizaremos alguns parâmetros do PyTorch;

Bem, existem alguns pequenos detalhes na codificação que poderão nos ajudar em termos de desempenho. O primeiro passo nós já demos no momento em que começamos a usar o poder de processamento da GPU em nosso código. Você deve ter percebido, inclusive, que o tempo de execução do código (treinamento e validação) diminuiu bastante em nosso exemplo atual, comparando-o aos anteriores.

Vamos conhecer mais alguns:

Se você possui uma boa quantidade de memória em seu computador, você pode utilizar o recurso de workers. Sem dúvida você ganhará desempenho na etapa de treinamento do seu modelo. A proporção geralmente utilizada é de 4X o número de GPU do seu computador. Em termos de código, com Pytorch, você poderá utilizar esse recurso aqui:

Workers

O recurso de pinned_memory coloca automaticamente os tensores de dados buscados na memória fixada, fazendo com que a transferência de dados para a GPU seja mais rápida.

Em redes neurais, os cálculos são geralmente feitos em precisão de flutuantes (float) de 32 bits. Para reduzir o uso de memória foi pensada a abordagem de fazer a mesma coisa em meia-precisão (half), o que significa usar flutuadores de 16 bits com o uso de GPU. A ideia é simples: 16 ocupam metade do espaço na RAM que 32 e, em teoria, podem permitir o dobro do tamanho do seu modelo e o tamanho do lote. Porém existem alguns probleminhas com essa abordagem (https://en.wikipedia.org/wiki/Half-precision_floating-point_format) . Sendo assim, aconselha-se o uso de mixed precision training (https://pytorch.org/docs/stable/notes/amp_examples.html). Em nosso exemplo, eu apenas habilitei que o nosso modelo fosse treinado com precisão de 16. É um bom exercício melhorar esse processo, ok?

A ideia de executar paralelismo no processo de treinamento é algo que possibilita benefícios diretos em termos de treinamento. Porém isso funciona quando temos mais de uma GPU disponível. Pytorch implementa duas formas de implementacão DistributedDataParallel (https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html) e DataParallel (https://pytorch.org/docs/stable/generated/torch.nn.DataParallel.html). Correntemente, o uso do DataParallel é desencorajado.

Uma das atividades mais recorrentes no trabalho de modelos que utilizam GPU é a transferência de informações de GPU para CPU e de CPU para GPU. Essa operação é custosa e, a cada chamada de .item (), .cpu () ou .numpy (), realizamos a transferência da GPU para a CPU. Outra forma é quando criamos um array com numpy, por exemplo, e depois o transferimos para a GPU.

Idealmente, em termos de criação, a melhor alternativa é criar o array diretamente na GPU (a = torch.cuda.FloatTensor([1., 2.])). Quando tivermos que transferir o valor da GPU para a CPU, devemos utilizar a função .detach(). Esta função removerá quaisquer gráficos computacionais anexados a essa variável. Você poderá obter mais dicas aqui (https://medium.com/@attyuttam/5-gradient-derivative-related-pytorch-functions-8fd0e02f13c6).

d) Utilizando métricas de otimização para selecionarmos o melhor modelo.

Este tópico é de extrema importância. Inclusive, eu vou escrever um blog especificamente sobre este tema, incluindo algumas dicas práticas que eu desenvolvi no meu dia a dia como cientista de dados na área de visão computacional.

Porém, eu estava dando uma olhada sobre alguns materiais e encontrei duas fontes interessantes e ricas de informações sobre este tema; então, por agora, eu vou compartilhar esses dois links e deixo registrada a minha promessa de escrever sobre as dicas complementares a esses materiais, ok?

Os materiais são os seguintes:

a) O que não te contam sobre métricas de classificação binária: (https://medium.com/@arnaldog12/o-que-n%C3%A3o-te-contam-sobre-m%C3%A9tricas-de-classifica%C3%A7%C3%A3o-bin%C3%A1ria-d1834e385402);

b) Metrics for object detection: (https://github.com/rafaelpadilla/Object-Detection-Metrics)

Vale muito a pena a leitura desses materiais. Eu mesmo já os utilizei na preparação de aulas.

Bem, pessoal… eu acho que é isso. Tenho mais dois posts para compartilhar aqui ainda essa semana. Em breve novidades.

Abraço a todos

--

--

Senior Computer Vision Data Scientist at Conception Ro-Main (Quebec — CA). DSc in Computer Science. MTAC Brazil. https://github.com/adrianosantospb

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adriano A. Santos

Senior Computer Vision Data Scientist at Conception Ro-Main (Quebec — CA). DSc in Computer Science. MTAC Brazil. https://github.com/adrianosantospb