Detecção de Patologias a Partir de Radiografias, via Rede Neural Artificial - 01
Tags: python, machinelearning
Published: 2020-04-12 01:36:22

Detecção de doenças pulmonares a partir de radiografias de tórax, via rede neural artificial convolucional. Classificador multiclasse TensorFlow / Keras.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1s1th7t86j8uehafygde.jpeg)

A partir do momento em que estamos buscando resolver algum tipo de problema computacional por meio de redes neurais artificiais, é de suma importância definirmos exatamente que tipo de problema estamos trabalhando, para escolhermos corretamente as ferramentas que serão utilizadas, assim como o modelo de rede neural que melhor se adapta para aquele fim. Uma vez que uma rede neural é um modelo estrutural de processamento de dados visando encontrar padrões e aprender a partir dos mesmos..

É bastante comum termos modelos específicos de redes neurais artificiais que realizam todo tipo de classificação, um desses modelos, chamado usualmente de rede neural convolucional, é um modelo especializado em resolver problemas de classificação a partir de imagens. Nesse sentido, existe toda uma área em machine learning e deep learning dedicada a realizar o processo chamado de convolução, onde as imagens, dadas as suas características de composição através de pixels e suas matrizes de cores, são convertidas para matrizes numéricas que por sua vez irão compor camadas de neurônios artificiais da rede neural para cruzamento dos dados.

Uma vez realizadas as devidas conversões, pixel a pixel, para arrays de um dataframe, é possível treinar uma rede neural artificial para que encontre padrões específicos e característicos de uma imagem a fim de classificar a mesma quanto a sua forma.

A nível de rede neural artificial convolucional, podemos, utilizando de conceitos de machine learning, treinar uma rede para que diferencie, por exemplo, diferentes animais entre si, diferentes objetos quanto ao seu formato, diferentes pessoas quanto às suas características únicas que compõe seu rosto, e, como será exemplificado neste capítulo, diferenciar a partir de exames de imagem, com uma precisão muito maior do que a de um médico especialista, características de apresentação de uma anatomia normal ou patológica..

O exemplo que veremos trata justamente desse tipo de classificação, realizado via rede neural artificial convolucional. A área da radiologia, também conhecida como diagnóstico por imagem, é o ramo da medicina onde por meio de exames como ultrassonografia, raios-x, tomografia computadorizada, ressonância magnética, cintilografia, entre outros exames, conseguimos obter imagens fidedignas da anatomia para que sejam feitos os devidos estudos em busca de quaisquer tipo de alteração morfológica, fisiológica ou funcional. Nesta área em particular, além dos equipamentos distintos para cada tipo de exame, existe toda uma equipe multidisciplinar composta por técnicos e médicos radiologistas.

O médico radiologista, profissional este que se dedica exclusivamente a interpretar exames de imagem, possui formação médica somada a uma especialização que o treina a identificar características bastante minuciosas, como a diferença de densidade ou de atividade metabólica entre tecidos. O mesmo, com base em seu conhecimento da anatomia normal assim como a experiência em clínica médica, identifica em exames de imagem características que possam apresentar alterações da anatomia indicando patologias. O ponto a se destacar é que, por melhor e mais experiente que este tipo de profissional seja, ele possui devido as suas limitações como ser humano, uma margem de erro a ser considerada em cada interpretação de exame.

É nesse momento que a coisa começa a ficar interessante, no sentido de que conseguimos elaborar e treinar uma rede neural artificial para que, a partir de uma base de dados previamente usada para aprendizado de máquina, possa realizar o processamento de novas imagens com nível de precisão maior do que a do próprio médico radiologista. Tenha em mente que toda subdivisão da área de inteligência artificial vem a somar, e muito, em várias áreas onde as mesmas estão sendo aplicadas, não longe disso, a área da medicina tem obtido bons e significativos progressos graças à usabilidade destas tecnologias e ferramentas. Tal tipo de tecnologia não visa substituir nenhum profissional desta área, mas servir como uma ferramenta que fornece um segundo viés de confirmação, para que sejam emitidos laudos mais precisos, e consequentemente tratamentos mais eficazes para os pacientes.

Nas páginas seguintes, estaremos elaborando e criando passo a passo, uma rede neural artificial convolucional dedicada a processar e interpretar radiografias de tórax, onde a anatomia principal demonstrada são os pulmões e a região do mediastino da caixa torácica, em busca de alguma patologia do trato respiratório como pneumonia, tuberculose e derrame pleural. Para isso, usaremos da linguagem Python assim como duas de suas mais importantes bibliotecas para estruturação de redes neurais densas chamadas TensorFlow e Keras.

