[PYTHON] Prédiction géolocalisée à partir d'images à l'aide de DNN

introduction

Cette fois, j'aimerais faire une prédiction de géolocalisation à partir d'une image de bâtiment à l'aide d'un modèle entraîné. Surtout dans cet article, j'ai commencé avec le but d'utiliser la sortie de plusieurs étiquettes de latitude et de longitude à partir de l'image d'entrée.

Données à utiliser

Les données utilisées cette fois sont "European Cities 1M dataset" http://image.ntua.gr/iva/datasets/ec1m/index.html

Utilisez respectivement l'image de l'ensemble de points de repère et la géolocalisation sur ce site.

Environnement de construction

La mise en œuvre de cet article utilise Google Colaboratory. Les paramètres de l'environnement utilisé sont répertoriés ci-dessous.


import keras
from keras.utils import np_utils
from keras.models import Sequential, Model, load_model
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.layers.core import Dense, Dropout, Activation, Flatten
import numpy as np
from sklearn.model_selection import train_test_split
import os, zipfile, io, re
from PIL import Image
import glob
from tqdm import tqdm

from sklearn.model_selection import train_test_split
from keras.applications.xception import Xception
from keras.applications.resnet50 import ResNet50
from keras.layers.pooling import GlobalAveragePooling2D
from keras.optimizers import Adam, Nadam

Prétraitement

Ici, en tant que prétraitement, un traitement avec des étiquettes de latitude et de longitude est effectué. Cette fois, nous apprendrons la latitude et la longitude séparément en tant qu'étiquettes, nous les traiterons donc afin qu'elles puissent être facilement récupérées sous forme de liste.


with open("landmark/ec1m_landmarks_geotags.txt") as f:
    label=f.readlines()
    for i in label:
        ans=i.split(' ')
        ans[1]=ans[1].replace('\n','')
        print(ans)

production


['41.4134', '2.153']
['41.3917', '2.16472']
['41.3954', '2.16177']
['41.3954', '2.16177']
['41.3954', '2.16156']
['41.3899', '2.17428']
['41.3953', '2.16184']
['41.3953', '2.16172']
['41.3981', '2.1645']
.....
.....

L'acquisition des données

La taille de l'image est de 100 Convertir l'ensemble de données en tableau Étiqueter l'image sans séparer la latitude et la longitude


X = []
Y = []
image_size=100

with open("landmark/ec1m_landmarks_geotags.txt") as f:
    label=f.readlines()

    dir = "landmark/ec1m_landmark_images"
    files = glob.glob(dir + "/*.jpg ")
    for index,file in tqdm(enumerate(files)):
        image = Image.open(file)
        image = image.convert("RGB")
        image = image.resize((image_size, image_size))
        data = np.asarray(image)
        X.append(data)
        Y.append(label[index])
 
X = np.array(X)
Y = np.array(Y)

production


927it [00:08, 115.29it/s]

Chaque forme est comme ça
X.shape,Y.shape
((927, 100, 100, 3), (927,))

Ensuite, divisez en train, testez, validez Divisez la latitude et la longitude ici

y0=[]  #Libellé Latitude
y1=[]  #Libellé de longitude

for i in Y:
    ans=i.split(' ')
    ans[1]=ans[1].replace('\n','')
    y0.append(float(ans[0]))
    y1.append(float(ans[1]))

y0=np.array(y0)
y1=np.array(y1)

#X(train,test)Divisé
X_train, X_test = train_test_split(X, random_state = 0, test_size = 0.2)
print(X_train.shape,  X_test.shape) 

#(741, 100, 100, 3) (186, 100, 100, 3)

#y0,y1(train,test)Divisé
y_train0,y_test0,y_train1, y_test1 = train_test_split(y0,y1,
                                                      random_state = 0,
                                                      test_size = 0.2)
print(y_train0.shape,  y_test0.shape) 
print(y_train1.shape,  y_test1.shape)

#(741,) (186,)
#(741,) (186,)

#Conversion et normalisation du type de données
X_train = X_train.astype('float32') / 255
X_test = X_test.astype('float32') / 255

#X(train,valid)Divisé
X_train, X_valid= train_test_split(X_train, random_state = 0, test_size = 0.2)
print(X_train.shape,  X_valid.shape) 

#(592, 100, 100, 3) (149, 100, 100, 3)

#y0,y1(train,valid)Divisé
y_train0, y_valid0,y_train1, y_valid1= train_test_split(y_train0,y_train1,
                                                        random_state = 0,
                                                        test_size = 0.2)

print(y_train0.shape,  y_valid0.shape) 
print(y_train1.shape,  y_valid1.shape) 

#(592,) (149,)
#(592,) (149,)

Construction de modèles

Cette fois, nous utiliserons le modèle entraîné de Xception en nous référant à l'article suivant. https://qiita.com/ha9kberry/items/314afb56ee7484c53e6f#データ取得

Je voulais l'essayer avec d'autres modèles, donc j'essaierai également d'utiliser Resnet.


#xception model
base_model = Xception(
    include_top = False,
    weights = "imagenet",
    input_shape = None
)

#resnet model
base_model = ResNet50(
    include_top = False,
    weights = "imagenet",
    input_shape = None
)

Entrez une valeur prédite à la fin du problème de régression Préparer la sortie d'étiquette pour la latitude et la longitude

x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions1 = Dense(1,name='latitude')(x)
predictions2 = Dense(1,name='longitude')(x)

