Créez un programme de classification d'images à l'aide de Keras. Préparez un grand nombre de fichiers image (format .jpeg) avant d'exécuter le programme et divisez-les en dossiers pour chaque type d'image. Conservez le fichier de test dans un dossier séparé de celui pour l'apprentissage, car vous ferez le test de classification plus tard.
ic_module.py
import glob
import numpy as np
glob est utilisé pour lire les fichiers. numpy est une bibliothèque souvent utilisée pour le ** calcul matriciel **.
from keras.preprocessing.image import load_img, img_to_array, array_to_img
from keras.preprocessing.image import random_rotation, random_shift, random_zoom
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Dense
from keras.layers.core import Dropout
from keras.layers.core import Flatten
from keras.models import Sequential
from keras.models import model_from_json
from keras.callbacks import LearningRateScheduler
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
from keras.utils import np_utils
Le prétraitement est un prétraitement. couches est la construction du contenu du modèle d'apprentissage, dont convolutif est le ** réseau convolutif **. La mise en pool est également une couche de mise en commun, utilisée pour ** ignorer ** l'emplacement d'un objet dans l'image. models traite du modèle implémenté lui-même. les rappels sont les processus exécutés pendant l'apprentissage. les optimiseurs sont des algorithmes d'optimisation. utils ici vectoriels entiers naturels (1, 2, 3, ...) ([1, 0, 0, ...], [0, 1, 0, ...], [0, 0, 1 Utilisé pour les fonctions qui se convertissent en, ...], ...).
FileNames = ["img1.npy", "img2.npy", "img3.npy"]
ClassNames = ["Lapins", "Inu", "Chat"]
hw = {"height":16, "width":16} #Insérez entre crochets du milieu de type dictionnaire au lieu de listes
On suppose qu'il existe trois catégories. FileNames est un fichier d'images du même type et ClassNames est une liste de noms de classification d'images. Modifiez les noms de classe selon vos besoins et lisez les dossiers dans cet ordre lors du prétraitement. hw spécifie la taille réduite de l'image chargée.
def PreProcess(dirname, filename, var_amount=3):
Ici, l'image est lue et la taille est unifiée à 16x16 (pour la hauteur: 16 et la largeur: 16). Il génère également une image pivotée et augmente les données d'entraînement (var_amount = 3 fois).
num = 0
arrlist = []
C'est une liste pour mettre le compteur du nombre de fichiers image et le fichier image converti au type numpy.
files = glob.glob(dirname + "/*.jpeg ")
Extrayez le nom de fichier du fichier jpeg dans le dossier.
for imgfile in files:
img = load_img(imgfile, target_size=(hw["height"], hw["width"])) #Chargement des fichiers image
array = img_to_array(img) / 255 #Fichier image numpy
arrlist.append(array) #Ajouter des données de type numpy à la liste
for i in range(var_amount-1):
arr2 = array
arr2 = random_rotation(arr2, rg=360)
arrlist.append(arr2) #Ajouter des données de type numpy à la liste
num += 1
Chargez le fichier image avec la taille spécifiée avec load_img. Étant donné que l'image est enregistrée avec une valeur numérique de 0 à 255 pour chaque couleur RVB, divisez-la par 255 pour obtenir une valeur numérique de 0 à 1. Nous ajouterons ceci à l'arrlist. De plus, random_rotation fait pivoter l'image de manière aléatoire et l'ajoute également à la liste d'arrêts.
nplist = np.array(arrlist)
np.save(filename, nplist)
print(">> " + dirname + "De" + str(num) + "Lecture réussie des fichiers")
Faites de arrlist un type numpy. Les données de type numpy peuvent être enregistrées avec save.
def BuildCNN(ipshape=(32, 32, 3), num_classes=3):
Ici, nous allons construire un modèle d'apprentissage.
model = Sequential()
Définit un modèle simple dans lequel les données ne divergent ni ne fusionnent.
model.add(Conv2D(24, 3, padding='same', input_shape=ipshape))
model.add(Activation('relu'))
Les données d'image sont pliées 24 fois avec un filtre 3x3. Tout d'abord, je vais expliquer ce qu'est le processus de convolution, en utilisant l'image ci-dessous comme exemple.
Dans le processus de convolution, le "filtre" rouge est d'abord superposé à "l'image" bleue, et chaque élément est multiplié. Si vous pouvez calculer 2 × 3 = 6, 5 × 2 = 10, 2 × 4 = 8, additionnez-les tous. Cette multiplication et cette addition sont effectuées en déplaçant le filtre verticalement et horizontalement un par un. Ensuite, vous obtiendrez le résultat suivant. C'est le processus de convolution.
Effectuez ce processus de convolution 24 fois. Ceci est parfois appelé "24 couches". Pour revenir à la description du programme, padding = 'same' signifie remplir l'image avec des 0. Cela signifie que la première image est entourée de «0» sur un fond blanc et qu'elle a la particularité que les tailles verticale et horizontale des données ne changent pas lorsque le processus de convolution est effectué. Utilisez également Activation ('relu') pour spécifier la ** fonction relu ** comme fonction d'activation.
model.add(Conv2D(48, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
Les données d'image sont pliées 48 fois avec un filtre 3x3. MaxPooling2D renvoie la valeur maximale dans pool_size (2 × 2). Les données d'image sont divisées en 2 x 2 petites zones et la valeur maximale de cette zone est émise.
Le décrochage (0,5) remplace également 50% de l'entrée par 0. Cela évitera le ** surapprentissage **.
model.add(Conv2D(96, 3, padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(96, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
Identique à la couche 1 et à la couche 2. La différence est qu'il y a 96 couches (96 plis).
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
Jusqu'à présent, les données étaient gérées comme un tableau bidimensionnel, mais Flatten () et Dense (128) en font un tableau unidimensionnel avec 128 éléments.
model.add(Dense(num_classes))
model.add(Activation('softmax'))
Définissez le nombre de sorties sur le nombre de dossiers chargés (= type d'image).
adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(loss='categorical_crossentropy',
optimizer=adam,
metrics=['accuracy'])
return model
Définissez la fonction d'optimisation sur ** Adam ** et construisez la structure que vous avez écrite jusqu'à présent en compilant. La fonction de perte est ** categorical_crossentropy **, qui est souvent utilisée dans les problèmes de classification. Enfin, retournez et passez le modèle créé dans la section suivante à chaque fonction.
def Learning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9):
Entraînons-nous en fait en utilisant le modèle et les données d'image implémentés précédemment.
X_TRAIN_list = []; Y_TRAIN_list = []; X_TEST_list = []; Y_TEST_list = [];
target = 0
for filename in FileNames :
data = np.load(filename) #Lire les données numpy de l'image
trnum = data.shape[0] - tsnum
X_TRAIN_list += [data[i] for i in range(trnum)] #données d'image
Y_TRAIN_list += [target] * trnum #Numéro de classe
X_TEST_list += [data[i] for i in range(trnum, trnum+tsnum)] #Données d'image non apprises
Y_TEST_list += [target] * tsnum; #Numéro de classification à ne pas apprendre
target += 1
Puisque les images sont utilisées comme données d'entrée et que les numéros de classification sont utilisés comme données d'enseignants pour la formation, ces deux éléments sont liés. Plus précisément, le numéro de classification de X_TRAIN_list [n] = Y_TRAIN_list [n]. De plus, afin de voir à quel point il est précis pendant l'entraînement, divisez les données des feuilles de tsnum (y compris celles gonflées par la rotation de l'image) afin qu'elles ne soient pas entraînées. Enfin, target + = 1 est configuré pour changer le numéro de classification pour chaque donnée numpy de l'image.
X_TRAIN = np.array(X_TRAIN_list + X_TEST_list) #Mise en relation
Y_TRAIN = np.array(Y_TRAIN_list + Y_TEST_list) #Mise en relation
print(">>Nombre d'échantillons de formation: ", X_TRAIN.shape)
y_train = np_utils.to_categorical(Y_TRAIN, target) #Convertir des nombres naturels en vecteurs
valrate = tsnum * target * 1.0 / X_TRAIN.shape[0]
La fonction d'ajustement, décrite ci-dessous, utilise la dernière partie des données pour vérifier l'exactitude. Par conséquent, X (Y) _TRAIN_list + X (Y) _TEST_list concatène les données qui ne sont pas apprises. De plus, le numéro de classification est actuellement écrit sous forme de nombre naturel (1, 2, 3), mais il est difficile de l'apprendre tel quel, donc le vecteur ([1, 0, 0], [0, 1, 0], [0 ,, Convertir en 0, 1]). Le valrate final est une valeur qui spécifie la quantité de données totales utilisée pour le contrôle de précision. Selon la formule, des feuilles de tsnum sont fournies pour chaque classification pour confirmation de l'exactitude.
class Schedule(object):
def __init__(self, init=0.001): #Définition de la valeur initiale
self.init = init
def __call__(self, epoch): #Calcul de la valeur actuelle
lr = self.init
for i in range(1, epoch+1):
lr *= learn_schedule
return lr
def get_schedule_func(init):
return Schedule(init)
À mesure que le nombre d'époques augmente, le taux d'apprentissage diminue. init est le taux d'apprentissage initial et lr est le taux d'apprentissage calculé ou actuel. Facilite la convergence des poids au fur et à mesure que l'apprentissage progresse.
lrs = LearningRateScheduler(get_schedule_func(0.001))
mcp = ModelCheckpoint(filepath='best.hdf5', monitor='val_loss', verbose=1, save_best_only=True, mode='auto')
model = BuildCNN(ipshape=(X_TRAIN.shape[1], X_TRAIN.shape[2], X_TRAIN.shape[3]), num_classes=target)
Définissez les paramètres utilisés pour l'apprentissage. lrs est la fonction de changement de taux d'apprentissage elle-même. mcp est une fonction qui enregistre le poids à chaque fois que ** val_loss ** devient le plus petit pendant l'entraînement. model est le modèle d'apprentissage construit dans la section précédente.
print(">>Commencer à apprendre")
hist = model.fit(X_TRAIN, y_train,
batch_size=batch_size,
verbose=1,
epochs=nb_epoch,
validation_split=valrate,
callbacks=[lrs, mcp])
L'apprentissage se fait avec la fonction fit. Spécifie les données X_TRAIN, y_train à utiliser pour l'entraînement. batch_size est la taille pour faire la moyenne des données d'entrée, epochs est le nombre de répétitions de l'entraînement, la variable est le pourcentage de données pour la confirmation de l'exactitude et les rappels est la fonction utilisée pendant l'entraînement.
json_string = model.to_json()
json_string += '##########' + str(ClassNames)
open('model.json', 'w').write(json_string)
model.save_weights('last.hdf5')
Le modèle de formation peut être enregistré au format json. Puisque json est un texte, ajoutez le nom de classification de l'image et enregistrez-le. Les poids peuvent également être facilement enregistrés avec save_weights.
def TestProcess(imgname):
L'image est lue et le résultat d'apprentissage est utilisé pour déterminer ce qu'est l'image.
modelname_text = open("model.json").read()
json_strings = modelname_text.split('##########')
textlist = json_strings[1].replace("[", "").replace("]", "").replace("\'", "").split()
model = model_from_json(json_strings[0])
model.load_weights("last.hdf5") # best.Utilisez le paramètre de moindre perte avec hdf5
img = load_img(imgname, target_size=(hw["height"], hw["width"]))
TEST = img_to_array(img) / 255
Chargez les données du modèle et les données de poids entraîné. Utilisez model_from_json pour charger le modèle à partir du format json et load_weights pour charger le fichier de sauvegarde de poids. Puisque le nom de classification est ajouté au fichier json, le modèle est chargé après sa division. L'image est chargée par load_img, qui a également été utilisé dans la section de prétraitement. L'image est quantifiée avec img_to_array.
pred = model.predict(np.array([TEST]), batch_size=1, verbose=0)
print(">>Résultat du calcul ↓\n" + str(pred))
print(">>Cette image est "" + textlist[np.argmax(pred)].replace(",", "") + ""est.")
Vous pouvez calculer à l'aide du résultat d'apprentissage avec la fonction prédire. Le résultat du calcul montre la probabilité d'être classé dans chaque catégorie en organisant des valeurs numériques telles que [[0,36011574 0,28402892 0,35585538]]. En d'autres termes, la classification indiquée par le plus grand nombre est le contenu de l'image.
ic_module.py
#! -*- coding: utf-8 -*-
import glob
import numpy as np
from keras.preprocessing.image import load_img, img_to_array, array_to_img
from keras.preprocessing.image import random_rotation, random_shift, random_zoom
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Dense
from keras.layers.core import Dropout
from keras.layers.core import Flatten
from keras.models import Sequential
from keras.models import model_from_json
from keras.callbacks import LearningRateScheduler
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
from keras.utils import np_utils
FileNames = ["img1.npy", "img2.npy", "img3.npy"]
ClassNames = ["Lapins", "Inu", "Chat"]
hw = {"height":32, "width":32} #Insérez entre crochets du milieu de type dictionnaire au lieu de listes
################################
######Prétraitement des données d'image######
################################
def PreProcess(dirname, filename, var_amount=3):
num = 0
arrlist = []
files = glob.glob(dirname + "/*.jpeg ")
for imgfile in files:
img = load_img(imgfile, target_size=(hw["height"], hw["width"])) #Chargement des fichiers image
array = img_to_array(img) / 255 #Fichier image numpy
arrlist.append(array) #Ajouter des données de type numpy à la liste
for i in range(var_amount-1):
arr2 = array
arr2 = random_rotation(arr2, rg=360)
arrlist.append(arr2) #Ajouter des données de type numpy à la liste
num += 1
nplist = np.array(arrlist)
np.save(filename, nplist)
print(">> " + dirname + "De" + str(num) + "Lecture réussie des fichiers")
################################
#########Construire un modèle#########
################################
def BuildCNN(ipshape=(32, 32, 3), num_classes=3):
model = Sequential()
model.add(Conv2D(24, 3, padding='same', input_shape=ipshape))
model.add(Activation('relu'))
model.add(Conv2D(48, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(96, 3, padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(96, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes))
model.add(Activation('softmax'))
adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(loss='categorical_crossentropy',
optimizer=adam,
metrics=['accuracy'])
return model
################################
#############Apprentissage#############
################################
def Learning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9):
X_TRAIN_list = []; Y_TRAIN_list = []; X_TEST_list = []; Y_TEST_list = [];
target = 0
for filename in FileNames :
data = np.load(filename) #Lire les données numpy de l'image
trnum = data.shape[0] - tsnum
X_TRAIN_list += [data[i] for i in range(trnum)] #données d'image
Y_TRAIN_list += [target] * trnum #Numéro de classe
X_TEST_list += [data[i] for i in range(trnum, trnum+tsnum)] #Données d'image non apprises
Y_TEST_list += [target] * tsnum; #Numéro de classification à ne pas apprendre
target += 1
X_TRAIN = np.array(X_TRAIN_list + X_TEST_list) #Mise en relation
Y_TRAIN = np.array(Y_TRAIN_list + Y_TEST_list) #Mise en relation
print(">>Nombre d'échantillons de formation: ", X_TRAIN.shape)
y_train = np_utils.to_categorical(Y_TRAIN, target) #Convertir des nombres naturels en vecteurs
valrate = tsnum * target * 1.0 / X_TRAIN.shape[0]
#Changement de taux d'apprentissage
class Schedule(object):
def __init__(self, init=0.001): #Définition de la valeur initiale
self.init = init
def __call__(self, epoch): #Calcul de la valeur actuelle
lr = self.init
for i in range(1, epoch+1):
lr *= learn_schedule
return lr
def get_schedule_func(init):
return Schedule(init)
lrs = LearningRateScheduler(get_schedule_func(0.001))
mcp = ModelCheckpoint(filepath='best.hdf5', monitor='val_loss', verbose=1, save_best_only=True, mode='auto')
model = BuildCNN(ipshape=(X_TRAIN.shape[1], X_TRAIN.shape[2], X_TRAIN.shape[3]), num_classes=target)
print(">>Commencer à apprendre")
hist = model.fit(X_TRAIN, y_train,
batch_size=batch_size,
verbose=1,
epochs=nb_epoch,
validation_split=valrate,
callbacks=[lrs, mcp])
json_string = model.to_json()
json_string += '##########' + str(ClassNames)
open('model.json', 'w').write(json_string)
model.save_weights('last.hdf5')
################################
##########Essai / expérience##########
################################
def TestProcess(imgname):
modelname_text = open("model.json").read()
json_strings = modelname_text.split('##########')
textlist = json_strings[1].replace("[", "").replace("]", "").replace("\'", "").split()
model = model_from_json(json_strings[0])
model.load_weights("last.hdf5") # best.Utilisez le paramètre de moindre perte avec hdf5
img = load_img(imgname, target_size=(hw["height"], hw["width"]))
TEST = img_to_array(img) / 255
pred = model.predict(np.array([TEST]), batch_size=1, verbose=0)
print(">>Résultat du calcul ↓\n" + str(pred))
print(">>Cette image est "" + textlist[np.argmax(pred)].replace(",", "") + ""est.")
La source jusqu'à ce point est écrite et enregistrée dans un fichier appelé ic_module.py. Lors de l'utilisation de ce module, exécutez le code suivant à chaque étape du traitement.
preprocess.py
import ic_module as ic
import os.path as op
i = 0
for filename in ic.FileNames :
#Entrez le nom du répertoire
while True :
dirname = input(">>「" + ic.ClassNames[i] + "Répertoire avec images:")
if op.isdir(dirname) :
break
print(">>Ce répertoire n'existe pas!")
#Exécution de la fonction
ic.PreProcess(dirname, filename, var_amount=3)
i += 1
Lire un dossier (répertoire). Spécifiez les répertoires dans l'ordre des ClassNames écrits au début de ic_module.
learning.py
import ic_module as ic
#Exécution de la fonction
ic.Learning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9)
Utilisez tsnum pour spécifier le nombre de feuilles de chaque classification utilisées pour le contrôle de précision et learn_schedule pour spécifier le degré d'atténuation du taux d'apprentissage pour chaque époque. Vous pouvez également spécifier combien de fois l'apprentissage doit être répété avec nb_epoch. Voici un exemple d'exécution.
perte signifie la différence (perte) entre le résultat du calcul et la valeur de réponse correcte, acc signifie la précision du jugement d'image, et ceux avec val_ sont les résultats lorsque des données non utilisées pour l'apprentissage sont utilisées. Plus le val_loss est petit et plus le val_acc est grand, plus l'apprentissage est avancé. Une grande différence entre loss et val_loss ou acc et val_acc signifie ** surapprentissage **. Il est difficile de s'en débarrasser ...
testprocess.py
import ic_module as ic
import os.path as op
while True:
while True:
imgname = input("\n>>Fichier image que vous souhaitez saisir(Terminer par "END") : ")
if op.isfile(imgname) or imgname == "END":
break
print(">>Ce fichier n'existe pas!")
if imgname == "END":
break
#Exécution de la fonction
ic.TestProcess(imgname)
Si vous spécifiez une image, elle déterminera de quoi il s'agit. Voici un exemple d'exécution. N'oubliez pas le nom du dossier.
Jugement par lots d'images dans un dossier
Ajout de "return np.argmax (pred)" à TestProcess de ic_module
import glob
import ic_module as ic
import os.path as op
dirname = "dogs"#input("Nom de dossier:")
files = glob.glob(dirname + "/*.jpeg ")
cn1 = 0; cn2 = 0;
for imgname in files :
kind = ic.TestProcess(imgname)
if kind == 1:
cn2 += 1
cn1 += 1
print("Le taux de réponse correct, y compris l'apprentissage et le non-apprentissage" + str(cn2*1.0/cn1) + "est.")