Uma das características interessantes da biblioteca Keras é o fato da mesma, ter capacidade de criar redes neurais convolucionais partindo de amostras de imagens. Diferente de outros modelos onde é necessário aprendizado supervisionado, ou por reforço, ou conciliando labels sobre as imagens para que destaquem suas características…, a biblioteca Keras por meio de suas funções internas consegue fazer classificação de dois ou mais tipos de imagens simplesmente as separando em pastas de acordo com o seu tipo, convertendo tais tipos de dados para arrays que irão compor camadas de uma rede neural e passar por uma série de funções para os devidos reconhecimentos de padrões a partir destas imagens.

O que faremos, etapa por etapa, é a identificação do tipo de problema computacional, neste caso uma classificação “multiclasse” a partir de imagens, posteriormente preparar uma base de dados a ser utilizada e dando sequência teremos de fato a codificação da estrutura da rede neural artificial e por fim teremos um modelo treinado para realização de testes a partir do mesmo.

Temos um problema computacional idealizado, hora de estruturar o mesmo de forma lógica para que possamos construir um modelo. Para realizarmos a classificação a partir de radiografias de tórax, temos de preparar uma base de dados com imagens que serão processadas para o treinamento de nossa rede neural artificial convolucional. Para isso, podemos buscar datasets públicos de radiografias de tórax ou montar nossa própria base de dados, reunindo imagens separadas quanto às suas características. Nesse caso, é preciso construir uma base composta de imagens de exames sem alterações, e com as respectivas patologias separadas quanto ao seu tipo.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fxfu2ptuzg8zd1ez6g2g.jpeg)
Imagem 01 — Estrutura de pastas para as amostras separando-as quanto ao seu tipo.

Ao todo, montamos uma base com apenas 674 imagens com as respectivas características de um exame “normal” ou apresentando algum tipo de patologia (pneumonia, derrame pleural e tuberculose), separados entre si. Importante salientar que assim como toda rede neural artificial, muito da eficiência de nossa rede em seu processo de aprendizado de máquina está diretamente ligado a base de dados usada para esse processo. Principalmente no que se refere a classificação a partir de imagens, uma base de dados mais robusta, com maior número de amostras (dependendo o caso, milhares ou até mesmo milhões de amostras), torna a eficiência de nossa rede neural muito maior.

Uma base de dados pequena pode impactar negativamente o processo de aprendizado por reforço, assim como uma base de dados muito volumosa, se não preparada da maneira correta, pode gerar ruídos no processo de aprendizado de máquina. Note que aqui, especificamente, estamos usando uma base de dados de imagens, onde todas são muito parecidas entre si, ao menos aos olhos de um leigo, todas essas radiografias possuem basicamente as mesmas características, como extensão da caixa torácica, dois pulmões, mediastino, imagens em preto e branco, resolução parecida, etc…, essas características, para esse relativo volume pequeno de amostras, será o suficiente para nosso modelo inicial mas em uma aplicação real o ideal seria utilizarmos de uma base de dados maior.

Base de dados pronta, com as devidas amostras separadas em pastas de acordo com seu tipo, assim como separadas em base de dados para treino e teste pela rede, podemos continuar nossa linha de raciocínio.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lzgfc06gynktbt53br58.jpeg)

Imagem 02 — Amostras de radiografias de tórax.

Para reforçar nosso entendimento, é interessante por hora entendermos o processo de convolução de uma imagem. O processo de conversão de uma imagem em toda sua forma e estrutura, para uma matriz numérica que alimentará perceptrons de camadas de nossa rede neural artificial convolucional é um processo dividido em várias etapas.

Inicialmente teremos uma imagem fonte, com uma determinada resolução dependendo o tipo de exame, que é convertida para preto e branco caso seja originalmente colorida, em seguida a imagem é mapeada e dividida em blocos menores, onde cada bloco será novamente mapeado em busca de características únicas e cada etapa desse mapeamento é indexada internamente como mapas de características. Na sequência, esse mapeamento inicial é replicado e novamente convertido em mapas indexados internamente, agora com as características de cada pixel, de cada bloco, de cada mapa, de cada posição da imagem original. Dando prosseguimento, cada mapa será escalonado e indexado algumas vezes até que por fim essas conversões resultarão em uma matriz de indexação com apenas uma coluna de dados numéricos. Essa coluna por sua vez, será normalizada em uma escala de 0 a 1 e dividida de forma que cada valor de cada linha da mesma se tornará um neurônio da camada de entrada na rede neural artificial. *Cada uma das imagens de nossa base de dados passará por esse processo ao alimentar nossa rede neural.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3q5870wlryrzx3miyr9q.png)
Imagem 03 — Representação das etapas do processo de convolução.

