C'est le 4e de la série.
Jusqu'à présent, NN (partie 2) qui produit la valeur moyenne et l'écart type des données numériques aléatoires données, et produit les trois paramètres utilisés pour créer les données de forme d'onde de distribution normale à partir des données de forme d'onde de distribution normale données. J'ai créé NN (3e).
Cette fois, à partir des données d'image bidimensionnelles du dessin d'un cercle, la convolution NN (convolution NN (coordonnée x du centre du cercle, coordonnée y, rayon, épaisseur de la ligne de crayon) qui est utilisée pour dessiner le cercle est sortie. Créer CNN).
Les données d'image ont été créées avec Objective-C.
Le premier est la création de données d'image. Créez une image d'un cercle de 50 pixels x 50 pixels, récupérez-y les données de pixels et exportez-la dans un fichier avec les quatre paramètres utilisés pour dessiner le cercle. Un élément de données se compose de 2504 éléments de données séparés par des virgules. Les 2500 premiers sont des nombres de 0 à 1, et les 4 restants sont les x, y, le rayon et l'épaisseur de ligne du centre du cercle. Séparez les données par un saut de ligne (\ n).
J'ai utilisé la classe NSImage en Objective-C pour créer les données.
4-001.c
//La taille de l'image est de 50 pixels x 50 pixels
//Déterminez les coordonnées du centre, le rayon et l'épaisseur de ligne avec des nombres aléatoires.
//Le rayon est de 5 à 25
//Les coordonnées du centre garantissent que le cercle est inclus dans l'image.
//L'épaisseur de la ligne est de 0.2 à 5
#import <Cocoa/Cocoa.h>
-(uint8_t *)pixelDataFromImage(NSImage *image);//main()Déclaration prototype de la fonction utilisée dans
int main(int argc, const char * argv[]) {
srand((unsigned int)time(NULL));//Initialisation aléatoire
//Ouvrez le fichier de destination
char *fileName = "~/imageLearningData.txt";
FILE *fp = fopen(fileName, "w");
//Créer 50 000 feuilles
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];
//Dessiner une image
[image lockFocus];
[bezierPath appendBezierPathWithOvalInRect:NSMakeRect(x - radius, y - radius, radius * 2, radius * 2)];
[bezierPath stroke];
[image unlockFocus];
uint8_t *pixels = pixelDataFromImage(image);
//Données de pixel de sortie
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;
//Ce qui suit est un périphérique pour réduire la taille du fichier de sortie. "1.Sortie "1" au lieu de "0000000".
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);
}
Concernant la méthode pixelDataFromImage dans le code ci-dessus, j'ai fait ce qui suit en modifiant légèrement Code de M. Shimapyon @ shimacpyon. Merci, monsieur Shimapyon.
4-002.c
-(uint8_t *)pixelDataFromImage(NSImage *image){
/*Créer une instance de NSBitmapImageRep*/
NSBitmapImageRep*bitmapRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
/*Si vous enregistrez au format JPEG, supprimez le canal alpha*/
[bitmapRep setAlpha:NO];
/*Obtenez de la qualité pour le stockage*/
float quality = 1.0;
/*Créer une propriété*/
NSDictionary* properties = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:quality] forKey:NSImageCompressionFactor];
/*Créer des données JPEG*/
NSData *data = [bitmapRep representationUsingType:NSJPEGFileType properties:properties];
//Créer à nouveau NSImage à partir de 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 à 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;
}
Il n'était pas possible d'extraire les données de pixels directement de NSImage, j'ai donc obtenu des données au format JPEG (NSData) de NSImage, créé à nouveau NSImage sur cette base et en ai extrait les données de pixels. Il existe peut-être un moyen plus intelligent, mais j'aimerais passer à autre chose.
Quatre données d'entraînement créées (2504 données x 50000 lignes), c'est-à-dire
Diviser en.
4-003.py
import numpy as np
d = np.loadtxt('./imageLearningData.txt', delimiter=',')
#-4:Est du 4e à la fin de l'arrière.
d_training_x = d[:40000,:-4]
d_training_y = d[:40000,-4:]
d_test_x = d[40000:,:-4]
d_test_y = d[40000:,-4:]
#Changer la forme des données
d_training_x = d_training_x.reshape(40000,50,50,1)
d_test_x = d_test_x.reshape(10000,50,50,1)
Concevez le CNN. Nous utilisons un réseau de neurones convolutifs pour former une image bidimensionnelle. La conception de CNN a été conçue de manière appropriée en fonction de mon intuition. Les points suivants ont été pris en considération.
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
#Définition du modèle
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()
Le nombre de paramètres est de 6 722 916. Il semble que cela prendra du temps ..... Commencer à apprendre.
4-005.py
batch_size = 128 #128 données sont réunies
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))
Cela prenait 107 secondes par époque. Faites un graphique de la progression de l'apprentissage. loss est la valeur de perte calculée à partir des données d'apprentissage et val_loss est la valeur de perte calculée à partir des données d'évaluation.
4-006.py
#Dessiner un graphique
import matplotlib.pyplot as plt
plt.plot(history.history['loss'],label="loss")
plt.plot(history.history['val_loss'],label="val_loss")
plt.legend() #Afficher la légende
plt.title("Can CNN learn to predict 4 parameters used to draw a circle?")
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.show()
On dirait que vous avez bien appris.
À quel point pouvez-vous prédire avec précision? Jetons les 200 premières données des données d'évaluation dans le CNN après l'entraînement.
4-007.py
inp = d_test_x[:200,:]
out = d_test_y[:200,:]
pred = model.predict(inp, batch_size=1)
#Faites un graphique.
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) #Afficher la légende
plt.xlabel("expected value")
plt.ylabel("prediction")
#C'est difficile à voir, donc x=La ligne y est omise
#x = np.arange(-1, 41, 0.01)
#y = x
#plt.plot(x, y,color="black")
plt.show()
L'axe horizontal est la valeur du paramètre utilisé lors de la création des données du cercle et l'axe vertical est la valeur sortie par CNN en fonction des données d'image.
Si vous prenez la ligne $ x = y $ tirée du coin inférieur gauche vers le coin supérieur droit, vous avez réussi la sortie.
Ce n'est pas parfait, mais il semble que j'ai beaucoup appris. Est-ce que ce sera un peu mieux si je change la configuration du réseau, etc.?
Il est maintenant possible d'afficher l'emplacement et la taille d'un cercle dans une image en tant que paramètre pour dessiner un cercle.
C'est la fin de la 4ème série!
Série 1ère préparation Moyenne et écart type de la deuxième série Série 3e distribution normale Série 4e yen