top of page
  • João Ataide

Classificando imagens de radar de variações do tanque T-72


 

Um desafio bem interessante, são os trabalhos com os dados da Sensor Data Management System (SDMS) promovidos e disponibilizados pela Força Aérea Americana, neste caso utilizei os dados MSTAR /IU T-72 variants.


Os dados públicos aqui, em questão, são imagens de SAR (Radar de Abertura Sintética) e ISAR (Radar de Abertura Sintética Inversa), os sensores que produzem essas possuem vantagens quando a meteorologia, pois, suas ondas atravessam as nuvens possibilitando a obtenção das informações sem obstruir a visão sobre o alvo observado, o que se encaixa bem os alvos aqui providos que são as variações dos tanques de guerras T-72, que você pode saber mais nesse artigo da wikipedia.


No entanto, existem diversas variações, mas neste caso nos dados disponibilizados somente existem oito classes, como você pode ver abaixo:



Preparando ambiente


Para fazer o desafio precisei de poucas bibliotecas, basicamente do Arcpy, da API do ArcGIS, especificamente o módulo learn e por último importei a biblioteca pandas.


from arcgis.learn import *
import arcpy
import os
import json
import pandas as pd

Preparando dados


Primeiro passo para realizar um treinamento utilizando o ArcGIS é realizar a preparação dos dados, mas antes de executar a função de preparação foi necessário realizar ajustes na massa de dados fornecida pelo SDMS, para que essa fique no formato correto para o módulo interpretar.


Então como primeiro passo, foi necessário mover todas as pastas das classes de cada uma das rotações para a pasta raiz de imagens, posteriormente foi somente realizar o mapeamento do diretório de cada uma das imagens e criando o arquivo map.txt usando a função que criei abaixo, além disso, retirei da pasta de dados duas imagens as quais utilizarei para inferênciar o modelo sobre elas, testando a execução deste.


dir_images= "D:\T72Variants\images"
res = os.listdir(dir_images)
lista_string = []
for sample in res:
    for path in os.scandir(dir_images + "\\"+ sample):
        if path.is_file():
            if path.name.endswith(".JPG"):
                print( "images\\"+ sample + "\\" + path.name)
                lista_string.append("images\\"+ sample + "\\" + path.name)
with open('D:\T72Variants\map.txt', 'w') as f:
    for line in lista_string:
        f.write(f"{line}\n")


Depois desses passos, foi necessário realizar as alterações dos valores e nomes das classes das imagens, nos arquivos esri_accumulated_stats.json e esri_model_definition.emd.


file_esri_st = open('esri_accumulated_stats.json')
file_esri_def = open('esri_model_definition.emd')
esri_st = json.load(file_esri_st)
esri_def  = json.load(file_esri_def)

new_classes = {'Classes':[{'ClassValue': 1,'ClassName': 'A04'},
                          {'ClassValue': 2, 'ClassName': 'A05'},
                          {'ClassValue': 3, 'ClassName': 'A07'},
                          {'ClassValue': 4, 'ClassName': 'A10'},
                          {'ClassValue': 5, 'ClassName': 'A32'},
                          {'ClassValue': 6, 'ClassName': 'A62'},
                          {'ClassValue': 7, 'ClassName': 'A63'},
                          {'ClassValue': 8, 'ClassName': 'A64'}]}

esri_st.update(new_classes)
esri_def.update(new_classes)

with open('esri_accumulated_stats.json', "w") as outfile:
    json.dump(esri_st, outfile)
    
with open('esri_model_definition.emd', "w") as outfile:
    json.dump(esri_def, outfile)

E pronto! Com isso o ArcGIS será capaz de executar o treinamento sem problemas.


Para a preparação dos dados do treinamento, defini o mini batch de 68 e realizei o reajuste do tamanho das imagens usando chip_size para 256. Para a amostragem utilizei o atributo de estratificação e utilizei random seed de 500, ou seja, estratificando aleatoriamente em 500 grupos dentro de toda a passa de dados para validação, onde a validação informei que essa seria de 30% da massa de dados, porcentagem escolhida devido a pouca quantidade de amostras.

data = prepare_data(out_amostras, batch_size= 68, dataset_type="ImageNet", 
                    chip_size = 256, seed = 500, val_split_pct = 0.3,
                    stratify = True)