Base de dados preparada, hora de partir para o código: Apenas lembrando que as bibliotecas TensorFlow e Keras não vem nativamente instaladas junto a sua distribuição do Python, porém a instalação das mesmas é facilmente realizada via pip (pip install tensorflow, pip install keras) ou via conda, já que estaremos trabalhando em um ambiente virtual criado para este fim (conda install tensorflow, conda install keras). Uma vez instaladas as bibliotecas, podemos abrir nossa IDE, nesse caso em particular estarei usando a Spyder, ambiente de desenvolvimento muito usado para computação científica principalmente em função da sua maneira intuitiva de apresentar os dados das variáveis de forma visual, assim como a execução independente de cada bloco de código.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x0eor39ad576ae9syuu1.jpeg)
Imagem 04 — Ambiente da IDE Spyder.

Apenas fazendo uma pequena observação, ao abrir o Spyder não é necessário realizar nenhuma configuração, a não ser verificar se estamos usando o kernel correto uma vez que estamos trabalhando em um ambiente virtual isolado.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g42mcutg0ss0uajihfnf.jpeg)
Imagem 05 — Seleção do kernel a ser utilizado para a execução da rede neural

Note que neste caso estarei utilizando a biblioteca TensorFlow em sua versão 1.15, porém o código apresentado é totalmente compatível com as versões a partir da 2.0 da mesma.

Como sempre, o processo se dá iniciando com as importações das bibliotecas, módulos, pacotes e ferramentas que estaremos usando ao longo do código.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f83yckzsw048bi77fepp.jpeg)

Repare que, para fins de performance, importamos especificamente apenas os módulos das bibliotecas que de fato usaremos.

Sendo assim, inicialmente importamos do módulo layers da biblioteca Keras as funções empacotadas Conv2D e MaxPooling2D que respectivamente servirão para criar a estrutura de neurônios por camada assim como a conversão das matrizes para duas dimensões; Activation será responsável pela camada de ativação e suas funções de ativação aplicadas sobre os neurônios; Dropout que é uma ferramenta que aleatoriamente seleciona e remove neurônios das camadas intermediárias, como uma espécie de filtro, para que seja testado o processamento sem os devidos neurônios, assim como seu impacto na performance dos ajustes dos pesos; Flatten que basicamente é uma ferramenta que converterá a última camada de matriz bidimensional para unidimensional, e dessa forma, cada perceptron empilhado destes se tornará um neurônio da camada de entrada da estrutura densa da rede; Dense que por sua vez permitirá criar camadas de neurônios conectadas entre si de forma a permitir, entre outras operações, a retroalimentação da rede e todo seu processo de aprendizado de máquina por meio dos ajustes dos pesos entre camadas; Da mesma forma, do módulo preprocessing importamos image, pacote que permitirá operações diretamente sobre arquivos de imagem, também importamos ImageDataGenerator, que possibilitará gerar uma base de dados aumentada, com amostras geradas pela própria rede neural a partir da base de dados inicial, para que o processo de reconhecimento de padrões a partir de imagens diretamente seja mais eficiente, haja visto que como mencionado anteriormente, temos uma base de dados bastante pequena para esse exemplo. Também importamos do módulo models Sequential, que nos permitirá a criação de camadas de neurônios subsequentes e conectadas de forma sequencial entre si. Por fim da biblioteca Keras importamos backend que nada mais é do que um pacote de funções de entrada e de comunicação com outras funções que podem ser oriundas de outras bibliotecas. Encerrando esse processo importamos a biblioteca Numpy que permitirá a utilização de dados em forma de matrizes numéricas, assim como a aplicação de funções lógicas e aritméticas sobre este tipo de dado em particular.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tq8crr06dx46n3lbwvg3.jpeg)

Em seguida criamos as variáveis que instanciação nossas imagens por meio de seus diretórios. Para isso, criamos data_treino e data_teste com seus respectivos diretórios absolutos (no caso de execução deste código em outra IDE é perfeitamente possível a utilização dos caminhos relativos ‘dataset/train’ e ‘dataset/test’)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/lifbmko023ljp6qdo3z2.jpeg)

Na sequência criamos uma simples estrutura condicional que funcionará como uma estrutura de validação, pois na mesma estaremos realizando a conversão de formato da matriz gerada para que a mesma possa ser corretamente lida pela biblioteca Numpy e processada. Por meio da função image_data_format( ) simplesmente realizamos a verificação se os dados de entrada estão no formato aceito em ‘channels_first’, onde o primeiro formato (3, 150, 150) era lido pela biblioteca Keras usando o antigo núcleo Theano, e em versões mais recentes, a biblioteca Keras passou a ser incorporada ao TensorFlow e dessa forma tem de carregar as matrizes no formato aceito pelo núcleo TensorFlow, ou seja, (150, 150, 3).


DEVIDO AO LIMITE DE IMAGENS POR ARTIGO, CONTINUAMOS NA PARTE 2...