IMA4 2018/2019 P35 : Différence entre versions
(→Semaine 9) |
(→Documents Rendus) |
||
(202 révisions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 10 : | Ligne 10 : | ||
==Description== | ==Description== | ||
− | L'apprentissage automatique (en anglais machine learning ) est un champ d'étude de l'intelligence artificielle qui se fonde sur des approches statistiques pour donner aux ordinateurs la capacité d' « apprendre » à partir de données, c'est-à-dire d'améliorer leurs performances à résoudre des tâches sans être explicitement programmés pour chacune. Plus largement, cela concerne la conception, l'analyse, le développement et l'implémentation de telles méthodes | + | L'apprentissage automatique (en anglais machine learning ) est un champ d'étude de l'intelligence artificielle qui se fonde sur des approches statistiques pour donner aux ordinateurs la capacité d' « apprendre » à partir de données, c'est-à-dire d'améliorer leurs performances à résoudre des tâches sans être explicitement programmés pour chacune. Plus largement, cela concerne la conception, l'analyse, le développement et l'implémentation de telles méthodes. |
− | + | Dans notre projet, l'apprentissage automatique est appliqué aux robots, en prenant des données personnalisées en entrée et en donnant le comportement d'action du robot en sortie dans le cas correspondant. Nous fournissons un ensemble de données d'entrée / sortie pour le robot. Le robot apprend le jeu d'entrées / sorties pour obtenir le modèle du calcul lui-même. Le robot peut donc utiliser ce modèle pour réaliser une navigation autonome. | |
+ | |||
+ | Nous allons traiter ce projet avec la navigation autonome de robots, qui n'inclut pas le positionnement du robot et n'utilise pas de capteurs pour détecter les obstacles. La taille et la limite (mur) de la carte que nous utilisons sont fixes, mais la position de l'obstacle change. Nous utiliserons des réseaux de neurones pour identifier l'emplacement des obstacles et prévoir l'itinéraire optimal. | ||
==Objectifs== | ==Objectifs== | ||
Ligne 69 : | Ligne 71 : | ||
'''Le robot mobile autonome devra réaliser:''' | '''Le robot mobile autonome devra réaliser:''' | ||
*Générer une trajectoire automatiquement selon le point de départ et la destination par lui-même. | *Générer une trajectoire automatiquement selon le point de départ et la destination par lui-même. | ||
− | |||
'''Phase d'apprentissage''' | '''Phase d'apprentissage''' | ||
*Prise de connaissance de machine learning et familiarisation avec l'environnement Tensorflow. | *Prise de connaissance de machine learning et familiarisation avec l'environnement Tensorflow. | ||
*Prise de connaissance de langage de programmation (Python). | *Prise de connaissance de langage de programmation (Python). | ||
− | |||
*Prise de connaissance du principe d'algorithme dans le domaine de machine learning. | *Prise de connaissance du principe d'algorithme dans le domaine de machine learning. | ||
Ligne 80 : | Ligne 80 : | ||
*Utilisation de Tensorflow. | *Utilisation de Tensorflow. | ||
*Utilisation de Python. | *Utilisation de Python. | ||
− | |||
==Liste des tâches à effectuer== | ==Liste des tâches à effectuer== | ||
*Conception du schéma global des différentes parties : | *Conception du schéma global des différentes parties : | ||
**Apprentissage des logicielles (programmable, robotique) | **Apprentissage des logicielles (programmable, robotique) | ||
− | **Génération de trajectoires avec un | + | **Génération de trajectoires avec un réseau de neurone |
**Exécution de trajectoire | **Exécution de trajectoire | ||
**Validation du modèle | **Validation du modèle | ||
Ligne 225 : | Ligne 224 : | ||
==Semaine 5== | ==Semaine 5== | ||
− | Nous avons décidé notre méthode pour construire notre modèle de machine learning avec l'aide de Monsieur Vincent Coelen. | + | '''Nous avons décidé notre méthode pour construire notre modèle de machine learning avec l'aide de Monsieur Vincent Coelen.''' |
*Nous utilison le simulateur et la manntte pour collecter toutes les données dont nous avons besion. Ils se composent des points de départ, des points de destination et de tous les points de vitesse chaque 0,1 seconde (la frèquence du simulateur = 10Hz). Parce qu'on pilote le robot jusqu'à la destination munuellement, nous devons donc le contrôler artificiellement pour choisir la trajectoire optimale et supprimer les chemins qui sont loin du meilleur. | *Nous utilison le simulateur et la manntte pour collecter toutes les données dont nous avons besion. Ils se composent des points de départ, des points de destination et de tous les points de vitesse chaque 0,1 seconde (la frèquence du simulateur = 10Hz). Parce qu'on pilote le robot jusqu'à la destination munuellement, nous devons donc le contrôler artificiellement pour choisir la trajectoire optimale et supprimer les chemins qui sont loin du meilleur. | ||
− | * | + | *Ensuite, lors de la phase d’entraînement, nous fournissons les trajectoires que nous collectons au réseau de neurones. Grâce à ce processus de formation, le robot peut apprendre à identifier l'emplacement de l'obstacle, tout en apprenant également à prédire la vitesse. Après la modèle est finie, il faut évaluer la fidélité de la modèle. On a décidé d'utiliser l'algorithme du gradient pour augmenter la fidélité petit-à-petit. |
* Enfin, dans la phase d'utilisation, on fournit le point de départ et la destination comme les entrées, et par ailleurs, on aussi donne les premiers 10 points de vitesse pour arriver à la destination comme les entrées. Donc le réseau peut utiliser ces conditions et calculer pour continuer à deplacer pas-à-pas (1 point) jusqu'à la destination. Bien sûr, si nous plus de points comme l'entrée, la précision sera meilleure. Nous avons temporairement fixer à 10 points. Le robot va sûrement s'arrêter pour calculer le point suivant. Mais le temps est très court. Donc on pense qu'on peut le négliger. | * Enfin, dans la phase d'utilisation, on fournit le point de départ et la destination comme les entrées, et par ailleurs, on aussi donne les premiers 10 points de vitesse pour arriver à la destination comme les entrées. Donc le réseau peut utiliser ces conditions et calculer pour continuer à deplacer pas-à-pas (1 point) jusqu'à la destination. Bien sûr, si nous plus de points comme l'entrée, la précision sera meilleure. Nous avons temporairement fixer à 10 points. Le robot va sûrement s'arrêter pour calculer le point suivant. Mais le temps est très court. Donc on pense qu'on peut le négliger. | ||
+ | |||
+ | [[Fichier:schema_principe_phase_utilisation.jpg]] | ||
==Semaine 6-7== | ==Semaine 6-7== | ||
Ligne 270 : | Ligne 271 : | ||
On utilise une manette sans fil pour simuler l'opération du Robotino dans la situation réelle. Quand on a fini une trajectoire, on doit arrêter le simulateur. Et nous devons traiter les données (supprimer les point de départ répétés et les point qui appartiennent au point de destination suivant). | On utilise une manette sans fil pour simuler l'opération du Robotino dans la situation réelle. Quand on a fini une trajectoire, on doit arrêter le simulateur. Et nous devons traiter les données (supprimer les point de départ répétés et les point qui appartiennent au point de destination suivant). | ||
− | Enfin, on doit collecter au moins de | + | Enfin, on doit collecter au moins de 50 groupes de données qui peuvent permettre construire le réseau de neurones. |
==Semaine 8== | ==Semaine 8== | ||
− | + | '''Nous avons commencé de programmer la première partie:''' | |
+ | *lire les données que nous avons déjà collecté, enregistrer dans le tensorflow et définir les groupes d'entraînement et les groupes de test. En fin, on doit réaliser la normalisation des données. | ||
+ | *lire les maps que nous avons déjà collecté. | ||
+ | |||
− | + | '''Lire les données:''' | |
+ | |||
+ | Nous avons utilisé quelques bibliothèques: | ||
import tensorflow as tf | import tensorflow as tf | ||
− | import matplotlib.pyplot as plt # pour dessiner les trajectoires | + | import matplotlib.pyplot as plt '''# pour dessiner les trajectoires''' |
import numpy as np | import numpy as np | ||
− | import pandas as pd # pour qu'on peut utiliser les tableaux | + | import pandas as pd '''# pour qu'on peut utiliser les tableaux''' |
import time | import time | ||
− | + | D'abord, nous avons définit une fonction pour lire des documents: | |
− | |||
− | D'abord, | ||
def load_data(input_file): | def load_data(input_file): | ||
print("Load Data:\n") | print("Load Data:\n") | ||
Ligne 291 : | Ligne 295 : | ||
print(len(dataset)) | print(len(dataset)) | ||
return dataset | return dataset | ||
− | train_targets = [] | + | train_targets = [] '''#Créer un tableau pour entraînement''' |
− | test_targets = [] | + | test_targets = [] '''#Créer un tableau pour test''' |
for n in [15]: | for n in [15]: | ||
− | train_data = dataset[15:, :14] | + | train_data = dataset[15:, :14] |
− | + | test_data = dataset[:15, :14] | |
− | |||
− | |||
train_target = to_categorical(dataset[15:, n], num_classes=4) | train_target = to_categorical(dataset[15:, n], num_classes=4) | ||
− | + | test_target = to_categorical(dataset[:15, n], num_classes=4) '''#4 types de données (point de départ, point de vitesse, point de destination et''' | |
− | + | '''image de carte )''' | |
− | + | test_targets = dataset[15:, 5:] | |
− | + | test_targets = test_targets.astype(int) '''#il faut change le type de label en entier''' | |
− | |||
− | |||
Lorsque différentes caractéristiques sont regroupées, les petites données en valeur absolue sont «consommées» par les méga données en raison de l'expression de la caractéristique elle-même. À ce stade, nous devons extraire "features vector". Normalisation s'assure que chaque caractéristiques est traitée de manière égale par le classificateur. | Lorsque différentes caractéristiques sont regroupées, les petites données en valeur absolue sont «consommées» par les méga données en raison de l'expression de la caractéristique elle-même. À ce stade, nous devons extraire "features vector". Normalisation s'assure que chaque caractéristiques est traitée de manière égale par le classificateur. | ||
Ligne 318 : | Ligne 318 : | ||
return train_data, train_targets, test_data, test_targets | return train_data, train_targets, test_data, test_targets | ||
− | + | Ensuite, il faut transformer la forme txt à la forme csv et l'enregistre: | |
− | |||
− | Ensuite, | ||
def readwrite(input_file,output_file): | def readwrite(input_file,output_file): | ||
data_f=pd.read_csv(input_file,names=['StaX', 'StaY', 'StaA', | data_f=pd.read_csv(input_file,names=['StaX', 'StaY', 'StaA', | ||
Ligne 329 : | Ligne 327 : | ||
'VelX', 'VelY', 'VelA', | 'VelX', 'VelY', 'VelA', | ||
'EndX', 'EndY', 'EndA']].to_csv(output_file, sep=',', header=False,index=False) | 'EndX', 'EndY', 'EndA']].to_csv(output_file, sep=',', header=False,index=False) | ||
+ | |||
+ | def tran_csv(input_file): | ||
+ | pathDir_1 = os.listdir(input_file) | ||
+ | for allDir_1 in pathDir_1: | ||
+ | child = os.path.join('%s\%s' % (input_file, allDir_1)) | ||
+ | print(allDir_1) | ||
+ | print(child) | ||
+ | pathDir_2 = os.listdir(child) | ||
+ | for allDir_2 in pathDir_2: | ||
+ | child_txt = os.path.join('%s\%s' % (child, allDir_2)) | ||
+ | pathDir_3 = os.listdir(child_txt) | ||
+ | for allDir_3 in pathDir_3: | ||
+ | child_txt_2 = os.path.join('%s\%s' % (child_txt, allDir_3)) | ||
+ | if os.path.isfile(child_txt_2) and child_txt_2[-3:] == 'txt': | ||
+ | # print(child_txt_2) | ||
+ | # print(child_txt_2[14:29]) | ||
+ | print(child_txt_2[24:36]) | ||
+ | # read_try() | ||
+ | # readwrite(child_txt_2,'full_data/'+allDir_1+'/data/'+child_txt_2[14:29]+'.csv') | ||
+ | # rw_sta(child_txt_2,'predict/'+allDir_1+'/vel_data/'+child_txt_2[14:29]+'.csv') | ||
+ | readwrite(child_txt_2,'predict_data/'+allDir_1+'/data/'+child_txt_2[24:36]+'.csv') | ||
+ | rw_sta(child_txt_2,'predict_data/'+allDir_1+'/vel_data/'+child_txt_2[24:36]+'.csv') | ||
+ | |||
+ | |||
+ | '''Lire les maps:''' | ||
+ | |||
+ | Définir une fonction pour lire des maps et les ransformer à la forme csv: | ||
+ | def load_image(input_file): | ||
+ | pathDir_1 = os.listdir(input_file) | ||
+ | for allDir_1 in pathDir_1: | ||
+ | child = os.path.join('%s\%s' % (input_file, allDir_1)) | ||
+ | print(allDir_1) | ||
+ | print(child) | ||
+ | pathDir_2 = os.listdir(child) | ||
+ | for allDir_2 in pathDir_2: | ||
+ | child_txt = os.path.join('%s\%s' % (child, allDir_2)) | ||
+ | pathDir_3 = os.listdir(child_txt) | ||
+ | for allDir_3 in pathDir_3: | ||
+ | child_txt_2 = os.path.join('%s\%s' % (child_txt, allDir_3)) | ||
+ | if os.path.isfile(child_txt_2) == False: | ||
+ | # print(os.path.isfile(child_txt)) | ||
+ | # print(child_txt[14:31]) | ||
+ | # print(child_txt) | ||
+ | pathDir_3 = os.listdir(child_txt_2) | ||
+ | # print(len(pathDir_3)) | ||
+ | allDir_3 = pathDir_3[0] | ||
+ | child_images = os.path.join('%s\%s' % (child_txt_2, allDir_3)) | ||
+ | img1 = cv2.imread(child_images, 0) | ||
+ | img1_shape = img1.shape | ||
+ | print(img1_shape) | ||
+ | img_ndarray = img1 | ||
+ | # name = child_images[14:29] | ||
+ | name = child_images[24:36] | ||
+ | print(name) | ||
+ | # numpy.savetxt('full_data/' + allDir_1 + '/images_data/' + str(name) + '.csv', img_ndarray, delimiter = ',') | ||
+ | numpy.savetxt('predict_data/' + allDir_1 + '/images_data/' + str(name) + '.csv', img_ndarray, delimiter = ',') | ||
+ | |||
+ | : | ||
==Semaine 9== | ==Semaine 9== | ||
− | Nous souhaitons réaliser deux fonctions principales: laisser le robot reconnaître les obstacles sur la carte et naviguer une trajectoire correcte. Nous devons donc créer deux réseaux neuronaux pour permettre aux robots d’apprendre ensemble. | + | Nous souhaitons réaliser deux fonctions principales: laisser le robot reconnaître les obstacles sur la carte et naviguer une trajectoire correcte. Nous devons donc créer deux réseaux neuronaux pour permettre aux robots d’apprendre ensemble. Pour identifier les images, nous avons décidé de le mettre en œuvre en utilisant '''un réseau neuronal convolutif(CNN)'''. |
− | |||
− | + | En apprentissage automatique, un réseau de neurones convolutifs ou réseau de neurones à convolution (en anglais CNN ou ConvNet pour Convolutional Neural Networks) est un type de réseau de neurones artificiels acycliques (feed-forward), dans lequel le motif de connexion entre les neurones est inspiré par le cortex visuel des animaux. Les neurones de cette région du cerveau sont arrangés de sorte qu'ils correspondent à des régions qui se chevauchent lors du pavage du champ visuel. Leur fonctionnement est inspiré par les processus biologiques, ils consistent en un empilage multicouche de perceptrons, dont le but est de prétraiter de petites quantités d'informations. Les réseaux neuronaux convolutifs ont de larges applications dans la reconnaissance d'image et vidéo. | |
+ | En bref, utiliser un ordinateur pour reconnaître une image ne permet pas d'identifier complètement une image complexe à la fois, mais divise une image complète en plusieurs petites morceaux, en extrayant les caractéristiques de chaque petite partie (c'est-à-dire, en identifiant chaque petite morceaux), puis combiner les caractéristiques de ces petites morceaux ensemble, et nous pouvons compléter le processus d’image d’identification de la machine. | ||
− | + | https://fr.wikipedia.org/wiki/R%C3%A9seau_neuronal_convolutif | |
− | + | '''Le principe de notre projet que nous avons conçu suivant:''' | |
+ | [[Fichier:conv2.png]] | ||
− | |||
− | + | '''Les programmes principaux:''' | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | Pour | + | Pour la couche du réseau CNN, l'effet multiréseau de couche générale sera meilleur, mais si le nombre de couches est trop nombreux, le coût de calcul est plus élevé. Après réflexion, nous avons décidé de construire 4 couches cachées: |
− | + | class CNN: | |
− | + | @staticmethod | |
− | + | def build(input): | |
− | + | x = Conv2D(32, (3, 3), border_mode='same')(input) #input layer | |
− | + | x = Conv2D(64, (3, 3),strides=(4, 4))(x) #hidden layer1 couche de convolution | |
− | + | x = MaxPooling2D((2, 2))(x) #hidden layer2 couche de pooling | |
− | + | x = Conv2D(32, (3, 3), border_mode='same')(x) #hidden layer3 couche de convolution | |
− | + | x = Conv2D(30, (5, 1), strides=(5, 28), border_mode='same', activation='relu')(x) #hidden layer4 couche de convolution | |
− | + | x = Flatten()(x) #output layer couches entièment connectées | |
− | + | return x | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | ==Semaine 10== | ||
+ | Cette semaine, nous avons continué à construire un autre réseau de neurones. | ||
+ | Pour prévoir des vitesses, nous avons décidé d'utiliser le réseau de neurone '''LSTM(Long Short-Term Memory)''' | ||
+ | [[Fichier:LSTM.jpg]] | ||
+ | Les équations de la dynamique de ce modèle sont les suivantes : | ||
− | + | [[Fichier:lstm2.jpg]] | |
− | + | Le vecteur ct est la mémoire de la cellule LSTM et yt la sortie. L’idée est de contrôler la mémoire à l’image du modèle RAM. On gère la lecture et l’écriture mémoire à l’aide des vecteurs f, i et o. Ce modèle résout les problèmes de calcul numérique évoqués plus haut. Il possède également la puissance de pouvoir apprendre la manière dont il gère ses accès mémoires. En effet Ui, Wi, Uf, Wf, Uo, Wo font partie de ses paramètres. C’est autour de cette idée qu’ont été réalisées les Neural Turing Machines qui apprennent des algorithmes à partir d’états mémoire rencontrés lors d’exécutions. Avec l’avènement des architectures profondes LSTM est très utilisé aujourd’hui dans le cadre de l’apprentissage de séquences et a démontré une grande puissance expérimentale. | |
− | |||
− | + | class LSTMRNN(object): | |
def __init__(self, n_steps, input_size, output_size, cell_size, batch_size): | def __init__(self, n_steps, input_size, output_size, cell_size, batch_size): | ||
self.n_steps = n_steps | self.n_steps = n_steps | ||
Ligne 418 : | Ligne 447 : | ||
self.compute_cost() | self.compute_cost() | ||
with tf.name_scope('train'): | with tf.name_scope('train'): | ||
− | self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost) | + | self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost) |
+ | |||
+ | def add_input_layer(self,): | ||
+ | l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='2_2D') | ||
+ | # (batch*n_step, in_size) | ||
+ | # # Ws (in_size, cell_size) | ||
+ | Ws_in = self._weight_variable([self.input_size, self.cell_size]) | ||
+ | # bs (cell_size, ) | ||
+ | bs_in = self._bias_variable([self.cell_size,]) | ||
+ | # l_in_y = (batch * n_steps, cell_size) | ||
+ | with tf.name_scope('Wx_plus_b'): | ||
+ | l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in | ||
+ | # reshape l_in_y ==> (batch, n_steps, cell_size) | ||
+ | self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='2_3D') | ||
+ | |||
+ | def add_cell(self): | ||
+ | lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True) | ||
+ | with tf.name_scope('initial_state'): | ||
+ | self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32) | ||
+ | self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn( | ||
+ | lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False) | ||
+ | |||
+ | def add_output_layer(self): | ||
+ | # shape = (batch * steps, cell_size) | ||
+ | l_out_x = tf.reshape(self.cell_outputs, [-1, self.cell_size], name='2_2D') | ||
+ | Ws_out = self._weight_variable([self.cell_size, self.output_size]) | ||
+ | bs_out = self._bias_variable([self.output_size, ]) | ||
+ | # shape = (batch * steps, output_size) | ||
+ | with tf.name_scope('Wx_plus_b'): | ||
+ | self.pred = tf.matmul(l_out_x, Ws_out) + bs_out | ||
+ | |||
+ | def compute_cost(self): | ||
+ | losses = tf.contrib.legacy_seq2seq.sequence_loss_by_example( | ||
+ | [tf.reshape(self.pred, [-1], name='reshape_pred')], | ||
+ | [tf.reshape(self.ys, [-1], name='reshape_target')], | ||
+ | [tf.ones([self.batch_size * self.n_steps], dtype=tf.float32)], | ||
+ | average_across_timesteps=True, | ||
+ | softmax_loss_function=self.ms_error, | ||
+ | name='losses' | ||
+ | ) | ||
+ | with tf.name_scope('average_cost'): | ||
+ | self.cost = tf.div( | ||
+ | tf.reduce_sum(losses, name='losses_sum'), | ||
+ | self.batch_size, | ||
+ | name='average_cost') | ||
+ | tf.summary.scalar('cost', self.cost) | ||
+ | |||
+ | @staticmethod | ||
+ | def ms_error(labels, logits): | ||
+ | return tf.square(tf.subtract(labels, logits)) | ||
+ | |||
+ | def _weight_variable(self, shape, name='weights'): | ||
+ | initializer = tf.random_normal_initializer(mean=0., stddev=1.,) | ||
+ | return tf.get_variable(shape=shape, initializer=initializer, name=name) | ||
+ | |||
+ | def _bias_variable(self, shape, name='biases'): | ||
+ | initializer = tf.constant_initializer(0.1) | ||
+ | return tf.get_variable(name=name, shape=shape, initializer=initializer) | ||
+ | |||
+ | De cette façon, nos deux réseaux de neurones ont été construits avec succès. | ||
+ | |||
+ | Nos étapes pour construire nos réseaux de neurones peuvent être simplifiées à la figure suivante: | ||
+ | |||
+ | |||
+ | [[Fichier:lstm+cnn.jpg]] | ||
+ | |||
+ | |||
+ | Après construire nos réseaux de neurones, nous avons utilisé 60*30=1800 différent trajectoire pour entraîné nos réseaux. Malheureusement, le résultat n'est pas très satisfait. | ||
+ | |||
+ | |||
+ | |||
+ | [[Fichier:25.jpg]] | ||
+ | |||
+ | '''la curbe bleue: les vitesse réelles''' | ||
+ | |||
+ | '''la curbe rouge: les vitesse prévues''' | ||
+ | |||
+ | On peut voir, pour la prédiction du point de vitesse,le réseau était très bonne au cours des 6 premières secondes environ, mais après 6 secondes, il existe un écart très large entre la valeur prédite et la valeur réelle. | ||
+ | |||
+ | Nous avons essayé d'utiliser RNN et GRU pour remplacer LSTM, mais le resultat n'est pas beaucoup amélioré. | ||
==Semaine 11== | ==Semaine 11== | ||
− | Nous | + | Nous essayons toujours de résoudre ce problème avec de grosses erreurs. Après avoir discuté avec nos profs, ils ont proposé plusieurs de solutions pour nous: |
− | 1. | + | *1. Dans le réseau 'CNN', lors du processus de transformation des cartes en données, nous convertissons toujours en valeur fixe (0) . en effet, pour la partie sans obstacle, et les données de cette partie peuvent être négligées. Nous pouvons n'enregistrer que des informations sur les obstacles (telles que la position, la taille, la forme) afin d’équilibrer entre les données de la carte et celles du trajectoires. |
− | 2. | + | *2. Il y a peut-être un problème sur la connexion entre les deux réseaux. |
− | 3. | + | *3. La troisième solution est de simplifier la sortie de la modèle : Au debut, on souhaite d'obtenir une séquence des point de vitesse pas-à-pas pour tracer une trajectoire. Mais il a provoqué une erreur de vitesse mauvaise. Donc, on peut-être relie un fil entre la point de départ et la destination. On maintient une vitesse fixe, et chaque fois on just contrôle un peu de l'angle du robot pour naviguer jusqu'à la destination. |
− | .... | + | |
+ | Finalement, nous avons décider de changer la méthode pour connecter entre les deux réseaux. Nous n'utilisons pas de 'reshape' mais nous n'utilisons qu'une liste pour connecter les données des images et les points de départ et les points de destination. Si ça marche pas bien, nous allons effectuer les autres méthodes. | ||
+ | |||
+ | [[Fichier:connexion2.jpg]] | ||
+ | |||
+ | |||
+ | Nous avons modifié la partie de connexion. Ici, c'est un message qui indique que le nombre de données pour représenter la carte est 300, le nombre de données pour chaque (X,Y,A) phase est 100. Donc le nombre de données dan un tableau combiné est 600. | ||
+ | |||
+ | Mais même si nous avons simplifié la méthode pour connecter les deux réseau, nous n'avons pas pouvoir résoudre notre problème. | ||
+ | |||
+ | ==Semaine 12-13 (Vacances)== | ||
+ | |||
+ | Pendant le processus de la modification de nos programmes, nous pensons que l’idée d’utiliser des réseaux de neurones pour prédire la vitesse n’est peut-être pas possible, donc nous avons donc choisi d’abandonner le réseau de RNN. Après avoir recherché de nombreuses informations, nous avons décidé d'utiliser '''DQN''' dans '''l'apprentissage par renforcement''' pour remplacer RNN. | ||
+ | |||
+ | Le nom complet de dqn est '''Deep Q-learning''', il est en réalité une combinaison d'apprentissage en profondeur et d'apprentissage par renforcement. La première chose que nous avons fait est de comprendre ce qu'est q-learning, quelle est la différence entre dqn et q-learning. | ||
+ | |||
+ | La situation consiste en un agent, un ensemble d'états '''S''' et d'actions '''A'''. En réalisant une action '''a ∈ A''', l'agent passe d'un état à un nouvel état. L'exécution d'une action dans un état spécifique fournit à l'agent une récompense (valeur numérique). Le but de l'agent est de maximiser sa récompense totale. Cela est réalisé par apprentissage de l'action optimale pour chaque état. L'action optimale pour chaque état correspond à celle avec la plus grande récompense sur le long terme. Cette récompense est une somme pondérée de l'espérance mathématique des récompenses de chaque étape future à partir de l'état actuel. La pondération de chaque étape peut être '''γΔt''' où '''Δt''' est le délai entre l'étape actuelle et future et '''γ''' un nombre entre 0 et 1 (autrement dit 0<=γ<=1) appelé le facteur d'actualisation. | ||
+ | |||
+ | L'algorithme calcule une fonction de valeur action-état : | ||
+ | '''Q = S * A''' | ||
+ | |||
+ | Avant que l'apprentissage ne débute, la fonction Q est initialisée arbitrairement. Ensuite, à chaque choix d'action, l'agent observe la récompense et le nouvel état (qui dépend de l'état précédent et de l'action actuelle). Ainsi, Q est mis à jour. Le cœur de l'algorithme est une mise à jour de la fonction de valeur. La définition de la fonction de valeur est corrigée à chaque étape de la façon suivante: | ||
+ | |||
+ | [[Fichier:Q.jpg]] | ||
+ | |||
+ | [[Fichier:Q2.PNG]] | ||
+ | |||
+ | La plus grande différence entre Q-learning et DQN est que DQN utilise plutôt un réseau de neurones pour remplacer le tableau Q. Parce que dans notre projet, le robot peut avoir plusieurs actions (haut, bas, gauche et droite). Si nous utilisons la table Q pour enregistrer le statut de chaque action, cette table Q sera inimaginable. | ||
+ | |||
+ | DQN n'utilise pas la table Q pour enregistrer la valeur Q mais utilise le réseau de neurones pour prédire la valeur Q et connaître la trajectoire optimale en mettant à jour en permanence le réseau de neurone. | ||
+ | |||
+ | DQN prédit principalement la trajectoire à travers les trois étapes importante suivantes. | ||
+ | *Experience Replay | ||
+ | *Target Network | ||
+ | *Clipping Rewards | ||
+ | |||
+ | |||
+ | '''Programmes:''' | ||
+ | |||
+ | *''' Créer un réseau de neurone.''' | ||
+ | |||
+ | Comparé au réseau précédent, il n'y a pas de grande différence. Mais cette fois, nous convertissons d'abord la carte en une carte quadrillée en utilisant find_maze_matrix, un total de 16 x 10 grilles, puis convertissons l'image en une matrice, prenons une valeur tous les 20 pixels pour déterminer si la grille est un obstacle, si c'est un obstacle, la grille sera marqué comme 1, sinon 0. Après nous utilisons matrix_to_img pour transmettre notre carte quadrillée à l'entrée de CNN. | ||
+ | et la sortie de CNN est 4 action(up, down, right, left) | ||
+ | def find_maze_matrix(self, input_file): | ||
+ | img1 = cv2.imread(input_file, 0) | ||
+ | print(type(img1)) | ||
+ | print(img1.shape) | ||
+ | r_map = [] | ||
+ | n = 0 | ||
+ | box = None | ||
+ | for i in range(10, 200, 20): | ||
+ | for j in range(10, 320, 20): | ||
+ | print(img1[i, j]) | ||
+ | if img1[i, j] == 0: | ||
+ | box = 1 | ||
+ | else: | ||
+ | box = 0 | ||
+ | r_map.append(box) | ||
+ | n += 1 | ||
+ | print(n) | ||
+ | r_map_matrix = np.array(r_map) | ||
+ | r_map_matrix = r_map_matrix.reshape((10,16)) | ||
+ | # r_map_list = list(r_map_matrix) | ||
+ | print(r_map_matrix) | ||
+ | return r_map_matrix | ||
+ | |||
+ | def matrix_to_img(row,col): | ||
+ | state = copy.deepcopy(maze) | ||
+ | state[row, col] = TMP_VALUE | ||
+ | state = np.reshape(state,newshape=(1, state.shape[0],state.shape[1],1)) | ||
+ | return state | ||
+ | |||
+ | |||
+ | *'''Rechercher l'action''' | ||
+ | |||
+ | def choose_action(self, state): | ||
+ | if np.random.rand() < self.epsilon: | ||
+ | action = random.choice(list(actions.keys())) | ||
+ | action = actions.get(action) | ||
+ | return action | ||
+ | else: | ||
+ | act_values = self.model.predict(state) | ||
+ | action = np.argmax(shuffle(pd.Series(act_values[0]))) | ||
+ | return action | ||
+ | |||
+ | |||
+ | *'''Action d'exécution''' | ||
+ | |||
+ | Obtenir l'état final du jeu, la récompense d'action, l'état suivant et le retour. | ||
+ | |||
+ | '''Les récompenses: si ‘arriver à la destination’, rewards=1; si 'marcher dans des zones sans obstacles', rewards=-0.01; si ‘hors des limites ou collision’, rewards=-1''' | ||
+ | |||
+ | reward_dict = {'reward_0': -1, 'reward_1': -0.01, 'reward_2': 1} | ||
+ | class Environ: | ||
+ | def __init__(self): | ||
+ | pass | ||
+ | '''# Obtenir next_state, reward, done en fonction de current_state et action.''' | ||
+ | def step(self,current_state, action): | ||
+ | '''# état actuel''' | ||
+ | row, col = np.argwhere(current_state == TMP_VALUE)[0,1:3] | ||
+ | done = False | ||
+ | if action == actions.get('up'): | ||
+ | next_state_pos = (row - 1, col) | ||
+ | elif action == actions.get('down'): | ||
+ | next_state_pos = (row + 1, col) | ||
+ | elif action == actions.get('left'): | ||
+ | next_state_pos = (row, col - 1) | ||
+ | else: | ||
+ | next_state_pos = (row, col + 1) | ||
+ | if next_state_pos[0] < 0 or next_state_pos[0] >= maze.shape[0] or next_state_pos[1] < 0 or next_state_pos[1] >= maze.shape[1] \ | ||
+ | or maze[next_state_pos[0], next_state_pos[1]] == 1: | ||
+ | '''#Si hors des limites ou rencontrez des obstacles(1), le robot reste là où il est et ne bouge plus.''' | ||
+ | next_state = copy.deepcopy(current_state) | ||
+ | reward = reward_dict.get('reward_0') | ||
+ | '''#done=True, entrer dans le piège, le jeu est terminée; done=False, faire un pas où il se trouve, obtenir une pénalité, mais le jeu n'est pas encore terminée''' | ||
+ | '''# done = True''' | ||
+ | elif next_state_pos == target_state_pos: # arriver à la destination | ||
+ | next_state = matrix_to_img(target_state_pos[0],target_state_pos[1]) | ||
+ | reward = reward_dict.get('reward_2') | ||
+ | done = True | ||
+ | else: | ||
+ | next_state = matrix_to_img(next_state_pos[0], next_state_pos[1]) | ||
+ | reward = reward_dict.get('reward_1') | ||
+ | return next_state, reward, done | ||
+ | |||
+ | |||
+ | *'''Enregistrer la memoire''' | ||
+ | |||
+ | # Enregistrer current_state, action, reward, next_state, le jeu se termine ou non done | ||
+ | def remember(self,current_state, action, reward, next_state, done): | ||
+ | self.memory.append((current_state, action, reward, next_state, done)) | ||
+ | |||
+ | |||
+ | *'''Experience Replay''' | ||
+ | |||
+ | Un petit lot de données est extrait de manière aléatoire du contenants qui dépose des mémoires (self.memory) en tant qu'échantillon d'apprentissage, et la valeur Q cible est calculée pour entainer le réseau de neurones. | ||
+ | |||
+ | Experience Replay a été proposé à l'origine dans l'apprentissage par renforcement pour les robots utilisant des réseaux de neurones en 1993. DNN surexploite facilement les épisodes actuels. Une fois que DNN est sur-équipé, il est difficile de produire diverses expériences. Pour résoudre ce problème, Experience Replay stocke les expériences, y compris les transitions d'état, les récompenses et les actions, données indispensables à l'apprentissage Q, et crée des mini-lots pour mettre à jour les réseaux de neurones. Cette technique attend les mérites suivants: | ||
+ | *réduit la corrélation entre les expériences de mise à jour de DNN | ||
+ | *augmente la vitesse d'apprentissage avec des mini-lots | ||
+ | *réutilise les transitions passées pour éviter un oubli catastrophique | ||
+ | |||
+ | '''En bref, le rôle le plus important de cette étape consiste à mettre à jour la table Q.''' | ||
+ | |||
+ | Formule de mise à jour de table Q est la suivante: | ||
+ | |||
+ | [[Fichier:q公式.jpg]] | ||
+ | |||
+ | ''''''# Sélectionner au hasard dans le self.memory (current_state, action, reward, next_state, done), puis les mettre dans le modèle pour les entrainer.'''''' | ||
+ | def repay(self, batch_size): | ||
+ | batch_size = min(batch_size, len(self.memory)) | ||
+ | batch_random_choice = np.random.choice(len(self.memory),batch_size) | ||
+ | for i in batch_random_choice: | ||
+ | current_state, action, reward, next_state, done = self.memory[i] | ||
+ | '''# target_f valeur cible''' | ||
+ | target_f = self.model.predict(current_state) | ||
+ | if done: | ||
+ | target = reward | ||
+ | else: | ||
+ | target = reward + self.alpha * (self.gamma * np.max(self.model.predict(next_state)[0]) - target_f[0][action]) | ||
+ | target_f[0][action] = target | ||
+ | self.model.fit(current_state, target_f, nb_epoch=2, verbose=0) | ||
+ | if self.epsilon > self.epsilon_min: | ||
+ | self.epsilon = self.epsilon * self.epsilon_decay | ||
+ | else: | ||
+ | self.epsilon = self.epsilon_min | ||
+ | |||
+ | |||
+ | *'''Entainer le modèle''' | ||
+ | def train(): | ||
+ | '''# Charger le modèle si le modèle existe déjà''' | ||
+ | if os.path.exists(model_name): | ||
+ | agent_model = load_model(model_name) | ||
+ | agent = DQNAgent(agent_model=agent_model) | ||
+ | else: | ||
+ | agent = DQNAgent() | ||
+ | '''# environement''' | ||
+ | environ = Environ() | ||
+ | # fois de itération | ||
+ | episodes = 2000 | ||
+ | for e in range(episodes): | ||
+ | '''# Réinitialiser les paramètres de statut au début de chaque jeu''' | ||
+ | current_state = matrix_to_img(start_state_pos[0],start_state_pos[1]) | ||
+ | i = 0 | ||
+ | while(True): | ||
+ | i = i + 1 | ||
+ | '''# choisir l'action''' | ||
+ | action = agent.choose_action(current_state) | ||
+ | # Appliquer l'action dans l'environnement pour avancer le jeu | ||
+ | next_state, reward, done= environ.step(current_state,action) | ||
+ | '''# Mémoriser l'état précédent, l'action, la valeur de récompense et l'état suivant''' | ||
+ | agent.remember(current_state, action, reward, next_state, done) | ||
+ | if done: | ||
+ | '''# Le jeu se termine, sautez hors de la boucle, entrez la prochaine itération''' | ||
+ | print("episode: {}, step used:{}" .format(e, i)) | ||
+ | break | ||
+ | |||
+ | current_state = copy.deepcopy(next_state) | ||
+ | '''# Former le modèle à travers l'expérience précédente''' | ||
+ | if i % 100 == 0: | ||
+ | agent.repay(100) | ||
+ | '''# Enregistrez le modèle une fois chaque 2000 itérations''' | ||
+ | if (e+1) % 200 == 0: | ||
+ | agent.model.save(model_name) | ||
+ | |||
+ | |||
+ | *'''Vérifier la correction:''' | ||
+ | |||
+ | On envoie une carte, un point de départ et une destination quelconques comme les entrées aux nos réseaux. Après nos réseaux avoir calculé, nous pouvons obtenir une trajectoire prévue. La première image est la carte qu'on a choisit comme l'entrée. La deuxième image est la trajectoire optimale que le simulateur a donnée. La troisième image est la trajectoire que nos réseaux ont prédite. Nous pouvons trouver que la trajectoire prévue est correcte, elle peut bien éviter les obstacles et arriver à la destination. Même si elle est un peu différente que la trajectoire donnée par le simulateur. | ||
+ | |||
+ | [[Fichier:img_1321.jpg]] | ||
+ | |||
+ | Puis, le programme peut enregistrer une séquence de points de vitesse prévue dans une document nommé 'DQN_result': | ||
+ | |||
+ | [[Fichier:Dqn_result.png]] | ||
+ | |||
+ | ==Semaine 14== | ||
+ | Après nous avons concultéavec Monsieur Redon, nous avons convenu qu'il serait plus clair de tracer la trajectoire sur la carte. Donc, cette semaine, notre mission est de combiner la trajectoire et la carte en un seul. | ||
+ | |||
+ | Nous stockons les coordonnées(x, y) de tous les points prévus sur une trajectoire dans les fichiers txt (filename et filenamey). orgina_filex, orgin_filex sont d’indiquer les points de trajectoires donnée par le simulateur. im lit la carte. | ||
+ | posx = load_data(filenamex) | ||
+ | posy = load_data(filenamey) | ||
+ | origin_px = load_data(origin_filex) | ||
+ | origin_py = load_data(origin_filey) | ||
+ | |||
+ | im = Image.open("pos/map_000000001.png") | ||
+ | |||
+ | Pendant le prétraitement des données d’images, la couche de protection sur la carte doit être unifiée : les pixels sont fixés en même valeur (la valeur est 255) afin de supprimer la couche. Ensuite, nous convertissons l'image en matrice d’image, puis nous utilisons des pandas pour la traiter. Les points de position prévus sont marqués, où les pixels représentent différentes couleurs en tant que marques. Lorsque le traitement des marques se termine, nous transformons la matrice d’image en les données de type array. | ||
+ | img = np.array(im) | ||
+ | data = pd.DataFrame(img) #use pandas handle the data | ||
+ | for i in range(0,200): | ||
+ | for j in range(0,320): | ||
+ | if data.at[i,j] != 0: | ||
+ | data.at[i,j] = 255 | ||
+ | origin_color = 128 | ||
+ | predi_color = 192 | ||
+ | for i in range(0,len(origin_px)): | ||
+ | raw = (int(200-(origin_py[i]-0.5)*20))# 0~200 | ||
+ | col = (int((origin_px[i]+7.5)*20))#make - to + 0~320 | ||
+ | data.at[raw,col] = origin_color | ||
+ | for i in range(0,len(posx)): | ||
+ | raw = (int(200-(posy[i]-0.5)*20))# 0~200 | ||
+ | col = (int((posx[i]+7.5)*20))#make - to + 0~320 | ||
+ | data.at[raw,col] = predi_color | ||
+ | print("_____________") | ||
+ | |||
+ | Ensuite, les cartes données par simulateur sont renversées. Donc nous devrions échanger les valeurs au début et à la fin de la matrice pour renverser l’image à normal. | ||
+ | for i in range(0,100): | ||
+ | for j in range(0,320): | ||
+ | d ata.ix[i,j],data.ix[200-1-i,j] = data.ix[200-1-i,j],data.ix[i,j] | ||
+ | |||
+ | Enfin, afin de distinguer les deux trajectoires différentes, nous devons utiliser différentes couleurs pour les représenter. Nous avons utilisé colormap pour les intervalles de pixels différents sont colorés différemment. Nous définissons : la trajectoire prévue est bleu et la trajectoire du simulateur est rouge. | ||
+ | colors = ['black','gray','red','blue','white'] #grad protect red origin blue predi | ||
+ | cmap = matplotlib.colors.ListedColormap(colors,'indexed') | ||
+ | |||
+ | [[Fichier:carte+trajectoire.jpg]] | ||
=Documents Rendus= | =Documents Rendus= | ||
+ | [[Fichier:IMA4_machine_learning_rapport.pdf]] | ||
+ | Lien vers git du script : https://github.com/Lucaslin0517/projet_ima4 |
Version actuelle datée du 9 mai 2019 à 11:41
Sommaire
Présentation générale
Nom du projet : Machine Learning pour navigation autonome de robots mobiles
Résumé : Le but du projet est de permettre le robot trouver un trajectoire optimale
Etudiants : Wenjing CHEN et Puyuan LIN
Description
L'apprentissage automatique (en anglais machine learning ) est un champ d'étude de l'intelligence artificielle qui se fonde sur des approches statistiques pour donner aux ordinateurs la capacité d' « apprendre » à partir de données, c'est-à-dire d'améliorer leurs performances à résoudre des tâches sans être explicitement programmés pour chacune. Plus largement, cela concerne la conception, l'analyse, le développement et l'implémentation de telles méthodes.
Dans notre projet, l'apprentissage automatique est appliqué aux robots, en prenant des données personnalisées en entrée et en donnant le comportement d'action du robot en sortie dans le cas correspondant. Nous fournissons un ensemble de données d'entrée / sortie pour le robot. Le robot apprend le jeu d'entrées / sorties pour obtenir le modèle du calcul lui-même. Le robot peut donc utiliser ce modèle pour réaliser une navigation autonome.
Nous allons traiter ce projet avec la navigation autonome de robots, qui n'inclut pas le positionnement du robot et n'utilise pas de capteurs pour détecter les obstacles. La taille et la limite (mur) de la carte que nous utilisons sont fixes, mais la position de l'obstacle change. Nous utiliserons des réseaux de neurones pour identifier l'emplacement des obstacles et prévoir l'itinéraire optimal.
Objectifs
Dans le but de réaliser notre projet nous devrons remplir les objectifs suivants:
- Nous devons apprendre et utiliser python pour programmer le robot afin de réaliser la fonction de machine learning, afin que le robot puisse trouver le meilleur itinéraire.
- Nous devons apprendre et utiliser TensorFlow pour apprendre le machine learning.
- Nous devons apprendre et utiliser Intel Neural Compute Stick pour calculer nos base de donnée.
Analyse du projet
Positionnement par rapport à l'existant
Il existe actuellement une grande tendance de robots mobiles de navigation autonome, dont certaines utilisent la carte intégrée pour atteindre la destination, tandis que d’autres obtiennent le chemin en avant via le code à barres attaché au sol. Mais pour éviter les obstacles, il s’agit essentiellement de capteurs pour surveiller les obstacles environnants.
Analyse du premier concurrent
Aethon Inc,un fournisseur mondial de robots de transport mobiles autonomes, a été fondé en 2001.Sa technologie principale comprend les robots mobiles automatiques(TUG). Le TUG est un robot mobile autonome et intelligent doté de devenir une phénomène normale dans les hôpitaux car il délivre matériaux et fournitures. TUG livre efficacement des chariots de fournitures là où ils sont nécessaires, y compris les repas, linge de maison, ainsi que l'enlèvement des ordures.Contrairement aux autres robots de navigation autonomes, il utilise des cartes intégrées et une gamme de capteurs embarqués pour la navigation. Les développeurs utilisent des cartes de haute précision des installations hospitalières, puis programment leur agencement, y compris l’utilisation des ascenseurs, l’ouverture automatique des portes, les points de livraison et les stations de recharge. La carte programmée est chargée dans la mémoire du TUG. TUG utilise des cartes embarquées à des fins de guidage et calcule sa position en temps réel à l'aide de l'algorithme d'odométrie breveté d'Aethon. Il utilise des capteurs embarqués pour ajuster les corridors dynamiques et changeants en temps réel, naviguant en toute sécurité autour des personnes et des obstacles, tout en utilisant toujours sa carte intégrée pour le suivi.
Analyse du second concurrent
Amazon Robotics, anciennement Kiva Systems, est une entreprise du Massachusetts qui fabrique des systèmes d'exécution robotiques mobiles. Traditionnellement, les marchandises sont déplacées autour d’un centre de distribution à l’aide d’un système de convoyage ou de machines actionnées par l’homme (comme des chariots élévateurs). Dans l’approche de Kiva, les articles sont stockés sur des unités de stockage portables. Lorsqu'une commande est validée dans le système de base de données Kiva, le logiciel localise le robot mobile le plus proche de l'article et lui ordonne de le récupérer. Les robots mobiles naviguent dans l’entrepôt en suivant une série d’autocollants de codes à barres informatisés posés au sol. Chaque unité d’entraînement est équipée d’un capteur qui l’empêche de se heurter aux autres. Lorsque l'unité d’entraînement arrive à l'endroit objectif, elle glisse sous la nacelle et la soulève du sol grâce à un tire-bouchon. Le robot transporte ensuite la nacelle vers l'opérateur pour prendre les articles.Kiva a deux modèles de robots. Le plus petit modèle mesure environ 2 pieds sur 2,5 pieds et un pied de haut et peut soulever 1 000 livres. Le plus grand modèle peut transporter des palettes et des charges pesant jusqu'à 3 000 livres. La vitesse maximale d'un robot est de 1,3 mètre par seconde. Les robots mobiles sont alimentés par batterie et doivent être rechargés toutes les heures pendant cinq minutes.
https://www.amazonrobotics.com/
Scénario d'usage du produit ou du concept envisagé
- Nos produits sont adaptés à les entreprise logistiques ou les entreprises de commerce électronique. Le robot peut traiter lui-même la commande afin de terminer la livraison des marchandises, en réduisant les coûts de main-d'œuvre et en améliorant l'efficacité.
- Nos produits conviennent également à la gestion des entrepôts de l'entreprise.
- La perspective de cette voiture intelligente peut également être utilisée dans les futures voitures intelligentes. Nous pouvons planifier le point de départ et la destination de la voiture, puis la voiture fonctionne de manière autonome pour éviter les obstacles et atteindre la fin.
Réponse à la question difficile
Est-ce qu'on commence à zéro ou utilise des bibliothèque?
Nous n'avons pas besoin d'écrire le programme entier à partir de zéro. Parce que ce sujet est assez grand, il peut se diviser en plusieurs parties, par exemple la partie de création de la carte d'endroit, la partie de connaissance des obstacles statiques, la partie de détections des gens et des robots, la partie de navigation, etc. C'est difficile pour nous de réaliser tous pour le temps limité. Tout ce que nous devons faire est de réaliser un algorithme de machine learning pour réaliser un seul but, la navigation autonome. Pour les restes, nous pouvons utiliser les code précédent pour apporter des améliorations en fonction de cela.
Est-ce que la mémoire de robot est assez suiffissant pour stocker le base de donnée de machine learning?
La taille de la mémoire de robot n'arrive pas à réaliser nombreux de calcul, nous devons utiliser intel neural compute stick pour calculer et stocker des données.
Préparation du projet
Cahier des charges
Le robot mobile autonome devra réaliser:
- Générer une trajectoire automatiquement selon le point de départ et la destination par lui-même.
Phase d'apprentissage
- Prise de connaissance de machine learning et familiarisation avec l'environnement Tensorflow.
- Prise de connaissance de langage de programmation (Python).
- Prise de connaissance du principe d'algorithme dans le domaine de machine learning.
Techniques Logicielles
- Utilisation de Tensorflow.
- Utilisation de Python.
Liste des tâches à effectuer
- Conception du schéma global des différentes parties :
- Apprentissage des logicielles (programmable, robotique)
- Génération de trajectoires avec un réseau de neurone
- Exécution de trajectoire
- Validation du modèle
Calendrier prévisionnel
Réalisation du Projet
Feuille d'heures
Tâche | Prélude | Heures S1 | Heures S2 | Heures S3 | Heures S4 | Heures S5 + vacance | Heures S6 | Heures S7 | Heures S8 | Heures S9 | Heures S10 | Total |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Analyse du projet | 4 | 4 | 2 | 2 | 1 | 0 | ||||||
Analyse de la structure de donnée d'entrée et sortie | 0 | 0 | 3 | 2 | 1 | 1 | ||||||
Installation du Tensorflow et Python | 0 | 0 | 0 | 0 | 3 | 0 | ||||||
Analyse de la modèle du reseau de neurone | 0 | 0 | 0 | 5 | 0 | 5 | ||||||
Programmation de Tensorflow | 0 | 0 | 0 | 0 | 0 | 4.5 | ||||||
Rédaction du wiki | 3 | 1 | 0.5 | 0.5 | 0.5 | 1 | ||||||
Total de la semaine (heure) | 8 | 5 | 5.5 | 9.5 | 5.5 | 11.5 |
Prologue
Semaine 1
Cette semaine nous avons commencé nos recherches sur machine learning et avons essayé de comprendre le principe de la palteforme «Tensorflow». Nous avons determiné nos prochaines étapes:
- 1.Exploration de données: Connaître la format des données d'entrées et sorties.
- 2.Préparation de données: Transformer des données en format standard(Tous les tableaux entiers sont en même taille.)
- 3.Construire une modèle.
- 4.Former la modèle: Utiliser des échantillons pour la formation.
- 5.Evaluer la modèle: Calculer taux de précision en utilisant l'ensemble du test
Semaine 2
Avec l'aide de Monsieur Vincent Coelen, nous avons déterminé comment collecter des données pour entraîner la modèles de machine learning. On veut utiliser la simulation qu'il fournit la carte virtuelle dont nous avons besoin et le robotino peut s'y déplacer pour simuler l'itinéraire de navigation. Nous utilisons la manette externe pour contrôler le mouvement du robotino. On utilise cette méthode pour collecter des données. Après avoir les données, il faut utiliser l'autre logicielle pour les stocker.
Semaine 3
Cette semaine, nous avons analysé de la structure de la donnée qu'on nous devons collecte. Nous avons décidé de collecter la vitesse de l'abscisse, la vitesse de l'ordonnée et la vitesse angulaire de chaque point sur une trajectoire, afin de pouvoir relier tous les points en une trajectoire entier. En même temps, il faut noter les coordonnées du point de départ et la destination.
Semaine 4
- Initiation au Deep learning. Suivre le lien [1] pour avoir accès à des cours et des travaux pratiques centrés sur l'apprentissage approfondi.
- Pour installer Anaconda : [2]
- Pour installer PyTorch : [3]
- Pour installer Tensorflow : [4]
Semaine 5
Nous avons décidé notre méthode pour construire notre modèle de machine learning avec l'aide de Monsieur Vincent Coelen.
- Nous utilison le simulateur et la manntte pour collecter toutes les données dont nous avons besion. Ils se composent des points de départ, des points de destination et de tous les points de vitesse chaque 0,1 seconde (la frèquence du simulateur = 10Hz). Parce qu'on pilote le robot jusqu'à la destination munuellement, nous devons donc le contrôler artificiellement pour choisir la trajectoire optimale et supprimer les chemins qui sont loin du meilleur.
- Ensuite, lors de la phase d’entraînement, nous fournissons les trajectoires que nous collectons au réseau de neurones. Grâce à ce processus de formation, le robot peut apprendre à identifier l'emplacement de l'obstacle, tout en apprenant également à prédire la vitesse. Après la modèle est finie, il faut évaluer la fidélité de la modèle. On a décidé d'utiliser l'algorithme du gradient pour augmenter la fidélité petit-à-petit.
- Enfin, dans la phase d'utilisation, on fournit le point de départ et la destination comme les entrées, et par ailleurs, on aussi donne les premiers 10 points de vitesse pour arriver à la destination comme les entrées. Donc le réseau peut utiliser ces conditions et calculer pour continuer à deplacer pas-à-pas (1 point) jusqu'à la destination. Bien sûr, si nous plus de points comme l'entrée, la précision sera meilleure. Nous avons temporairement fixer à 10 points. Le robot va sûrement s'arrêter pour calculer le point suivant. Mais le temps est très court. Donc on pense qu'on peut le négliger.
Semaine 6-7
Nous avons commencé la semaine avec un rendez-vous avec notre tuteur afin de faire un compte rendu du simulateur de robotino. On lancer logiciel Rviz et utilise la mannette pour piloter notre robot.La vitesse et la vitesse angulaire à cet instant sont enregistrées automatiquementtoutes toutes les 0,01 secondes. Chaque fois on pilote le robot jusqu'à la destination, la prochaine destination apparaîtra au hasard sur la carte et ensuit on ferme l'acquisition, et toutes les données sur cet itinéraire seront automatiquement enregistrées sous forme de texte, Il faut faire attention que les données de la prochaine destination seront enregistrées aussi à ce moment-là, n'oubliez pas de supprimer. Parce que nous utilisons la mannette pour collecter manuellement des données, nous ne pouvons que contrôler le robot suive l'itinéraire optimal approximatif. Si parfois l'itinéraire que nous empruntons et que les meilleurs itinéraires sont éloignés, nous devons supprimer cette itinéraire inutiles.
Pour réaliser toutes les fonctions, il faut lancer 6 terminaux (droite à gauche).
- Le premier et le deuxième terminal sont d'ouvrir refbox.
dans le 1er terminal: cd refbox/rcll-refbox/ bin/llsf-refbox dans le 2ème terminal: cd refbox/rcll-refbox/ bin/llsf-refbox
- Le troisième terminal est d'ouvrir l'environnement de simulateur et lancer le fichier de simulateur.
roslaunch gazebo_sim_launch env_global.launch sim:=true roslaunch ML_acquisition StartAcquisition.launch
- Le quatrième terminal est d'ouvrir la carte virtuelle dont on a besoin.
rviz load config ~/.rviz/ML_acquisition.rviz
- Le cinquième terminal est de connecter entre PC et la mannette. Et on ne contrôle qu'un robotino (robot 1).
launch the joystick controller roslaunch robotino_teleop joystick_teleop.launch robot:=robotino1
- Le sixième terminal est d'engistrer toutes les données dans un texte.
cd ~/acquisition rosrun ML_acquisition GenerateWaypoints1.py
Quand on ouvre la logicielle rviz, on peut trouver différents types de carte. La première carte simule l'environnement réel. Les rectangles représentent les obstacles. Le cercle représente le Robotino. On peut aussi voir une flèche rouge sur la carte, qui représente le point de destination et sa direction. Alors, il y a l'autre type de la carte. Il nous semble que les obstacles ont les couches épaissies. La fonction de cette couche est d'éviter la collision entre le Robotino et l'obstacle. Parce que l'épaisseur de la couche est supérieure à le rayon du Robotino. On peut aussi trouver que quelques lignes vertes apparaissent sur les obstacles. Ces lignes servent à représenter le contour de l'obstacle mesuré par le capteur de distance. En comparant ces deux types, nous avons finalement choisi le dernier pour collecter des données. Car on n'a pas besoin de s'inquiéter la situation de la collision. Donc, on peut obtenir les données qui est proche de la trajectoire optimale.
On utilise une manette sans fil pour simuler l'opération du Robotino dans la situation réelle. Quand on a fini une trajectoire, on doit arrêter le simulateur. Et nous devons traiter les données (supprimer les point de départ répétés et les point qui appartiennent au point de destination suivant).
Enfin, on doit collecter au moins de 50 groupes de données qui peuvent permettre construire le réseau de neurones.
Semaine 8
Nous avons commencé de programmer la première partie:
- lire les données que nous avons déjà collecté, enregistrer dans le tensorflow et définir les groupes d'entraînement et les groupes de test. En fin, on doit réaliser la normalisation des données.
- lire les maps que nous avons déjà collecté.
Lire les données:
Nous avons utilisé quelques bibliothèques:
import tensorflow as tf import matplotlib.pyplot as plt # pour dessiner les trajectoires import numpy as np import pandas as pd # pour qu'on peut utiliser les tableaux import time
D'abord, nous avons définit une fonction pour lire des documents:
def load_data(input_file): print("Load Data:\n") dataset = np.loadtxt(input_file, delimiter=",") print("Done") print(len(dataset)) return dataset train_targets = [] #Créer un tableau pour entraînement test_targets = [] #Créer un tableau pour test for n in [15]: train_data = dataset[15:, :14] test_data = dataset[:15, :14] train_target = to_categorical(dataset[15:, n], num_classes=4) test_target = to_categorical(dataset[:15, n], num_classes=4) #4 types de données (point de départ, point de vitesse, point de destination et image de carte ) test_targets = dataset[15:, 5:] test_targets = test_targets.astype(int) #il faut change le type de label en entier
Lorsque différentes caractéristiques sont regroupées, les petites données en valeur absolue sont «consommées» par les méga données en raison de l'expression de la caractéristique elle-même. À ce stade, nous devons extraire "features vector". Normalisation s'assure que chaque caractéristiques est traitée de manière égale par le classificateur. Il y a beaucoup de méthode pour normaliser les données. On choisit une méthode classique: scikit-learn (StandardScaler):
mean = train_data.mean(axis=0) train_data -= mean std = train_data.std(axis=0) train_data /= std test_data -= mean test_data /= std train_targets.append(train_target) test_targets.append(test_target) return train_data, train_targets, test_data, test_targets
Ensuite, il faut transformer la forme txt à la forme csv et l'enregistre:
def readwrite(input_file,output_file): data_f=pd.read_csv(input_file,names=['StaX', 'StaY', 'StaA', 'VelX', 'VelY', 'VelA', 'EndX', 'EndY', 'EndA', 'image'],sep=',') print(type(data_f), '\t', data_f.shape) data_f[['StaX', 'StaY', 'StaA', 'VelX', 'VelY', 'VelA', 'EndX', 'EndY', 'EndA']].to_csv(output_file, sep=',', header=False,index=False)
def tran_csv(input_file): pathDir_1 = os.listdir(input_file) for allDir_1 in pathDir_1: child = os.path.join('%s\%s' % (input_file, allDir_1)) print(allDir_1) print(child) pathDir_2 = os.listdir(child) for allDir_2 in pathDir_2: child_txt = os.path.join('%s\%s' % (child, allDir_2)) pathDir_3 = os.listdir(child_txt) for allDir_3 in pathDir_3: child_txt_2 = os.path.join('%s\%s' % (child_txt, allDir_3)) if os.path.isfile(child_txt_2) and child_txt_2[-3:] == 'txt': # print(child_txt_2) # print(child_txt_2[14:29]) print(child_txt_2[24:36]) # read_try() # readwrite(child_txt_2,'full_data/'+allDir_1+'/data/'+child_txt_2[14:29]+'.csv') # rw_sta(child_txt_2,'predict/'+allDir_1+'/vel_data/'+child_txt_2[14:29]+'.csv') readwrite(child_txt_2,'predict_data/'+allDir_1+'/data/'+child_txt_2[24:36]+'.csv') rw_sta(child_txt_2,'predict_data/'+allDir_1+'/vel_data/'+child_txt_2[24:36]+'.csv')
Lire les maps:
Définir une fonction pour lire des maps et les ransformer à la forme csv:
def load_image(input_file): pathDir_1 = os.listdir(input_file) for allDir_1 in pathDir_1: child = os.path.join('%s\%s' % (input_file, allDir_1)) print(allDir_1) print(child) pathDir_2 = os.listdir(child) for allDir_2 in pathDir_2: child_txt = os.path.join('%s\%s' % (child, allDir_2)) pathDir_3 = os.listdir(child_txt) for allDir_3 in pathDir_3: child_txt_2 = os.path.join('%s\%s' % (child_txt, allDir_3)) if os.path.isfile(child_txt_2) == False: # print(os.path.isfile(child_txt)) # print(child_txt[14:31]) # print(child_txt) pathDir_3 = os.listdir(child_txt_2) # print(len(pathDir_3)) allDir_3 = pathDir_3[0] child_images = os.path.join('%s\%s' % (child_txt_2, allDir_3)) img1 = cv2.imread(child_images, 0) img1_shape = img1.shape print(img1_shape) img_ndarray = img1 # name = child_images[14:29] name = child_images[24:36] print(name) # numpy.savetxt('full_data/' + allDir_1 + '/images_data/' + str(name) + '.csv', img_ndarray, delimiter = ',') numpy.savetxt('predict_data/' + allDir_1 + '/images_data/' + str(name) + '.csv', img_ndarray, delimiter = ',')
Semaine 9
Nous souhaitons réaliser deux fonctions principales: laisser le robot reconnaître les obstacles sur la carte et naviguer une trajectoire correcte. Nous devons donc créer deux réseaux neuronaux pour permettre aux robots d’apprendre ensemble. Pour identifier les images, nous avons décidé de le mettre en œuvre en utilisant un réseau neuronal convolutif(CNN).
En apprentissage automatique, un réseau de neurones convolutifs ou réseau de neurones à convolution (en anglais CNN ou ConvNet pour Convolutional Neural Networks) est un type de réseau de neurones artificiels acycliques (feed-forward), dans lequel le motif de connexion entre les neurones est inspiré par le cortex visuel des animaux. Les neurones de cette région du cerveau sont arrangés de sorte qu'ils correspondent à des régions qui se chevauchent lors du pavage du champ visuel. Leur fonctionnement est inspiré par les processus biologiques, ils consistent en un empilage multicouche de perceptrons, dont le but est de prétraiter de petites quantités d'informations. Les réseaux neuronaux convolutifs ont de larges applications dans la reconnaissance d'image et vidéo.
En bref, utiliser un ordinateur pour reconnaître une image ne permet pas d'identifier complètement une image complexe à la fois, mais divise une image complète en plusieurs petites morceaux, en extrayant les caractéristiques de chaque petite partie (c'est-à-dire, en identifiant chaque petite morceaux), puis combiner les caractéristiques de ces petites morceaux ensemble, et nous pouvons compléter le processus d’image d’identification de la machine.
https://fr.wikipedia.org/wiki/R%C3%A9seau_neuronal_convolutif
Le principe de notre projet que nous avons conçu suivant:
Les programmes principaux:
Pour la couche du réseau CNN, l'effet multiréseau de couche générale sera meilleur, mais si le nombre de couches est trop nombreux, le coût de calcul est plus élevé. Après réflexion, nous avons décidé de construire 4 couches cachées:
class CNN: @staticmethod def build(input): x = Conv2D(32, (3, 3), border_mode='same')(input) #input layer x = Conv2D(64, (3, 3),strides=(4, 4))(x) #hidden layer1 couche de convolution x = MaxPooling2D((2, 2))(x) #hidden layer2 couche de pooling x = Conv2D(32, (3, 3), border_mode='same')(x) #hidden layer3 couche de convolution x = Conv2D(30, (5, 1), strides=(5, 28), border_mode='same', activation='relu')(x) #hidden layer4 couche de convolution x = Flatten()(x) #output layer couches entièment connectées return x
Semaine 10
Cette semaine, nous avons continué à construire un autre réseau de neurones.
Pour prévoir des vitesses, nous avons décidé d'utiliser le réseau de neurone LSTM(Long Short-Term Memory)
Les équations de la dynamique de ce modèle sont les suivantes :
Le vecteur ct est la mémoire de la cellule LSTM et yt la sortie. L’idée est de contrôler la mémoire à l’image du modèle RAM. On gère la lecture et l’écriture mémoire à l’aide des vecteurs f, i et o. Ce modèle résout les problèmes de calcul numérique évoqués plus haut. Il possède également la puissance de pouvoir apprendre la manière dont il gère ses accès mémoires. En effet Ui, Wi, Uf, Wf, Uo, Wo font partie de ses paramètres. C’est autour de cette idée qu’ont été réalisées les Neural Turing Machines qui apprennent des algorithmes à partir d’états mémoire rencontrés lors d’exécutions. Avec l’avènement des architectures profondes LSTM est très utilisé aujourd’hui dans le cadre de l’apprentissage de séquences et a démontré une grande puissance expérimentale.
class LSTMRNN(object): def __init__(self, n_steps, input_size, output_size, cell_size, batch_size): self.n_steps = n_steps self.input_size = input_size self.output_size = output_size self.cell_size = cell_size self.batch_size = batch_size with tf.name_scope('inputs'): self.xs = tf.placeholder(tf.float32, [None, n_steps, input_size], name='xs') self.ys = tf.placeholder(tf.float32, [None, n_steps, output_size], name='ys') with tf.variable_scope('in_hidden'): self.add_input_layer() with tf.variable_scope('LSTM_cell'): self.add_cell() with tf.variable_scope('out_hidden'): self.add_output_layer() with tf.name_scope('cost'): self.compute_cost() with tf.name_scope('train'): self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost) def add_input_layer(self,): l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='2_2D') # (batch*n_step, in_size) # # Ws (in_size, cell_size) Ws_in = self._weight_variable([self.input_size, self.cell_size]) # bs (cell_size, ) bs_in = self._bias_variable([self.cell_size,]) # l_in_y = (batch * n_steps, cell_size) with tf.name_scope('Wx_plus_b'): l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in # reshape l_in_y ==> (batch, n_steps, cell_size) self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='2_3D') def add_cell(self): lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True) with tf.name_scope('initial_state'): self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32) self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn( lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False) def add_output_layer(self): # shape = (batch * steps, cell_size) l_out_x = tf.reshape(self.cell_outputs, [-1, self.cell_size], name='2_2D') Ws_out = self._weight_variable([self.cell_size, self.output_size]) bs_out = self._bias_variable([self.output_size, ]) # shape = (batch * steps, output_size) with tf.name_scope('Wx_plus_b'): self.pred = tf.matmul(l_out_x, Ws_out) + bs_out def compute_cost(self): losses = tf.contrib.legacy_seq2seq.sequence_loss_by_example( [tf.reshape(self.pred, [-1], name='reshape_pred')], [tf.reshape(self.ys, [-1], name='reshape_target')], [tf.ones([self.batch_size * self.n_steps], dtype=tf.float32)], average_across_timesteps=True, softmax_loss_function=self.ms_error, name='losses' ) with tf.name_scope('average_cost'): self.cost = tf.div( tf.reduce_sum(losses, name='losses_sum'), self.batch_size, name='average_cost') tf.summary.scalar('cost', self.cost) @staticmethod def ms_error(labels, logits): return tf.square(tf.subtract(labels, logits))
def _weight_variable(self, shape, name='weights'): initializer = tf.random_normal_initializer(mean=0., stddev=1.,) return tf.get_variable(shape=shape, initializer=initializer, name=name) def _bias_variable(self, shape, name='biases'): initializer = tf.constant_initializer(0.1) return tf.get_variable(name=name, shape=shape, initializer=initializer)
De cette façon, nos deux réseaux de neurones ont été construits avec succès.
Nos étapes pour construire nos réseaux de neurones peuvent être simplifiées à la figure suivante:
Après construire nos réseaux de neurones, nous avons utilisé 60*30=1800 différent trajectoire pour entraîné nos réseaux. Malheureusement, le résultat n'est pas très satisfait.
la curbe bleue: les vitesse réelles
la curbe rouge: les vitesse prévues
On peut voir, pour la prédiction du point de vitesse,le réseau était très bonne au cours des 6 premières secondes environ, mais après 6 secondes, il existe un écart très large entre la valeur prédite et la valeur réelle.
Nous avons essayé d'utiliser RNN et GRU pour remplacer LSTM, mais le resultat n'est pas beaucoup amélioré.
Semaine 11
Nous essayons toujours de résoudre ce problème avec de grosses erreurs. Après avoir discuté avec nos profs, ils ont proposé plusieurs de solutions pour nous:
- 1. Dans le réseau 'CNN', lors du processus de transformation des cartes en données, nous convertissons toujours en valeur fixe (0) . en effet, pour la partie sans obstacle, et les données de cette partie peuvent être négligées. Nous pouvons n'enregistrer que des informations sur les obstacles (telles que la position, la taille, la forme) afin d’équilibrer entre les données de la carte et celles du trajectoires.
- 2. Il y a peut-être un problème sur la connexion entre les deux réseaux.
- 3. La troisième solution est de simplifier la sortie de la modèle : Au debut, on souhaite d'obtenir une séquence des point de vitesse pas-à-pas pour tracer une trajectoire. Mais il a provoqué une erreur de vitesse mauvaise. Donc, on peut-être relie un fil entre la point de départ et la destination. On maintient une vitesse fixe, et chaque fois on just contrôle un peu de l'angle du robot pour naviguer jusqu'à la destination.
Finalement, nous avons décider de changer la méthode pour connecter entre les deux réseaux. Nous n'utilisons pas de 'reshape' mais nous n'utilisons qu'une liste pour connecter les données des images et les points de départ et les points de destination. Si ça marche pas bien, nous allons effectuer les autres méthodes.
Nous avons modifié la partie de connexion. Ici, c'est un message qui indique que le nombre de données pour représenter la carte est 300, le nombre de données pour chaque (X,Y,A) phase est 100. Donc le nombre de données dan un tableau combiné est 600.
Mais même si nous avons simplifié la méthode pour connecter les deux réseau, nous n'avons pas pouvoir résoudre notre problème.
Semaine 12-13 (Vacances)
Pendant le processus de la modification de nos programmes, nous pensons que l’idée d’utiliser des réseaux de neurones pour prédire la vitesse n’est peut-être pas possible, donc nous avons donc choisi d’abandonner le réseau de RNN. Après avoir recherché de nombreuses informations, nous avons décidé d'utiliser DQN dans l'apprentissage par renforcement pour remplacer RNN.
Le nom complet de dqn est Deep Q-learning, il est en réalité une combinaison d'apprentissage en profondeur et d'apprentissage par renforcement. La première chose que nous avons fait est de comprendre ce qu'est q-learning, quelle est la différence entre dqn et q-learning.
La situation consiste en un agent, un ensemble d'états S et d'actions A. En réalisant une action a ∈ A, l'agent passe d'un état à un nouvel état. L'exécution d'une action dans un état spécifique fournit à l'agent une récompense (valeur numérique). Le but de l'agent est de maximiser sa récompense totale. Cela est réalisé par apprentissage de l'action optimale pour chaque état. L'action optimale pour chaque état correspond à celle avec la plus grande récompense sur le long terme. Cette récompense est une somme pondérée de l'espérance mathématique des récompenses de chaque étape future à partir de l'état actuel. La pondération de chaque étape peut être γΔt où Δt est le délai entre l'étape actuelle et future et γ un nombre entre 0 et 1 (autrement dit 0<=γ<=1) appelé le facteur d'actualisation.
L'algorithme calcule une fonction de valeur action-état : Q = S * A
Avant que l'apprentissage ne débute, la fonction Q est initialisée arbitrairement. Ensuite, à chaque choix d'action, l'agent observe la récompense et le nouvel état (qui dépend de l'état précédent et de l'action actuelle). Ainsi, Q est mis à jour. Le cœur de l'algorithme est une mise à jour de la fonction de valeur. La définition de la fonction de valeur est corrigée à chaque étape de la façon suivante:
La plus grande différence entre Q-learning et DQN est que DQN utilise plutôt un réseau de neurones pour remplacer le tableau Q. Parce que dans notre projet, le robot peut avoir plusieurs actions (haut, bas, gauche et droite). Si nous utilisons la table Q pour enregistrer le statut de chaque action, cette table Q sera inimaginable.
DQN n'utilise pas la table Q pour enregistrer la valeur Q mais utilise le réseau de neurones pour prédire la valeur Q et connaître la trajectoire optimale en mettant à jour en permanence le réseau de neurone.
DQN prédit principalement la trajectoire à travers les trois étapes importante suivantes.
- Experience Replay
- Target Network
- Clipping Rewards
Programmes:
- Créer un réseau de neurone.
Comparé au réseau précédent, il n'y a pas de grande différence. Mais cette fois, nous convertissons d'abord la carte en une carte quadrillée en utilisant find_maze_matrix, un total de 16 x 10 grilles, puis convertissons l'image en une matrice, prenons une valeur tous les 20 pixels pour déterminer si la grille est un obstacle, si c'est un obstacle, la grille sera marqué comme 1, sinon 0. Après nous utilisons matrix_to_img pour transmettre notre carte quadrillée à l'entrée de CNN. et la sortie de CNN est 4 action(up, down, right, left)
def find_maze_matrix(self, input_file): img1 = cv2.imread(input_file, 0) print(type(img1)) print(img1.shape) r_map = [] n = 0 box = None for i in range(10, 200, 20): for j in range(10, 320, 20): print(img1[i, j]) if img1[i, j] == 0: box = 1 else: box = 0 r_map.append(box) n += 1 print(n) r_map_matrix = np.array(r_map) r_map_matrix = r_map_matrix.reshape((10,16)) # r_map_list = list(r_map_matrix) print(r_map_matrix) return r_map_matrix
def matrix_to_img(row,col): state = copy.deepcopy(maze) state[row, col] = TMP_VALUE state = np.reshape(state,newshape=(1, state.shape[0],state.shape[1],1)) return state
- Rechercher l'action
def choose_action(self, state): if np.random.rand() < self.epsilon: action = random.choice(list(actions.keys())) action = actions.get(action) return action else: act_values = self.model.predict(state) action = np.argmax(shuffle(pd.Series(act_values[0]))) return action
- Action d'exécution
Obtenir l'état final du jeu, la récompense d'action, l'état suivant et le retour.
Les récompenses: si ‘arriver à la destination’, rewards=1; si 'marcher dans des zones sans obstacles', rewards=-0.01; si ‘hors des limites ou collision’, rewards=-1
reward_dict = {'reward_0': -1, 'reward_1': -0.01, 'reward_2': 1} class Environ: def __init__(self): pass # Obtenir next_state, reward, done en fonction de current_state et action. def step(self,current_state, action): # état actuel row, col = np.argwhere(current_state == TMP_VALUE)[0,1:3] done = False if action == actions.get('up'): next_state_pos = (row - 1, col) elif action == actions.get('down'): next_state_pos = (row + 1, col) elif action == actions.get('left'): next_state_pos = (row, col - 1) else: next_state_pos = (row, col + 1) if next_state_pos[0] < 0 or next_state_pos[0] >= maze.shape[0] or next_state_pos[1] < 0 or next_state_pos[1] >= maze.shape[1] \ or maze[next_state_pos[0], next_state_pos[1]] == 1: #Si hors des limites ou rencontrez des obstacles(1), le robot reste là où il est et ne bouge plus. next_state = copy.deepcopy(current_state) reward = reward_dict.get('reward_0') #done=True, entrer dans le piège, le jeu est terminée; done=False, faire un pas où il se trouve, obtenir une pénalité, mais le jeu n'est pas encore terminée # done = True elif next_state_pos == target_state_pos: # arriver à la destination next_state = matrix_to_img(target_state_pos[0],target_state_pos[1]) reward = reward_dict.get('reward_2') done = True else: next_state = matrix_to_img(next_state_pos[0], next_state_pos[1]) reward = reward_dict.get('reward_1') return next_state, reward, done
- Enregistrer la memoire
# Enregistrer current_state, action, reward, next_state, le jeu se termine ou non done def remember(self,current_state, action, reward, next_state, done): self.memory.append((current_state, action, reward, next_state, done))
- Experience Replay
Un petit lot de données est extrait de manière aléatoire du contenants qui dépose des mémoires (self.memory) en tant qu'échantillon d'apprentissage, et la valeur Q cible est calculée pour entainer le réseau de neurones.
Experience Replay a été proposé à l'origine dans l'apprentissage par renforcement pour les robots utilisant des réseaux de neurones en 1993. DNN surexploite facilement les épisodes actuels. Une fois que DNN est sur-équipé, il est difficile de produire diverses expériences. Pour résoudre ce problème, Experience Replay stocke les expériences, y compris les transitions d'état, les récompenses et les actions, données indispensables à l'apprentissage Q, et crée des mini-lots pour mettre à jour les réseaux de neurones. Cette technique attend les mérites suivants:
- réduit la corrélation entre les expériences de mise à jour de DNN
- augmente la vitesse d'apprentissage avec des mini-lots
- réutilise les transitions passées pour éviter un oubli catastrophique
En bref, le rôle le plus important de cette étape consiste à mettre à jour la table Q.
Formule de mise à jour de table Q est la suivante:
'# Sélectionner au hasard dans le self.memory (current_state, action, reward, next_state, done), puis les mettre dans le modèle pour les entrainer.' def repay(self, batch_size): batch_size = min(batch_size, len(self.memory)) batch_random_choice = np.random.choice(len(self.memory),batch_size) for i in batch_random_choice: current_state, action, reward, next_state, done = self.memory[i] # target_f valeur cible target_f = self.model.predict(current_state) if done: target = reward else: target = reward + self.alpha * (self.gamma * np.max(self.model.predict(next_state)[0]) - target_f[0][action]) target_f[0][action] = target self.model.fit(current_state, target_f, nb_epoch=2, verbose=0) if self.epsilon > self.epsilon_min: self.epsilon = self.epsilon * self.epsilon_decay else: self.epsilon = self.epsilon_min
- Entainer le modèle
def train(): # Charger le modèle si le modèle existe déjà if os.path.exists(model_name): agent_model = load_model(model_name) agent = DQNAgent(agent_model=agent_model) else: agent = DQNAgent() # environement environ = Environ() # fois de itération episodes = 2000 for e in range(episodes): # Réinitialiser les paramètres de statut au début de chaque jeu current_state = matrix_to_img(start_state_pos[0],start_state_pos[1]) i = 0 while(True): i = i + 1 # choisir l'action action = agent.choose_action(current_state) # Appliquer l'action dans l'environnement pour avancer le jeu next_state, reward, done= environ.step(current_state,action) # Mémoriser l'état précédent, l'action, la valeur de récompense et l'état suivant agent.remember(current_state, action, reward, next_state, done) if done: # Le jeu se termine, sautez hors de la boucle, entrez la prochaine itération print("episode: {}, step used:{}" .format(e, i)) break
current_state = copy.deepcopy(next_state) # Former le modèle à travers l'expérience précédente if i % 100 == 0: agent.repay(100) # Enregistrez le modèle une fois chaque 2000 itérations if (e+1) % 200 == 0: agent.model.save(model_name)
- Vérifier la correction:
On envoie une carte, un point de départ et une destination quelconques comme les entrées aux nos réseaux. Après nos réseaux avoir calculé, nous pouvons obtenir une trajectoire prévue. La première image est la carte qu'on a choisit comme l'entrée. La deuxième image est la trajectoire optimale que le simulateur a donnée. La troisième image est la trajectoire que nos réseaux ont prédite. Nous pouvons trouver que la trajectoire prévue est correcte, elle peut bien éviter les obstacles et arriver à la destination. Même si elle est un peu différente que la trajectoire donnée par le simulateur.
Puis, le programme peut enregistrer une séquence de points de vitesse prévue dans une document nommé 'DQN_result':
Semaine 14
Après nous avons concultéavec Monsieur Redon, nous avons convenu qu'il serait plus clair de tracer la trajectoire sur la carte. Donc, cette semaine, notre mission est de combiner la trajectoire et la carte en un seul.
Nous stockons les coordonnées(x, y) de tous les points prévus sur une trajectoire dans les fichiers txt (filename et filenamey). orgina_filex, orgin_filex sont d’indiquer les points de trajectoires donnée par le simulateur. im lit la carte.
posx = load_data(filenamex) posy = load_data(filenamey) origin_px = load_data(origin_filex) origin_py = load_data(origin_filey)
im = Image.open("pos/map_000000001.png")
Pendant le prétraitement des données d’images, la couche de protection sur la carte doit être unifiée : les pixels sont fixés en même valeur (la valeur est 255) afin de supprimer la couche. Ensuite, nous convertissons l'image en matrice d’image, puis nous utilisons des pandas pour la traiter. Les points de position prévus sont marqués, où les pixels représentent différentes couleurs en tant que marques. Lorsque le traitement des marques se termine, nous transformons la matrice d’image en les données de type array.
img = np.array(im) data = pd.DataFrame(img) #use pandas handle the data for i in range(0,200): for j in range(0,320): if data.at[i,j] != 0: data.at[i,j] = 255 origin_color = 128 predi_color = 192 for i in range(0,len(origin_px)): raw = (int(200-(origin_py[i]-0.5)*20))# 0~200 col = (int((origin_px[i]+7.5)*20))#make - to + 0~320 data.at[raw,col] = origin_color for i in range(0,len(posx)): raw = (int(200-(posy[i]-0.5)*20))# 0~200 col = (int((posx[i]+7.5)*20))#make - to + 0~320 data.at[raw,col] = predi_color print("_____________")
Ensuite, les cartes données par simulateur sont renversées. Donc nous devrions échanger les valeurs au début et à la fin de la matrice pour renverser l’image à normal.
for i in range(0,100): for j in range(0,320): d ata.ix[i,j],data.ix[200-1-i,j] = data.ix[200-1-i,j],data.ix[i,j]
Enfin, afin de distinguer les deux trajectoires différentes, nous devons utiliser différentes couleurs pour les représenter. Nous avons utilisé colormap pour les intervalles de pixels différents sont colorés différemment. Nous définissons : la trajectoire prévue est bleu et la trajectoire du simulateur est rouge.
colors = ['black','gray','red','blue','white'] #grad protect red origin blue predi cmap = matplotlib.colors.ListedColormap(colors,'indexed')
Documents Rendus
Fichier:IMA4 machine learning rapport.pdf
Lien vers git du script : https://github.com/Lucaslin0517/projet_ima4