Então, tivemos no final 3794 imagens para treino e 1627 imagens para validação.


data

Veja que mesmo eu passando chip_size 256 as imagens possuem menor resolução, sendo essa de 138, então a função desprezou meu valor e adotou o valor 138.


Aqui abaixo você pode ver um exemplo de um dos batch's que serão utilizados no treinamento.


data.show_batch()

Agora era realizar o treinamento do modelo.


Treinando o modelo


Utilizando a função FeatureClassifier é preciso somente informar o conjunto de dados, a arquitetura base que usei, neste caso, utilizei o resnet18 e informei o oversample como True, pois, como as classes e as imagens são desbalanceadas a função irá ajustar tal problema.

model =  FeatureClassifier(data, backbone="resnet18", oversample=True)

Modelo compilado, foi somente utilizar a função .lr_find (find learning rate) para executar iterativamente, estima qual será nosso melhor valor para o learning rate do modelo de deep learning, que neste caso a função encontrou 0.0014.

lr = model.lr_find()
print("Learning Rate:",lr)


Encontrado o melhor Learning Rate executei o treinamento para 100 épocas, mas informei o early stop como falso, ou seja, que o modelo não iria parar quando o validation loss e o train loss aumentasse a diferença e também informei o checkpoint, salvando os melhores modelos durante o treinamento.

model.fit(100, lr =lr, early_stopping=False, checkpoint=True)


Depois das 100 épocas de treinamento o modelo chegou a uma acurácia de 97.42%.


Com o modelo finalizado podemos ver então o gráfico de perdas, onde mostra que o modelo treinou bem, pois as duas curvas desceram em conjunto até chegar em um ponto de estabilização, como é de se esperar.


model.plot_losses()


Como a função é de feature classifier, foi possível também ver a matriz de confusão, onde foi possível verificar que a maioria da confusão está entre as classes A04 - A32, A32 - A04 e A62 - A64.


model.plot_confusion_matrix()


Onde esses casos de erros são mostrados, quando utilizamos a função .plot_hard_examples que aponta as piores imagens e o Grad-CAM (Gradient-weighted Class Activation Mapping) de cada um deles.


model.plot_hard_examples(2)



No final foi possível ver o resultado, neste caso, escolhi somente duas imagens, onde consequentemente, as duas foram da classe A32 e obtiveram a classificação correta.


model.show_results(2)



Prevendo novas imagens


Para prever as classes das imagens de teste, criei uma função para buscas dentro dos metadados das imagens de teste, realizando a leitura do arquivo e informando qual a classe da imagem e assim comparar com o resultado previsto pelo modelo.


dir_teste = "D:\T72Variants\teste"
    
def read_metadata(diretorio):
    lista_files = []
    for path in os.scandir(dir_teste):
        if path.is_file():
            if not path.name.endswith(".JPG"):
                img_test1_char = pd.read_fwf(diretorio+path.name,
                               encoding='unicode_escape').iloc[12][0][-3:]
                lista_files.append(img_test1_char)
                               
    return lista_files

E então foi possível ver que a primeira e a segunda imagem eram respectivamente A04 e A63

read_metadata(dir_teste)



E então realizei a predição do modelo utilizando a função .predict e informei que gostaria de visualizar a execução, mas não gostaria de ver o gradcam.





model.predict(f"{dir_teste}\\HB14937.JPG", visualize=True, gradcam=False)







model.predict(f"{dir_teste}\\HB14961.JPG", visualize=True, gradcam=False)




Com isso foi possível ver que no modelo, para essas duas imagens de teste, ele acertou a classe das duas.




Conclusão


O artigo aqui mostra mais uma vez o potencial do ArcGIS para treinar modelos de deep learning em sua forma low-code, que facilita a gente formar mais, em modificar parâmetros e no experimento que na codificação dos modelos, como foi mostrado que realizei o treinamento de uma modelo com 97.42% acurácia e que acertou as duas imagens de teste, tendo pouco falsos positivos e negativos durante a validação.


Além disso, demostra o potencial crescente entre a união da Inteligência Artificial com Sensoriamento Remoto para realizar aplicações efetivas e resolver problemas como esses na área defesa, no qual informações como essa poderia balizar a tomada de decisão em táticas de guerra.


Se tiver interesse em ver o jupyter notebook onde realizei o treinamento do modelo esse é o link do github.

bottom of page