Fiz diversos testes com o dataset CIFAR-10. Não consegui ótimos resultados, mas consegui acurácia de 70% nas classes de meio de transporte; as demais estão bem precárias, vou fazer mais alguns testes e, se melhorar, coloco outro artigo. Nesse artigo vou compartilhar como fazer predição de imagens com Keras e OpenCV utilizando imagens que baixei através do Google Images.
Table of Contents
Classificação de imagens com CIFAR-10
É bem interessante fazer o treinamento, cheguei a um resultado superior a 80% em um dos treinamentos, mas conforme varia (para cima ou para baixo) as predições falham em lugares diferentes; imagens que outrora foram reconhecidas adequadamente, deixam de ser reconhecidas. Por essa razão optei por utilizar um treinamento que fiz com margem de acurácia inferior, mas eficiente para as classes de meios de transporte, batendo mesmo nos 70%. Claro, utilizei algumas imagens ruins em meio às óbvias e, na classificação de imagens boas, deve chegar a 100% de assertividade.
Se não leu minhas anotações sobre meu aprendizado e aprimoramento, sugiro que comece a partir da configuração do ambiente, descrito nesse artigo.
Por que Keras?
Poderia ter utilizado outra API, mas por acaso escolhi o Keras e acabei gostando bastante. O bom em utilizar algo assim é que além de facilitar a composição dos perceptrons, fica fácil mudar o backend, caso seja necessário migrar para outra plataforma. Antes de experimentar outras opções, vou dedicar por alguns meses um pouco do meu tempo ao aprendizado de deep learning, utilizando o Keras para minhas redes neurais.
Como fazer predição de imagens com Keras e OpenCV?
Essa foi uma dúvida que tive desde o começo. Realmente, não encontrei nada de exemplo, mas acredito que isso aconteceu porque procurei por predição em redes neurais, o que é algo bem isolado. É como pesquisar por “como definir chave primária em banco de dados MySQL”. O banco é uma coisa, o sistema que o utilizará é outra. Da mesma forma a rede neural; não importa a integração que for feita, ela tem um propósito independente da interface que a consultará.
Seu ambiente já está preparado para uma rede neural?
Se você ainda não configurou o ambiente, siga para esse artigo. Reproduzir esse tutorial será algo bem divertido!
Poderia ser uma infelicidade, mas graças a Deus meu sistema deu problema e tive que formatar e reconfigurar tudo. Daí tive a oportunidade de corrigir problemas residuais, além de aumentar minha compreensão no processo de configuração do ambiente. Dessa vez não utilizei docker nem virtualenv, queria ter o quanto antes meu ambiente de estudos de volta.
Por que OpenCV?
Daria para ler a imagem sem utilizar OpenCV. Aliás, assim eu estava fazendo; passava a imagem como argumento do script e fazia um loop no shell, mais ou menos assim:
ls barco/*|while read line; do sleep 5;python testingLayers-77.py $line; xdg-open $line;done
Testei cada categoria de forma independente justamente buscando pela acurácia de cada uma. Para ver a imagem relacionada, coloquei nesse loop a execução do visualizador de imagens que corresponde ao mime-type da extensão (xdg-open abre automaticamente) e fiz um delay de 5 segundos entre cada execução da rede neural. Mas ai tinha outro problema; não conseguia perceber o quão rápido era o processo entre cada imagem, da abertura até a predição. Daí entrou o OpenCV.
Código completo
O código que utilizei para fazer predição de imagens com Keras e OpenCV é este abaixo. Ainda tem mais coisas a adicionar e outras a modificar, mas já está bom para a brincadeira inicial.
# 77,14 10 epochs # 76,57 20 epochs # 77,50 30 epochs import time #import matplotlib.pyplot as plt import numpy as np from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.constraints import maxnorm from keras.layers import Activation from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.layers.normalization import BatchNormalization from keras.utils import np_utils from keras_sequential_ascii import sequential_model_to_ascii_printout from keras import backend as K import os import tensorflow as tf import multiprocessing as mp from keras.datasets import cifar10 import sys #sys.path.append("/usr/local/lib/pyhon2.7/dist-packages/") import cv2 # fix random seed for reproducibility seed = 7 np.random.seed(seed) batch_size = 32 num_classes = 10 epochz = 30 global density density = 128 #512 (x_train, y_train), (x_test, y_test) = cifar10.load_data() y_train = np_utils.to_categorical(y_train, num_classes) y_test = np_utils.to_categorical(y_test, num_classes) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255.0 x_test /= 255.0 #ok global labelsCifar10 labelsCifar10 = {} if (os.path.isfile('labels')): rfile = open('labels', 'r') labelsRaw = rfile.readlines() rfile.close() for i in range(0,10): labelsCifar10[int(labelsRaw[i].split(",")[0])] = str(labelsRaw[i].split(",")[1].replace("\n","")) def img_to_array(img, image_data_format='default'): """Converts numpy image into channels_first/channels_last format :param img: Numpy array x has format (height, width, channel) or (channel, height, width) """ if image_data_format == "default": image_data_format = K.image_data_format() if image_data_format not in ['channels_first', 'channels_last']: raise Exception('Unknown image_data_format: ', image_data_format) x = np.asarray(img, dtype=K.floatx()) # colored image # (channel, height, width) if len(x.shape) == 3: if image_data_format == 'channels_first': x = x.transpose(2, 0, 1) # grayscale elif len(x.shape) == 2: # already for th format x = np.expand_dims(x, axis=0) if image_data_format == 'channels_last': # (height, width, channel) x = x.reshape((x.shape[1], x.shape[2], x.shape[0])) # unknown else: raise Exception('Unsupported image shape: ', x.shape) return x def base_model(): global density model = Sequential() model.add(Conv2D(32, (3, 3), padding='same', input_shape=x_train.shape[1:])) model.add(Activation('relu')) model.add(Conv2D(64,(3, 3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.2)) model.add(Conv2D(64, (3, 3), padding='same')) model.add(Activation('relu')) model.add(Conv2D(128, (3,3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.2)) model.add(Flatten()) model.add(Dense(128)) model.add(Activation('relu')) model.add(Dropout(0.2)) #ativacao de saida para 10 classes model.add(Dense(10)) model.add(Activation('softmax')) #model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) #para classificacao binaria #binary_crossentropy #para regressao #mse #para multiclasse #categorical_crossentropy model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) return model if len(sys.argv) == 1: cnn_n = base_model() cnn_n.summary() cnn = cnn_n.fit(x_train, y_train, batch_size=batch_size, epochs=epochz, validation_data=(x_test,y_test),shuffle=True) cnn_n.save_weights("77-img_class-adam-cross_entropy.h5", overwrite=True) scores = cnn_n.evaluate(x_test, y_test, verbose=0) print("Accuracy: %.2f%%" % (scores[1] * 100)) else: if not os.path.isdir(sys.argv[1]): print("Directory not found. Exiting...") exit(0) directory = sys.argv[1] files = os.listdir(directory) files = [w.replace("\n","") for w in files] #print(files) #print(labelsCifar10) if len(files) < 1: print("There is no files in \'"+directory+"\' directory. Exiting...") exit(0) cnn_n = base_model() cnn_n.load_weights("77-img_class-adam-cross_entropy.h5") font = cv2.FONT_HERSHEY_SIMPLEX for filename in files: img = cv2.imread(directory + "/" +filename) img = cv2.resize(img, (32, 32)) x = img_to_array(np.float32(img) / 255.0) x = np.expand_dims(x, axis=0) start_t = time.time() res = cnn_n.predict(x, verbose=0) ####print("took (s)", round(time.time() - start_t,2)) #print("class index: ", res.argmax()) detected = res.argmax() if labelsCifar10[res.argmax()] in filename: print(labelsCifar10[res.argmax()]) imgRead = cv2.imread(directory + "/" + filename, cv2.IMREAD_COLOR) cv2.putText(imgRead, labelsCifar10[res.argmax()], (42, 42), font, 1, (0, 0, 0), 2, cv2.LINE_AA) cv2.putText(imgRead, labelsCifar10[res.argmax()], (38, 38), font, 1, (255, 255, 255), 2, cv2.LINE_AA) cv2.putText(imgRead, labelsCifar10[res.argmax()], (40, 40), font, 1, (0, 128, 255), 2, cv2.LINE_AA) else: print("unknown") imgRead = cv2.imread(directory + "/" + filename, cv2.IMREAD_COLOR) cv2.putText(imgRead, "unknown", (42, 42), font, 1, (0, 0, 0), 2, cv2.LINE_AA) cv2.putText(imgRead, "unknown", (38, 38), font, 1, (255, 255, 255), 2, cv2.LINE_AA) cv2.putText(imgRead, "unknown", (40, 40), font, 1, (0, 128, 255), 2, cv2.LINE_AA) cv2.imshow("CIFAR-10", imgRead) cv2.waitKey(0) cv2.destroyAllWindows()
Modo de uso
Crie um diretório com imagens misturadas, pertencentes (ou não) às classes do CIFAR-10. Se desejar, crie diretórios com as classes separadas e faça a predição por classe. Para fazer predição de imagens com Keras e OpenCV utilizando esse script, basta chamar o python seguido do programa e passando o nome do diretório como parâmetro:
python predictor.py aviao
Essa linha acima fará apenas a predição do diretório contendo as imagens de avião. As imagens podem ter qualquer nome, isso não importa. Prefira utilizar imagens com extensão .jpg para evitar quaisquer problemas.
Se o script for executado sem parâmetros, um novo treinamento será iniciado. Se esquecer de passar o parâmetro, não se preocupe, pode interromper com Ctrl+C ou com sua IDE de desenvolvimento, porque o model só seria sobrescrito ao final do treinamento.
Vídeo
Prometi em um dos artigos anteriores que mostraria a predição de imagens com Keras e OpenCV utilizando o dataset CIFAR-10, mas achei melhor esperar até esse momento, com um programa visualmente mais agradável. O vídeo deverá estar pronto algumas horas após a publicação desse artigo, vale a pena conferir. Faço alguns comentários a respeito das predições no vídeo. Visite (e se inscreva no canal) DobitAoByteBrasil no Youtube. Aproveite para clicar no sininho para receber notificações, assim quando o vídeo estiver publicado, você ficará sabendo logo. não deixe de ver o vídeo, uma parte decepciona e outra, surpreende.
Espero que se divirta como eu estou me divertindo. Até a próxima!
Primeira execução?
Se ainda não teve contato com CIFAR-10, o programa irá baixar o dataset automaticamente. Se quiser saber mais do dataset, visite o site oficial. A compilação levará um tempo, mas em uma próxima execução os pesos serão carregados do computador, pois estou salvando o treinamento ao final da execução do model.
Artigos relacionados
Monitorar câmeras e ONVIF no Raspberry
superres : upscale de imagem sem perda com Waifu2x
Controle remoto universal inteligente