Erstellen Sie ein Bildklassifizierungsprogramm mit Keras. Bereiten Sie eine große Anzahl von Bilddateien (JPEG-Format) vor, bevor Sie das Programm ausführen, und teilen Sie sie für jeden Bildtyp in Ordner auf. Bewahren Sie die Testdatei in einem anderen Ordner als dem zum Lernen auf, da Sie den Klassifizierungstest später durchführen werden.
ic_module.py
import glob
import numpy as np
glob wird zum Lesen von Dateien verwendet. numpy ist eine Bibliothek, die häufig für die ** Matrixberechnung ** verwendet wird.
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
Vorverarbeitung ist Vorverarbeitung. Schichten ist die Konstruktion des Inhalts des Lernmodells, dessen Faltungsnetz das Faltungsnetzwerk ist. Pooling ist auch eine Pooling-Ebene, die verwendet wird, um zu ignorieren, wo sich ein Objekt im Bild befindet. models befasst sich mit dem implementierten Modell selbst. Rückrufe sind die Prozesse, die während des Lernens ausgeführt werden. Optimierer sind Optimierungsalgorithmen. utils hier Vektor natürliche Zahlen (1, 2, 3, ...) ([1, 0, 0, ...], [0, 1, 0, ...], [0, 0, 1 Wird für Funktionen verwendet, die konvertieren in, ...], ...).
FileNames = ["img1.npy", "img2.npy", "img3.npy"]
ClassNames = ["Kaninchen", "Inu", "Katze"]
hw = {"height":16, "width":16} #Schließen Sie anstelle von Listen in mittlere Klammern vom Typ Wörterbuch ein
Es wird angenommen, dass es drei Kategorien gibt. FileNames ist eine Datei mit Bildern desselben Typs, und ClassNames ist eine Liste mit Bildklassifizierungsnamen. Ändern Sie die Klassennamen entsprechend und lesen Sie die Ordner in dieser Reihenfolge in der Vorverarbeitung. hw gibt die reduzierte Größe des geladenen Bildes an.
def PreProcess(dirname, filename, var_amount=3):
Hier wird das Bild gelesen und die Größe auf 16 x 16 vereinheitlicht (für Höhe: 16 und Breite: 16). Es erzeugt auch ein gedrehtes Bild und erhöht die Trainingsdaten (var_amount = 3-mal).
num = 0
arrlist = []
In dieser Liste wird der Zähler für die Anzahl der Bilddateien und die konvertierte Bilddatei auf den Typ numpy gesetzt.
files = glob.glob(dirname + "/*.jpeg ")
Extrahieren Sie den Dateinamen der JPEG-Datei in den Ordner.
for imgfile in files:
img = load_img(imgfile, target_size=(hw["height"], hw["width"])) #Laden von Bilddateien
array = img_to_array(img) / 255 #Bilddatei numpy
arrlist.append(array) #Fügen Sie der Liste Daten vom Typ Numpy hinzu
for i in range(var_amount-1):
arr2 = array
arr2 = random_rotation(arr2, rg=360)
arrlist.append(arr2) #Fügen Sie der Liste Daten vom Typ Numpy hinzu
num += 1
Laden Sie die Bilddatei mit der angegebenen Größe mit load_img. Da das Bild mit einem numerischen Wert von 0 bis 255 für jede RGB-Farbe aufgezeichnet wird, teilen Sie es durch 255, um einen numerischen Wert von 0 bis 1 zu erhalten. Wir werden dies zur Arrlist hinzufügen. Außerdem dreht random_rotation das Bild zufällig und fügt es ebenfalls der Arrlist hinzu.
nplist = np.array(arrlist)
np.save(filename, nplist)
print(">> " + dirname + "Von" + str(num) + "Erfolgreiches Lesen von Dateien")
Machen Sie arrlist zu einem numpy-Typ. Daten vom Typ numpy können mit save gespeichert werden.
def BuildCNN(ipshape=(32, 32, 3), num_classes=3):
Hier werden wir ein Lernmodell erstellen.
model = Sequential()
Definiert ein einfaches Modell, in dem Daten nicht divergieren oder zusammengeführt werden.
model.add(Conv2D(24, 3, padding='same', input_shape=ipshape))
model.add(Activation('relu'))
Die Bilddaten werden 24 Mal mit einem 3x3-Filter gefaltet. Zunächst werde ich anhand des folgenden Bildes den Faltungsprozess erläutern.
Während des Faltungsprozesses wird der rote "Filter" zuerst dem blauen "Bild" überlagert und jedes Element wird multipliziert. Wenn Sie 2 × 3 = 6, 5 × 2 = 10, 2 × 4 = 8 berechnen können, addieren Sie alle. Diese Multiplikation und Addition erfolgt durch vertikales und horizontales Verschieben des Filters nacheinander. Dann erhalten Sie das folgende Ergebnis. Dies ist der Faltungsprozess.
Führen Sie diesen Faltungsprozess 24 Mal durch. Dies wird manchmal als "24 Schichten" bezeichnet. Zurück zur Programmbeschreibung bedeutet padding = 'same', das Bild mit 0s zu füllen. Dies bedeutet, dass das erste Bild auf einem weißen Hintergrund von "0" umgeben ist und dass sich die vertikale und horizontale Größe der Daten nicht ändert, wenn der Faltungsprozess ausgeführt wird. Verwenden Sie außerdem die Aktivierung ('relu'), um die ** relu-Funktion ** als Aktivierungsfunktion anzugeben.
model.add(Conv2D(48, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
Die Bilddaten werden 48 Mal mit einem 3x3-Filter gefaltet. MaxPooling2D gibt den Maximalwert in pool_size aus (2 × 2). Die Bilddaten sind in 2x2 kleine Bereiche unterteilt und der Maximalwert in diesem Bereich wird ausgegeben.
Dropout (0,5) ersetzt auch 50% der Eingabe durch 0. Dies verhindert ** Überlernen **.
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))
Gleich wie Schicht 1 und Schicht 2. Der Unterschied besteht darin, dass es 96 Schichten (96 Falten) gibt.
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
Bisher wurden Daten als zweidimensionales Array behandelt, aber Flatten () und Dense (128) machen es zu einem eindimensionalen Array mit 128 Elementen.
model.add(Dense(num_classes))
model.add(Activation('softmax'))
Stellen Sie die Anzahl der Ausgaben auf die Anzahl der geladenen Ordner (= Bildtyp) ein.
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
Setzen Sie die Optimierungsfunktion auf ** Adam ** und erstellen Sie die bisher geschriebene Struktur durch Kompilieren. Die Verlustfunktion ist ** kategoriale_kreuzentropie **, die häufig bei Klassifizierungsproblemen verwendet wird. Geben Sie abschließend das im nächsten Abschnitt erstellte Modell zurück und übergeben Sie es an jede Funktion.
def Learning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9):
Lassen Sie uns tatsächlich anhand der zuvor implementierten Modell- und Bilddaten trainieren.
X_TRAIN_list = []; Y_TRAIN_list = []; X_TEST_list = []; Y_TEST_list = [];
target = 0
for filename in FileNames :
data = np.load(filename) #Lesen Sie die Numpy-Daten des Bildes
trnum = data.shape[0] - tsnum
X_TRAIN_list += [data[i] for i in range(trnum)] #Bilddaten
Y_TRAIN_list += [target] * trnum #Klassennummer
X_TEST_list += [data[i] for i in range(trnum, trnum+tsnum)] #Bilddaten nicht gelernt
Y_TEST_list += [target] * tsnum; #Klassifikationsnummer nicht zu lernen
target += 1
Da das Bild als Eingabedaten und die Klassifizierungsnummer als Lehrerdaten für das Training verwendet werden, hängen diese beiden zusammen. Insbesondere ist die Klassifizierungsnummer von X_TRAIN_list [n] = Y_TRAIN_list [n]. Um zu sehen, wie genau es während des Trainings ist, teilen Sie die Daten der Tsnum-Blätter (einschließlich der durch Bildrotation gepolsterten) so, dass sie nicht trainiert werden. Schließlich wird Ziel + = 1 gesetzt, um die Klassifizierungsnummer für jede Numpy-Daten des Bildes zu ändern.
X_TRAIN = np.array(X_TRAIN_list + X_TEST_list) #Verknüpfen
Y_TRAIN = np.array(Y_TRAIN_list + Y_TEST_list) #Verknüpfen
print(">>Anzahl der Trainingsmuster: ", X_TRAIN.shape)
y_train = np_utils.to_categorical(Y_TRAIN, target) #Konvertieren Sie natürliche Zahlen in Vektoren
valrate = tsnum * target * 1.0 / X_TRAIN.shape[0]
Die unten beschriebene Anpassungsfunktion verwendet den letzten Teil der Daten, um die Genauigkeit zu überprüfen. Daher verkettet X (Y) _TRAIN_list + X (Y) _TEST_list die Daten, die nicht gelernt wurden. Außerdem wird die Klassifizierungsnummer derzeit als natürliche Zahl (1, 2, 3) geschrieben, aber es ist schwierig zu lernen, wie sie ist, also der Vektor ([1, 0, 0], [0, 1, 0], [0 ,, In 0, 1 konvertieren]). Der endgültige Wert ist ein Wert, der angibt, wie viel der Gesamtdaten für die Genauigkeitsprüfung verwendet werden. Gemäß der Formel werden für jede Klassifizierung Tsnum-Blätter zur Bestätigung der Genauigkeit bereitgestellt.
class Schedule(object):
def __init__(self, init=0.001): #Anfangswertdefinition
self.init = init
def __call__(self, epoch): #Aktuelle Wertberechnung
lr = self.init
for i in range(1, epoch+1):
lr *= learn_schedule
return lr
def get_schedule_func(init):
return Schedule(init)
Mit zunehmender Anzahl von Epochen nimmt die Lernrate ab. init ist die anfängliche Lernrate und lr ist die berechnete oder aktuelle Lernrate. Erleichtert die Konvergenz von Gewichten im Verlauf des Lernens.
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)
Definieren Sie die zum Lernen verwendeten Parameter. lrs ist die Lernratenänderungsfunktion selbst. mcp ist eine Funktion, die jedes Mal Gewicht spart, wenn ** val_loss ** während des Trainings am kleinsten wird. Modell ist das im vorherigen Abschnitt erstellte Lernmodell.
print(">>Fang an zu lernen")
hist = model.fit(X_TRAIN, y_train,
batch_size=batch_size,
verbose=1,
epochs=nb_epoch,
validation_split=valrate,
callbacks=[lrs, mcp])
Das Lernen erfolgt mit der Funktion fit. Gibt die Daten X_TRAIN, y_train an, die für das Training verwendet werden sollen. batch_size ist die Größe, um die Eingabedaten zusammen zu mitteln, Epochen sind die Anzahl der Wiederholungen des Trainings, variable ist der Prozentsatz der Daten zur Bestätigung der Genauigkeit und Rückrufe sind die während des Trainings verwendeten Funktionen.
json_string = model.to_json()
json_string += '##########' + str(ClassNames)
open('model.json', 'w').write(json_string)
model.save_weights('last.hdf5')
Das Trainingsmodell kann im JSON-Format gespeichert werden. Da es sich bei json um einen Text handelt, fügen Sie den Klassifizierungsnamen des Bildes hinzu und speichern Sie ihn. Gewichte können auch einfach mit save_weights gespeichert werden.
def TestProcess(imgname):
Das Bild wird gelesen und das Lernergebnis wird verwendet, um zu bestimmen, was das Bild ist.
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.Verwenden Sie den Parameter für den geringsten Verlust mit hdf5
img = load_img(imgname, target_size=(hw["height"], hw["width"]))
TEST = img_to_array(img) / 255
Laden Sie Modelldaten und trainierte Gewichtsdaten. Verwenden Sie model_from_json, um das Modell aus dem json-Format zu laden, und load_weights, um die Weight Save-Datei zu laden. Da der Klassifizierungsname zur JSON-Datei hinzugefügt wird, wird das Modell nach dem Teilen geladen. Das Bild wird von load_img geladen, das auch im Vorverarbeitungsabschnitt verwendet wurde. Das Bild wird mit img_to_array quantifiziert.
pred = model.predict(np.array([TEST]), batch_size=1, verbose=0)
print(">>Berechnungsergebnis ↓\n" + str(pred))
print(">>Dieses Bild ist "" + textlist[np.argmax(pred)].replace(",", "") + ""ist.")
Sie können anhand des Lernergebnisses mit der Funktion Vorhersagen berechnen. Das Berechnungsergebnis zeigt die Wahrscheinlichkeit, in jede Klassifizierung eingeteilt zu werden, indem numerische Werte wie [[0.36011574 0.28402892 0.35585538]] angeordnet werden. Mit anderen Worten, die durch die größte Zahl angegebene Klassifizierung ist der Inhalt des Bildes.
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 = ["Kaninchen", "Inu", "Katze"]
hw = {"height":32, "width":32} #Schließen Sie anstelle von Listen in mittlere Klammern vom Typ Wörterbuch ein
################################
######Bilddatenvorverarbeitung######
################################
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"])) #Laden von Bilddateien
array = img_to_array(img) / 255 #Bilddatei numpy
arrlist.append(array) #Fügen Sie der Liste Daten vom Typ Numpy hinzu
for i in range(var_amount-1):
arr2 = array
arr2 = random_rotation(arr2, rg=360)
arrlist.append(arr2) #Fügen Sie der Liste Daten vom Typ Numpy hinzu
num += 1
nplist = np.array(arrlist)
np.save(filename, nplist)
print(">> " + dirname + "Von" + str(num) + "Erfolgreiches Lesen von Dateien")
################################
#########Ein Modell bauen#########
################################
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
################################
#############Lernen#############
################################
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) #Lesen Sie die Numpy-Daten des Bildes
trnum = data.shape[0] - tsnum
X_TRAIN_list += [data[i] for i in range(trnum)] #Bilddaten
Y_TRAIN_list += [target] * trnum #Klassennummer
X_TEST_list += [data[i] for i in range(trnum, trnum+tsnum)] #Bilddaten nicht gelernt
Y_TEST_list += [target] * tsnum; #Klassifikationsnummer nicht zu lernen
target += 1
X_TRAIN = np.array(X_TRAIN_list + X_TEST_list) #Verknüpfen
Y_TRAIN = np.array(Y_TRAIN_list + Y_TEST_list) #Verknüpfen
print(">>Anzahl der Trainingsmuster: ", X_TRAIN.shape)
y_train = np_utils.to_categorical(Y_TRAIN, target) #Konvertieren Sie natürliche Zahlen in Vektoren
valrate = tsnum * target * 1.0 / X_TRAIN.shape[0]
#Änderung der Lernrate
class Schedule(object):
def __init__(self, init=0.001): #Anfangswertdefinition
self.init = init
def __call__(self, epoch): #Aktuelle Wertberechnung
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(">>Fang an zu lernen")
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')
################################
##########Versuch / Versuch##########
################################
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.Verwenden Sie den Parameter für den geringsten Verlust mit 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(">>Berechnungsergebnis ↓\n" + str(pred))
print(">>Dieses Bild ist "" + textlist[np.argmax(pred)].replace(",", "") + ""ist.")
Die Quelle bis zu diesem Punkt wird in einer Datei namens ic_module.py geschrieben und gespeichert. Führen Sie bei Verwendung dieses Moduls in jeder Verarbeitungsstufe den folgenden Code aus.
preprocess.py
import ic_module as ic
import os.path as op
i = 0
for filename in ic.FileNames :
#Geben Sie den Verzeichnisnamen ein
while True :
dirname = input(">>「" + ic.ClassNames[i] + "Verzeichnis mit Bildern:")
if op.isdir(dirname) :
break
print(">>Dieses Verzeichnis existiert nicht!")
#Funktionsausführung
ic.PreProcess(dirname, filename, var_amount=3)
i += 1
Lesen Sie einen Ordner (Verzeichnis). Geben Sie die Verzeichnisse in der Reihenfolge der Klassennamen an, die am Anfang von ic_module geschrieben wurden.
learning.py
import ic_module as ic
#Funktionsausführung
ic.Learning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9)
Verwenden Sie tsnum, um anzugeben, wie viele Blätter aus jeder Klassifizierung für die Genauigkeitsprüfung verwendet werden, und learn_schedule, um anzugeben, um wie viel die Lernrate für jede Epoche gedämpft wird. Sie können auch angeben, wie oft das Lernen mit nb_epoch wiederholt werden soll. Das Folgende ist ein Ausführungsbeispiel.
Verlust bedeutet die Differenz (Verlust) zwischen dem Berechnungsergebnis und dem korrekten Antwortwert, acc bedeutet die Genauigkeit der Bildbeurteilung, und diejenigen mit val_ sind die Ergebnisse, wenn Daten verwendet werden, die nicht für das Training verwendet werden. Je kleiner der val_loss und je größer der val_acc, desto fortgeschrittener ist das Lernen. Ein großer Unterschied zwischen Verlust und val_loss oder acc und val_acc bedeutet ** Überlernen **. Es ist schwer, das loszuwerden ...
testprocess.py
import ic_module as ic
import os.path as op
while True:
while True:
imgname = input("\n>>Bilddatei, die Sie eingeben möchten(Beenden Sie mit "END") : ")
if op.isfile(imgname) or imgname == "END":
break
print(">>Diese Datei existiert nicht!")
if imgname == "END":
break
#Funktionsausführung
ic.TestProcess(imgname)
Wenn Sie ein Bild angeben, wird bestimmt, um welches es sich handelt. Das Folgende ist ein Ausführungsbeispiel. Vergessen Sie nicht den Ordnernamen.
Stapelbeurteilung von Bildern in einem Ordner
"Return np.argmax (pred)" zu TestProcess von ic_module hinzugefügt
import glob
import ic_module as ic
import os.path as op
dirname = "dogs"#input("Ordnernamen:")
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("Die richtige Antwortrate einschließlich Lernen und Nichtlernen" + str(cn2*1.0/cn1) + "ist.")