« SE5 ECEAI/eceai 2024/2025/wijsman-lefranc » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
Ligne 124 : Ligne 124 :


En effet, si la hauteur de chute était constante, le modèle de machine learning risquerait d'apprendre uniquement à détecter les différences en fonction de l'intensité de l'impact. Cela le rendrait inutile, car notre objectif n'est pas de discriminer sur la base de la force d'impact, mais de différencier deux matériaux différents indépendamment de cette variable.
En effet, si la hauteur de chute était constante, le modèle de machine learning risquerait d'apprendre uniquement à détecter les différences en fonction de l'intensité de l'impact. Cela le rendrait inutile, car notre objectif n'est pas de discriminer sur la base de la force d'impact, mais de différencier deux matériaux différents indépendamment de cette variable.
[[Fichier:Système de percussion.jpg|vignette|378x378px|Un système de percussion par chute d'une masse le long d'un axe gradué]]


* '''Un système de mesure avec des capteurs piézoélectriques.'''
* '''Un système de mesure avec des capteurs piézoélectriques.'''
Ligne 132 : Ligne 129 :
Le système de mesure est équipé de plusieurs capteurs piézoélectriques, ce qui nous offre une plus grande flexibilité lors de l'entraînement du modèle.
Le système de mesure est équipé de plusieurs capteurs piézoélectriques, ce qui nous offre une plus grande flexibilité lors de l'entraînement du modèle.


[[Fichier:Un système de mesure avec des capteurs piézoélectriques.jpg|vignette|Un système de mesure avec des capteurs piézoélectriques]]
 
{| class="wikitable"
|-
! Système de percussion par chute d'une masse le long d'un axe gradué. !! Système de mesure avec des capteurs piézoélectriques
|-
| [[Fichier:Système de percussion.jpg|vignette|378x378px|]]
| [[Fichier:Un système de mesure avec des capteurs piézoélectriques.jpg|vignette|378x378px|Un système de mesure avec des capteurs piézoélectriques]]
|}


== Machine Learning ==
== Machine Learning ==

Version du 30 janvier 2025 à 14:49

Git du projet:

https://gitlab.univ-lille.fr/louis.wijsman.etu/projet-ia-wijsman-lefranc

Séance 1 (09 Sept 2024):

Expérience :

L'objectif de l'expérience est de différencier des essences de bois à partir du spectre d'absorption et du temps de propagation d'un choc dans le bois.

Maquette :

La maquette est constituée de deux capteurs piézoélectriques fixés à une distance \( L \) l'un de l'autre. Une petite masse guidée permet de générer des chocs avec une amplitude variable.

Expérience :

L'expérimentation se fera en faisant varier plusieurs paramètres :

  • Amplitude des chocs
  • Forme de la planche de bois
  • Épaisseur de la planche de bois

Cela permettra de discriminer l'essence du bois.

Séance 2

  • Configuration du Raspberry Pi en Wi-Fi pour permettre la liaison SSH.

Séance 3 (23 Septembre 2024)

  • Le Raspberry Pi peut maintenant communiquer en TCP avec notre serveur VM sur Capbreton.
  • Création du code pour l'acquisition des données via le microcontrôleur.

Communication entre le Raspberry Pi et le serveur (SE5-WIJSMAN-LEFRANC-IA)

VM sur Capbreton : SE5-WIJSMAN-LEFRANC-IA ('172.26.145.111').

Contient un script Python ~/tcp_server/tcp_server.py permettant de récupérer des données depuis le Raspberry Pi.

import socket

# Set up the server IP and port
SERVER_IP = '0.0.0.0'  # Listens on all interfaces
SERVER_PORT = 12345

# Create a TCP socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Bind the socket to the server IP and port
server_socket.bind((SERVER_IP, SERVER_PORT))

# Start listening for incoming connections
server_socket.listen(1)
print(f"Server listening on {SERVER_IP}:{SERVER_PORT}")

while True:
    # Accept a connection
    client_socket, client_address = server_socket.accept()
    print(f"Connection from {client_address}")

    # Receive the message from the client
    message = client_socket.recv(1024).decode('utf-8')
    print(f"Received message: {message}")

    # Optionally, send a response back to the client
    client_socket.send("Message received".encode('utf-8'))

    # Close the connection
    client_socket.close()

Raspbery pi:

Contient un script Python tcp_com/send_data.py qui permet d'envoyer des donees vers la VM

import socket
import json

