Einige Leute haben es bereits mit Qiita versucht, aber es dient auch als eigene Studie. Ich habe versucht, Gitarrenbilder mit CNN (ResNet) zu klassifizieren, also habe ich es dabei versucht, Hier sind einige Dinge, die hilfreich sein können. (Da es nicht zusammengefasst ist, ist es ein wenig schmutzig, aber ich werde auch den Code posten)
Das Gitarrenbild wird durch Schaben erhalten und vorverarbeitet, um das Bild aufzublasen. Durch Feinabstimmung von ResNet, einer CNN-Methode, unter Verwendung aufgeblähter Bilder Ich werde versuchen, maschinelles Lernen zu machen, ohne zu viel Lernkosten auszugeben.
Ich habe die folgenden Modelle ausgewählt, die relativ einfach zu sammeln scheinen.
Das erste ist, Bilder zu sammeln. Dieses Mal habe ich es mit iCrawler gesammelt. Im Allgemeinen werden die meisten von ihnen über die Google-Bildsuche erfasst, jedoch ab dem 12. März 2020 aufgrund von Änderungen der Spezifikationen auf der Google-Seite. Diesmal habe ich Bilder von Bing gesammelt, weil das Tool nicht in Ordnung zu sein scheint.
crawling.py
import os
from icrawler.builtin import BingImageCrawler
searching_words = [
"Fender Stratocaster",
"Fender Telecaster",
"Fender Jazzmaster",
"Fender Jaguar",
"Fender Mustang",
"Gibson LesPaul",
"Gibson SG",
"Gibson FlyingV",
"Gibson ES-335",
"Acoustic guitar"
]
if __name__ == "__main__":
for word in searching_words:
if not os.path.isdir('./searched_image/' + word):
os.makedirs('./searched_image/' + word)
bing_crawler = BingImageCrawler(storage={ 'root_dir': './searched_image/' + word })
bing_crawler.crawl(keyword=word, max_num=1000)
Nach dem Sammeln habe ich manuell Bilder weggelassen, die nicht verwendet werden konnten (solche, die nicht den gesamten Körper der Gitarre zeigen, solche, die Buchstaben enthalten, solche, die Reflexionen wie Hände usw. haben). Infolgedessen konnten wir für jedes Etikett etwa 100 bis 160 Bilder sammeln. (Ich habe max_num = 1000 in der Crawl-Methode angegeben, aber es wurden nur etwa 400 Blätter gesammelt.)
Als nächstes werden wir die gesammelten Bilder vorverarbeiten. Dieses Mal wurde das Bild um 45 ° gedreht und invertiert. Das Ergebnis stieg also 16-mal auf etwa 1600-2000 Bilder für jedes Etikett.
image_preprocessing.py
import os
import glob
from PIL import Image
import numpy as np
from sklearn.model_selection import train_test_split
#Die Größe des zu komprimierenden Bildes
image_size = 224
#Anzahl der Trainingsdaten
traindata = 1000
#Anzahl der Testdaten
testdata = 300
#Ordnernamen eingeben
src_dir = './searched_image'
#Name des Ausgabeordners
dst_dir = './input_guitar_data'
#Markenname zu identifizieren
labels = [
"Fender Stratocaster",
"Fender Telecaster",
"Fender Jazzmaster",
"Fender Jaguar",
"Fender Mustang",
"Gibson LesPaul",
"Gibson SG",
"Gibson FlyingV",
"Gibson ES-335",
"Acoustic guitar"
]
#Bilder laden
for index, label in enumerate(labels):
files =glob.glob("{}/{}/all/*.jpg ".format(src_dir, label))
#Bild konvertierte Daten
X = []
#Etikette
Y = []
for file in files:
#Bild öffnen
img = Image.open(file)
img = img.convert("RGB")
#===================#In Quadrat konvertieren#===================#
width, height = img.size
#Wenn es vertikal lang ist, erweitern Sie es horizontal
if width < height:
result = Image.new(img.mode,(height, height),(255, 255, 255))
result.paste(img, ((height - width) // 2, 0))
#Wenn es horizontal lang ist, erweitern Sie es vertikal
elif width > height:
result = Image.new(img.mode,(width, width),(255, 255, 255))
result.paste(img, (0, (width - height) // 2))
else:
result = img
#Richten Sie die Bildgröße auf 224 x 224 aus
result.resize((image_size, image_size))
data = np.asarray(result)
X.append(data)
Y.append(index)
#===================#Aufgeblasene Daten#===================#
for angle in range(0, 360, 45):
#Drehung
img_r = result.rotate(angle)
data = np.asarray(img_r)
X.append(data)
Y.append(index)
#Umkehren
img_t = img_r.transpose(Image.FLIP_LEFT_RIGHT)
data = np.asarray(img_t)
X.append(data)
Y.append(index)
#Normalisierung(0~255->0~1)
X = np.array(X,dtype='float32') / 255.0
Y = np.array(Y)
#Daten für die Kreuzungsüberprüfung aufteilen
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=testdata, train_size=traindata)
xy = (X_train, X_test, y_train, y_test)
np.save("{}/{}_{}.npy".format(dst_dir, label, index), xy)
Speichern Sie die vorverarbeiteten Ergebnisse in einer npy-Datei für jedes Etikett.
Dieses Mal werde ich versuchen, ResNet zu lernen, eine typische Methode von CNN. Da der PC, den ich besitze, keine NVIDIA-GPU hat, dauert es sehr lange, wenn ich versuche, ihn so zu trainieren, da er nur von der CPU berechnet wird. Lassen Sie uns also den folgenden Code in der GPGPU-Umgebung mit Google Colab ausführen und lernen. Ich tat. (Wie man Colab benutzt, wie man Dateien hochlädt usw. wird weggelassen)
import gc
import keras
from keras.applications.resnet50 import ResNet50
from keras.models import Sequential, Model
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense, Input
from keras.callbacks import EarlyStopping
from keras.utils import np_utils
from keras import optimizers
from sklearn.metrics import confusion_matrix
import numpy as np
import matplotlib.pyplot as plt
#Definition der Klassenbezeichnung
classes = [
"Fender Stratocaster",
"Fender Telecaster",
"Fender Jazzmaster",
"Fender Jaguar",
"Fender Mustang",
"Gibson LesPaul",
"Gibson SG",
"Gibson FlyingV",
"Gibson ES-335",
"Acoustic guitar"
]
num_classes = len(classes)
#Bildgröße zum Laden
ScaleTo = 224
#Definition der Hauptfunktion
def main():
#Trainingsdaten lesen
src_dir = '/content/drive/My Drive/Maschinelles Lernen/input_guitar_data'
train_Xs = []
test_Xs = []
train_ys = []
test_ys = []
for index, class_name in enumerate(classes):
file = "{}/{}_{}.npy".format(src_dir, class_name, index)
#Bringen Sie eine separate Lerndatei mit
train_X, test_X, train_y, test_y = np.load(file, allow_pickle=True)
#Kombinieren Sie Daten zu einem
train_Xs.append(train_X)
test_Xs.append(test_X)
train_ys.append(train_y)
test_ys.append(test_y)
#Kombinieren Sie die kombinierten Daten
X_train = np.concatenate(train_Xs, 0)
X_test = np.concatenate(test_Xs, 0)
y_train = np.concatenate(train_ys, 0)
y_test = np.concatenate(test_ys, 0)
#Etikette
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
#Generierung eines maschinellen Lernmodells
model, history = model_train(X_train, y_train, X_test, y_test)
model_eval(model, X_test, y_test)
#Lernverlauf anzeigen
model_visualization(history)
def model_train(X_train, y_train, X_test, y_test):
#ResNet 50 laden. Einschließen, da keine vollständig verbundene Ebene erforderlich ist_top=False
input_tensor = Input(shape=(ScaleTo, ScaleTo, 3))
resnet50 = ResNet50(include_top=False, weights='imagenet', input_tensor=input_tensor)
#Erstellen einer vollständig verbundenen Ebene
top_model = Sequential()
top_model.add(Flatten(input_shape=resnet50.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(num_classes, activation='softmax'))
#Erstellen Sie ein Modell, indem Sie ResNet50 und eine vollständig verbundene Ebene kombinieren
resnet50_model = Model(input=resnet50.input, output=top_model(resnet50.output))
"""
#Einige Gewichte von ResNet50 wurden behoben
for layer in resnet50_model.layers[:100]:
layer.trainable = False
"""
#Geben Sie eine Klassifizierung für mehrere Klassen an
resnet50_model.compile(loss='categorical_crossentropy',
optimizer=optimizers.SGD(lr=1e-3, momentum=0.9),
metrics=['accuracy'])
resnet50_model.summary()
#Ausführung des Lernens
early_stopping = EarlyStopping(monitor='val_loss', patience=0, verbose=1)
history = resnet50_model.fit(X_train, y_train,
batch_size=75,
epochs=25, validation_data=(X_test, y_test),
callbacks=[early_stopping])
#Modell speichern
resnet50_model.save("/content/drive/My Drive/Maschinelles Lernen/guitar_cnn_resnet50.h5")
return resnet50_model, history
def model_eval(model, X_test, y_test):
scores = model.evaluate(X_test, y_test, verbose=1)
print("test Loss", scores[0])
print("test Accuracy", scores[1])
#Berechnung der Verwirrungsmatrix
predict_classes = model.predict(X_test)
predict_classes = np.argmax(predict_classes, 1)
true_classes = np.argmax(y_test, 1)
print(predict_classes)
print(true_classes)
cmx = confusion_matrix(true_classes, predict_classes)
print(cmx)
#Löschen Sie das Modell, wenn die Inferenz abgeschlossen ist
del model
keras.backend.clear_session() #← Das ist
gc.collect()
def model_visualization(history):
#Grafische Anzeige des Verlustwertes
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#Grafische Anzeige der richtigen Antwortrate
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
if __name__ == "__main__":
main()
Dieses Mal war das Ergebnis von val acc usw. besser, wenn das Gewicht nicht festgelegt wurde, sodass auch das Gewicht jeder Schicht erneut gelernt wird. Im Code werden 100 Epochen trainiert, aber in Wirklichkeit beendete Early Stopping das Lernen in der 5. Epoche.
Das Ergebnis ist wie folgt.
test Loss 0.09369107168481061
test Accuracy 0.9744
Ich werde auch eine Verwirrungsmatrix herausgeben.
[[199 0 1 0 0 0 0 0 0 0]
[ 0 200 0 0 0 0 0 0 0 0]
[ 2 5 191 2 0 0 0 0 0 0]
[ 1 0 11 180 6 0 2 0 0 0]
[ 0 2 0 0 198 0 0 0 0 0]
[ 0 0 0 0 0 288 4 0 6 2]
[ 0 2 0 0 0 0 296 0 2 0]
[ 0 0 0 0 0 0 0 300 0 0]
[ 0 0 0 0 0 0 0 0 300 0]
[ 0 0 0 0 0 0 0 1 0 299]]
Am Ende einer Epoche können Sie sehen, dass das Lernen erheblich fortgeschritten ist.
Ich werde versuchen, auf dem gespeicherten Modell zu schließen. Dieses Mal habe ich versucht, mit Flask, das ich zum ersten Mal berührt habe, eine sehr rudimentäre Webanwendung zu erstellen.
graphing.py
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
def to_graph(image, labels, predicted):
#=======#Plotten und speichern#=======#
fig = plt.figure(figsize=(10.24, 5.12))
fig.subplots_adjust(left=0.2)
#=======#Schreiben Sie ein horizontales Balkendiagramm#=======#
ax1 = fig.add_subplot(1,2,1)
ax1.barh(labels, predicted, color='c', align="center")
ax1.set_yticks(labels)#y-Achsenbeschriftung
ax1.set_xticks([])#Entfernen Sie die Beschriftung der x-Achse
#Schreiben Sie Zahlen in Balkendiagramme
for interval, value in zip(range(0,len(labels)), predicted):
ax1.text(0.02, interval, value, ha='left', va='center')
#=======#Fügen Sie das identifizierte Bild ein#=======#
ax2 = fig.add_subplot(1,2,2)
ax2.imshow(image)
ax2.axis('off')
return fig
def expand_to_square(input_file):
"""Konvertieren Sie ein rechteckiges Bild in ein Quadrat
input_file:Zu konvertierender Dateiname
Rückgabewert:Konvertiertes Bild
"""
img = Image.open(input_file)
img = img.convert("RGB")
width, height = img.size
#Wenn es vertikal lang ist, erweitern Sie es horizontal
if width < height:
result = Image.new(img.mode,(height, height),(255, 255, 255))
result.paste(img, ((height - width) // 2, 0))
#Wenn es horizontal lang ist, erweitern Sie es vertikal
elif width > height:
result = Image.new(img.mode,(width, width),(255, 255, 255))
result.paste(img, (0, (width - height) // 2))
else:
result = img
return result
predict_file.py
predict_file.py
import io
import gc
from flask import Flask, request, redirect, url_for
from flask import flash, render_template, make_response
from keras.models import Sequential, load_model
from keras.applications.resnet50 import decode_predictions
import keras
import numpy as np
from PIL import Image
from matplotlib.backends.backend_agg import FigureCanvasAgg
import graphing
classes = [
"Fender Stratocaster",
"Fender Telecaster",
"Fender Jazzmaster",
"Fender Jaguar",
"Fender Mustang",
"Gibson LesPaul",
"Gibson SG",
"Gibson FlyingV",
"Gibson ES-335",
"Acoustic guitar"
]
num_classes = len(classes)
image_size = 224
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'gif'])
app = Flask(__name__)
def allowed_file(filename):
return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('Keine Datei')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
flash('Keine Datei')
return redirect(request.url)
if file and allowed_file(file.filename):
virtual_output = io.BytesIO()
file.save(virtual_output)
filepath = virtual_output
model = load_model('./cnn_model/guitar_cnn_resnet50.h5')
#Bild in Quadrat konvertieren
image = graphing.expand_to_square(filepath)
image = image.convert('RGB')
#Richten Sie die Bildgröße auf 224 x 224 aus
image = image.resize((image_size, image_size))
#Wechseln Sie von Bild zu Numpy-Array und führen Sie eine Normalisierung durch
data = np.asarray(image) / 255.0
#Erhöhen Sie die Abmessungen des Arrays(3D->4 Dimensionen)
data = np.expand_dims(data, axis=0)
#Machen Sie Schlussfolgerungen mit dem erlernten Modell
result = model.predict(data)[0]
#Zeichnen Sie das Inferenzergebnis und das abgeleitete Bild in einem Diagramm
fig = graphing.to_graph(image, classes, result)
canvas = FigureCanvasAgg(fig)
png_output = io.BytesIO()
canvas.print_png(png_output)
data = png_output.getvalue()
response = make_response(data)
response.headers['Content-Type'] = 'image/png'
response.headers['Content-Length'] = len(data)
#Löschen Sie das Modell, wenn die Inferenz abgeschlossen ist
del model
keras.backend.clear_session()
gc.collect()
return response
return '''
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Laden wir die Datei hoch und beurteilen</title>
</head>
<body>
<h1>Laden Sie die Datei hoch und beurteilen Sie!</h1>
<form method = post enctype = multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
</body>
</html>
'''
Übrigens, wenn Sie das Lernen und Inferenzieren auf Keras viele Male wiederholen, scheinen die Daten im Speicher überzulaufen, und es scheint, dass Sie sie explizit im Code löschen müssen. (Ähnlich auf Colab)
Referenz-URL ↓ Das Problem, dass die Speichernutzung beim wiederholten Lernen mit Keras zunimmt, wurde behoben
Außerdem werde ich den Quellcode der Webanwendung veröffentlichen, die ich tatsächlich erstellt habe. ↓ Guitar Classification Web App
Ich habe es tatsächlich mit meinem eigenen Instrument versucht.
Zuerst vom Jazzmeister Es reagiert auch auf Jaguar, der viele Ähnlichkeiten aufweist. Wenn es sich jedoch um ein anderes Bild handelt, das aus einem anderen Netz stammt, kann es als 99% Jazz Master beurteilt werden, sodass nicht gesagt werden kann, dass die Klassifizierungsgenauigkeit schlecht ist.
Dann Stratocaster Es war mit ziemlicher Sicherheit entschlossen, eine Stratocaster zu sein. Es scheint, dass es kein besonderes Problem gibt, selbst wenn der Kontrast etwas dunkel ist.
Was passiert also, wenn Sie sie bestimmen lassen, welche Basis sie nicht trainiert haben? Ich habe es mit meinem Jazzbass versucht. Es ist nicht unklar, ob es als Mustang beurteilt wird, aber ich bin besorgt, dass die Wahrscheinlichkeit von SG ebenfalls hoch ist. Es scheint, dass der Tsuno-Teil nicht ähnlich ist ...?
Dieses Mal konnten wir durch Feinabstimmung von ResNet, einer Methode von CNN, einen Klassifikator erstellen, der relativ einfach zu erstellen ist, aber eine hohe Genauigkeit aufweist. Einige maschinelle Lernmethoden wie CNN sind jedoch schwer zu erklären, warum die Ergebnisse so waren. Wenn ich also Zeit habe, werde ich in Zukunft Visualisierungsmethoden wie Grad-CAM ausprobieren.
das ist alles.