Dies ist der 4. in der Reihe.
Bisher NN (2.), das den Durchschnittswert und die Standardabweichung von den gegebenen zufälligen numerischen Daten ausgibt und die drei Parameter ausgibt, die zum Erzeugen der Normalverteilungswellenformdaten aus den gegebenen Normalverteilungswellenformdaten verwendet werden. Ich habe NN (3.) erstellt.
Diesmal wird aus den zweidimensionalen Bilddaten, die einen Kreis gezeichnet haben, die Faltung NN (Faltung NN) ausgegeben, die die vier Parameter (x-Koordinate, y-Koordinate, Radius und Stiftliniendicke des Kreismittelpunkts) ausgibt, die zum Zeichnen des Kreises verwendet werden. CNN erstellen).
Die Bilddaten wurden mit Objective-C erstellt.
Erstens ist die Erstellung von Bilddaten. Erstellen Sie ein Bild eines Kreises mit 50 x 50 Pixeln, rufen Sie die Pixeldaten ab und exportieren Sie es in eine Datei mit den vier Parametern, die zum Zeichnen des Kreises verwendet werden. Ein Datenelement besteht aus 2504 Daten, die durch Kommas getrennt sind. Die ersten 2500 sind Zahlen von 0 bis 1, und die restlichen 4 sind x, y, Radius und Linienstärke des Kreismittelpunkts. Trennen Sie die Daten mit einem Zeilenumbruch (\ n).
Ich habe die NSImage-Klasse in Objective-C verwendet, um die Daten zu erstellen.
4-001.c
//Die Bildgröße beträgt 50 x 50 Pixel
//Bestimmen Sie die Mittelkoordinaten, den Radius und die Linienstärke mit Zufallszahlen.
//Der Radius beträgt 5 bis 25
//Die Mittelkoordinaten stellen sicher, dass der Kreis im Bild enthalten ist.
//Die Linienstärke beträgt 0.2 bis 5
#import <Cocoa/Cocoa.h>
-(uint8_t *)pixelDataFromImage(NSImage *image);//main()Prototypdeklaration der in
int main(int argc, const char * argv[]) {
srand((unsigned int)time(NULL));//Zufällige Initialisierung
//Öffnen Sie die Zieldatei
char *fileName = "~/imageLearningData.txt";
FILE *fp = fopen(fileName, "w");
//Erstellen Sie 50.000 Blätter
for(int mmm = 0; mmm < 50000;mmm++){
double radius = (double)rand()/RAND_MAX*20 + 5;
double x = (double)rand()/RAND_MAX*(50 - radius * 2) + radius;
double y = (double)rand()/RAND_MAX*(50 - radius * 2) + radius;
double lineWidth = (double)rand()/RAND_MAX*4.8 + 0.2;
[NSBezierPath setDefaultLineWidth:lineWidth];
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(50, 50)];
NSBezierPath *bezierPath = [NSBezierPath bezierPath];
//Ein Bild zeichnen
[image lockFocus];
[bezierPath appendBezierPathWithOvalInRect:NSMakeRect(x - radius, y - radius, radius * 2, radius * 2)];
[bezierPath stroke];
[image unlockFocus];
uint8_t *pixels = pixelDataFromImage(image);
//Pixeldaten ausgeben
NSSize size = [image size];
uint32_t width = (uint32_t) size.width;
uint32_t height = (uint32_t) size.height;
int components = 4;
for(int iii = 0; iii < height ;iii ++){
for(int kkk = 0; kkk < width ; kkk++){
double value = 0;
value += pixels[( width * iii + kkk )*4 ]/255.0;
value += pixels[( width * iii + kkk )*4 + 1 ]/255.0;
value += pixels[( width * iii + kkk )*4 + 2 ]/255.0;
//Das folgende Gerät reduziert die Größe der Ausgabedatei. "1.Geben Sie "1" anstelle von "0000000" aus.
value /= 3;
if(value == 1){
fprintf(fp,"%d,",1);
}else{
fprintf(fp,"%f,",value);
}
}
}
fprintf(fp,"%f,%f,%f,%f\n",x,y,radius,lineWidth);
free(pixels);
}
fclose(fp);
}
In Bezug auf die Methode pixelDataFromImage im obigen Code habe ich Folgendes vorgenommen, indem ich Code von Mr. Shimapyon @ shimacpyon leicht geändert habe. Vielen Dank, Herr Shimapyon.
4-002.c
-(uint8_t *)pixelDataFromImage(NSImage *image){
/*Erstellen Sie eine Instanz von NSBitmapImageRep*/
NSBitmapImageRep*bitmapRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
/*Wenn Sie als JPEG speichern, entfernen Sie den Alphakanal*/
[bitmapRep setAlpha:NO];
/*Holen Sie sich Qualität für die Lagerung*/
float quality = 1.0;
/*Erstellen Sie eine Eigenschaft*/
NSDictionary* properties = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:quality] forKey:NSImageCompressionFactor];
/*Erstellen Sie JPEG-Daten*/
NSData *data = [bitmapRep representationUsingType:NSJPEGFileType properties:properties];
//Erstellen Sie NSImage erneut aus NSData
NSImage *newImage = [[NSImage alloc] initWithData:data];
if (newImage != nil) {
NSSize size = [newImage size];
uint32_t width = (uint32_t) size.width, height = (uint32_t) size.height, components = 4;
uint8_t *pixels = (uint8_t *) malloc(size.width * size.height * components);//0 bis 255
if (pixels) {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(pixels, width, height, 8, components * width, colorSpace, kCGImageAlphaPremultipliedLast);
NSRect rect = NSMakeRect(0, 0, width, height);
NSGraphicsContext *graphicsContext = (NSGraphicsContext *) [[NSGraphicsContext currentContext] graphicsPort];
CGImageRef cgImage = [newImage CGImageForProposedRect:&rect context:graphicsContext hints:nil];
CGContextDrawImage(bitmapContext, NSRectToCGRect(rect), cgImage);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
return pixels;
}
}
return nil;
}
Es war nicht möglich, Pixeldaten direkt aus NSImage zu extrahieren. Daher habe ich JPEG-Formatdaten (NSData) von NSImage erhalten, darauf basierend NSImage erneut erstellt und Pixeldaten daraus extrahiert. Es mag einen klügeren Weg geben, aber ich würde gerne weitermachen.
Vier erstellte Trainingsdaten (2504 Daten x 50000 Zeilen), d. H.
Teilen in.
4-003.py
import numpy as np
d = np.loadtxt('./imageLearningData.txt', delimiter=',')
#-4:Ist vom 4. bis zum Ende von hinten.
d_training_x = d[:40000,:-4]
d_training_y = d[:40000,-4:]
d_test_x = d[40000:,:-4]
d_test_y = d[40000:,-4:]
#Ändern Sie die Form der Daten
d_training_x = d_training_x.reshape(40000,50,50,1)
d_test_x = d_test_x.reshape(10000,50,50,1)
Entwerfen Sie das CNN. Wir verwenden ein neuronales Faltungsnetzwerk, um ein zweidimensionales Bild zu trainieren. Das Design von CNN wurde entsprechend meiner Intuition angemessen gestaltet. Die folgenden Punkte wurden berücksichtigt.
4-004.py
import keras
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.optimizers import Adam
from keras.layers.core import Dense, Activation, Dropout, Flatten
#Modelldefinition
model = Sequential()
model.add(Conv2D(32,5,input_shape=(50,50,1)))
model.add(Activation('tanh'))
model.add(Conv2D(32,3))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,3))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dense(4, activation='linear'))
adam = Adam(lr=1e-4)
model.compile(optimizer=adam, loss='mean_squared_error', metrics=["accuracy"])
model.summary()
Die Anzahl der Parameter beträgt 6.722.916. Es sieht so aus, als würde es einige Zeit dauern ..... Fang an zu lernen.
4-005.py
batch_size = 128 #128 Daten werden zusammengeworfen
epochs = 20
history = model.fit(d_training_x, d_training_y,
batch_size=batch_size,
epochs=20,
verbose=1,
validation_data=(d_test_x, d_test_y))
Es dauerte 107 Sekunden pro Epoche. Machen Sie ein Diagramm über den Lernfortschritt. Verlust ist der aus den Trainingsdaten berechnete Verlustwert, und val_loss ist der aus den Bewertungsdaten berechnete Verlustwert.
4-006.py
#Zeichnen eines Diagramms
import matplotlib.pyplot as plt
plt.plot(history.history['loss'],label="loss")
plt.plot(history.history['val_loss'],label="val_loss")
plt.legend() #Legende anzeigen
plt.title("Can CNN learn to predict 4 parameters used to draw a circle?")
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.show()
Es sieht so aus, als hättest du gut gelernt.
Wie genau können Sie vorhersagen? Lassen Sie uns die ersten 200 Daten der Auswertungsdaten nach dem Training in das CNN werfen.
4-007.py
inp = d_test_x[:200,:]
out = d_test_y[:200,:]
pred = model.predict(inp, batch_size=1)
#Machen Sie ein Diagramm.
plt.title("Can NN deduce circle parameters?")
plt.scatter(out[:,0], pred[:,0],label = "x",marker='.', s=20,alpha=0.7)
plt.scatter(out[:,1], pred[:,1],label = "y",marker='.', s=20,color="green",alpha=0.7)
plt.scatter(out[:,2], pred[:,2],label = "r",marker='.', s=20,color="red",alpha=0.7)
plt.scatter(out[:,3], pred[:,3],label = "line width",marker='.', s=20,color="black",alpha=0.7)
plt.legend(fontsize=14) #Legende anzeigen
plt.xlabel("expected value")
plt.ylabel("prediction")
#Es ist schwer zu sehen, also x=Die y-Linie wird weggelassen
#x = np.arange(-1, 41, 0.01)
#y = x
#plt.plot(x, y,color="black")
plt.show()
Die horizontale Achse ist der Wert des Parameters, der beim Erstellen der Kreisdaten verwendet wird, und die vertikale Achse ist der Wert, den CNN basierend auf den Bilddaten ausgibt.
Wenn Sie die Linie $ x = y $ von links unten nach rechts oben ziehen, haben Sie erfolgreich ausgegeben.
Es ist nicht perfekt, aber es scheint, dass ich viel gelernt habe. Wird es etwas besser sein, wenn ich die Netzwerkkonfiguration usw. ändere?
Es ist jetzt möglich, als Parameter zum Zeichnen eines Kreises auszugeben, wo und wie groß ein Kreis in einem Bild ist.
Dies ist das Ende der 4. Serie!
Vorbereitung der ersten Serie Serie 2. Durchschnitt und Standardabweichung Serie 3. Normalverteilung Serie 4. Yen
Recommended Posts