Mettez predictions1 et predictions2 en sortie. D'autres sont comme dans l'article de référence Cette fois, nous étudierons l'utilisation d'Adam et Nadam comme optimiseurs.


model = Model(inputs = base_model.input, outputs = [predictions1,predictions2])

#Congelez jusqu'à 108 couches
for layer in model.layers[:108]:
    layer.trainable = False

    #Libérer la normalisation des lots
    if layer.name.startswith('batch_normalization'):
        layer.trainable = True
    if layer.name.endswith('bn'):
        layer.trainable = True

#Apprenez à partir de la couche 109
for layer in model.layers[108:]:
    layer.trainable = True

# layer.compiler après avoir défini entraînable
model.compile(
    optimizer = Adam(),
    #optimizer=Nadam(),
    loss = {'latitude':root_mean_squared_error,
            'longitude':root_mean_squared_error
        }
)


Apprentissage


history = model.fit( X_train,   #decode_train
                    {'latitude': y_train0,
                     'longitude':y_train1},
                    batch_size=64,
                    epochs=50,
                    validation_data=(X_valid,    decode_valid
                                     {'latitude' :y_valid0,
                                      'longitude':y_valid1}),
                    )

production



Epoch 1/50
10/10 [==============================] - 4s 409ms/step - loss: 0.6146 - latitude_loss: 0.4365 - longitude_loss: 0.1782 - val_loss: 1.6756 - val_latitude_loss: 1.3430 - val_longitude_loss: 0.3326
Epoch 2/50
10/10 [==============================] - 4s 404ms/step - loss: 0.5976 - latitude_loss: 0.4415 - longitude_loss: 0.1562 - val_loss: 0.7195 - val_latitude_loss: 0.5987 - val_longitude_loss: 0.1208

...
...

Tracez les résultats

import matplotlib.pyplot as plt


plt.figure(figsize=(18,6))

# loss
plt.subplot(1, 2, 1)
plt.plot(history.history["latitude_loss"], label="latitude_loss", marker="o")
plt.plot(history.history["longitude_loss"], label="longitude_loss", marker="o")
#plt.yticks(np.arange())
#plt.xticks(np.arange())
plt.ylabel("loss")
plt.xlabel("epoch")
plt.title("")
plt.legend(loc="best")
plt.grid(color='gray', alpha=0.2)

plt.show()

résultat ダウンロード (9).png

Évaluation


#batch size 64  Adam
scores = model.evaluate(X_test,{'latitude' :y_test0,
                                'longitude':y_test1}, 
                             verbose=1)

print("total loss:\t{0}".format(scores[0]))
print("latitude loss:\t{0}".format(scores[1]))
print("longtitude loss:{0}".format(scores[2]))

production



total loss:	0.7182420492172241
latitude loss:	0.6623533964157104
longtitude loss:0.05588864907622337

Prévoir


# show image, prediction and actual label
for i in range(10,12):
    plt.figure(figsize=(10,10))
    print('latitude:{} \tlongititude{}'.format(
        prediction[0][i],
        prediction[1][i],
        ))

    plt.imshow(X_test[i].reshape(100, 100, 3))
    plt.show()

latitude:[39.69221] longititude[2.2188098] ダウンロード (10).png

latitude:[39.728386] longititude[2.224149] ダウンロード (11).png

Il y a des nombres comme ça, mais lorsqu'ils sont exprimés sur la carte (Google Map), c'est au milieu de la mer comme indiqué ci-dessous, ce qui n'est pas suffisant à utiliser.

image.png

Comparaison avec d'autres paramètres

Paramètres utilisés Total loss latitude_loss longtitude_loss
Xception , Adam 0.7182 0.6623 0.0558
Xception , Nadam 0.3768 0.1822 0.1946
Resnet , Adam 0.7848 0.7360 0.0488
Resnet , Nadam 49.6434 47.2652 2.3782
Resnet,Adam,AutoEncoder 1.8299 1.6918 0.13807

enfin

Dans cet essai, la combinaison de Xception et de Nadam s'est avérée la plus précise. À l'avenir, j'utiliserai un autre modèle ou créerai un modèle à partir de zéro

Référence, citation

base de données

Publications Conferences Y. Avrithis, Y. Kalantidis, G. Tolias, E. Spyrou. Retrieving Landmark and Non-Landmark Images from Community Photo Collections. In Proceedings of ACM Multimedia (MM 2010), Firenze, Italy, October 2010.

Journals Y. Kalantidis, G. Tolias, Y. Avrithis, M. Phinikettos, E. Spyrou, P. Mylonas, S. Kollias. VIRaL: Visual Image Retrieval and Localization. In Multimedia Tools and Applications (to appear), 2011.

article

--https: //qiita.com/ha9kberry/items/314afb56ee7484c53e6f # Présentation

Recommended Posts

Prédiction géolocalisée à partir d'images à l'aide de DNN
Télécharger des images de «Irasutoya» à l'aide de Scrapy
Charger des images à partir d'une URL à l'aide de Pillow dans Python 3
Télécharger des images à l'aide de demandes
Extraire des caractères d'images à l'aide de l'API de reconnaissance de caractères de docomo
Collectez des images à l'aide d'icrawler
Rechercher des illustrations de cartes à partir d'images à l'aide de la correspondance des points caractéristiques
Compilez Tesseract pour Tess4J pour transcrire des images à l'aide de CentOS
Enregistrer des images à l'aide de requêtes python3
Grattage immédiat des images google!
Prédiction d'images dans le cloud à l'aide de convLSTM
Catégoriser les images de chats à l'aide de ChainerCV