def send_dict_to_server(server_ip, server_port, data_dict):
    try:
        # Serialize the dictionary to a JSON string
        json_data = json.dumps(data_dict)

        # Create a TCP socket
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # Connect to the server
        client_socket.connect((server_ip, server_port))
        print(f"Connected to server {server_ip}:{server_port}")

        # Send the JSON data to the server
        client_socket.send(json_data.encode('utf-8'))
        print(f"Sent: {json_data}")

        # Receive and print the server's response
        response = client_socket.recv(1024).decode('utf-8')
        print(f"Server response: {response}")

    except Exception as e:
        print(f"Error: {e}")

    finally:
        # Close the connection
        client_socket.close()
        print("Connection closed.")

if __name__ == "__main__":
    # Example dictionary to send
    data = {
        "name": "Raspberry Pi",
        "type": "client",
        "message": "Hello from the Pi!",
        "value": 3
    }

    # Call the function to send the dictionary to the server
    SERVER_IP = '172.26.145.111'  # VM's IP (SE5-WIJSMAN-LEFRANC-IA)
    SERVER_PORT = 12345            # The port the server is listening on
    send_dict_to_server(SERVER_IP, SERVER_PORT, data)

Système de Mesure

Pour effectuer les mesures, nous avons réalisé le montage suivant :

  • Un système de percussion par chute d'une masse le long d'un axe gradué.

Nous utilisons une graduation, car l'objectif est de réaliser des mesures variées en modifiant la force de l'impact (via la hauteur de chute).

En effet, si la hauteur de chute était constante, le modèle de machine learning risquerait d'apprendre uniquement à détecter les différences en fonction de l'intensité de l'impact. Cela le rendrait inutile, car notre objectif n'est pas de discriminer sur la base de la force d'impact, mais de différencier deux matériaux différents indépendamment de cette variable.

  • Un système de mesure avec des capteurs piézoélectriques.

Le système de mesure est équipé de plusieurs capteurs piézoélectriques, ce qui nous offre une plus grande flexibilité lors de l'entraînement du modèle.


Système de percussion par chute d'une masse le long d'un axe gradué. Système de mesure avec des capteurs piézoélectriques
Système de percussion.jpg
Un système de mesure avec des capteurs piézoélectriques

Machine Learning

Tout d'abord, nous récupérons les données d'enregistrement et les convertissons en spectrogrammes, qui sont ensuite mis au format pickle selon la structure suivante :

data = {
    "bin_centers": bin_centers,  # numpy array de taille N
    "bin_averages": bin_averages,  # numpy array de taille N représentant l'intensité pour chaque gamme de fréquence.
    "type": type_of_wood  # booléen indiquant le type de bois (A ou B)
}

On peut observer la présence de l'attribut type. Il s'agit d'un **TAG** utilisé pour entraîner et vérifier le modèle. Ce tag fait référence au type de bois utilisé.


A) Implémentation du modele de Machine Learning

Nous comptons entraîner le modèle sur des spectres fréquentiels obtenus à partir des enregistrements.

En revanche, dans un premier temps, nous n’avons pas encore de données.

Pour pouvoir déjà implémenter et tester le modèle, nous utilisons un script qui génère de fausses données.

Pour générer les données, nous créons deux sinusoïdes à des fréquences différentes, ajoutons du bruit et calculons la FFT.

En sortie, nous obtenons une FFT sur 50 échantillons.

Nous combinons ce tableau NumPy avec un label binaire "type" (True ou False) selon qu'il s'agit d'un type A ou B.

L’ensemble est ensuite sauvegardé sous forme de fichiers pickle, en veillant à ce que 80 % des données soient placées dans train/ et 20 % dans validation/.

Au total, il y a 2 000 données.

Entraînement du modèle :

Pour entraîner le modèle, nous utilisons les données issues de train/.

Le dataloader du modèle est capable de lire les fichiers pickle et de repérer le label "type" (True ou False) afin de superviser l'entraînement du modèle.


Nous effectuons un entraînement de 500 époques et observons que la perte diminue et converge vers 0.

Voici un graphique représentant la perte au fil de l'entraînement :

Loss en fonction des epochs


Une fois le modèle entraîné, nous sauvegardons son état dans un fichier.

Validation du modèle :

Pour la validation, il suffit de charger le modèle à partir du fichier.

Ensuite, nous récupérons les données dans validation/.

Le script itère sur chacune des données, effectue un passage avant (forward pass) du modèle et compare la sortie obtenue avec la sortie attendue contenue dans le fichier pickle.

Cela permet d'obtenir des statistiques de performance.

Résultats :

Dans le cadre des données artificielles, sans surprise, les résultats sont bons.

En effet, nous obtenons :

Résultats de l'évaluation :

Accuracy : 0.9818

Précision : 0.9649

Rappel (Recall) : 1.0000

F1 Score : 0.9821

Matrice de confusion :

[212 8]

[0 220]

On a une précision de 98%.

La matrice de confusion montre qu’il n’y a que 8 faux positifs et 0 faux négatifs sur 400 données de validation !