Commit cfcce20f authored by Olivier REYNET's avatar Olivier REYNET
Browse files

corrections

parent bad1704c
# Objectifs et évaluation --> 18/01/2022
## Objectifs :
1. (obligatoire) Implémenter en C++-20
1. en utilisant la bibliothèque standard,
2. sans utiliser de bibliothèques externes,
3. sur votre machine et sur la cible embarquée (dans notre cas Raspberry Pi 4).
2. (obligatoire) Veiller à donner la preuve que le code fonctionne sur la cible.
3. (obligatoire) Évaluer (et mesurer) les complexités temporelle et mémoire de vos algorithmes.
4. (obligatoire) Vérifier la performance de chaque classificateur embarqué sur les fichiers de test sélectionnés avant l'entraînement afin de les comparer.
5. Programmer une extraction de paramètres en C++ performante :
1. (obligatoire) compléter le fichier au_reading.h afin de [convertir les fichiers AU du dataset en DataVector en C++](https://en.wikipedia.org/wiki/Au_file_format).
2. (obligatoire) efficace dans son exécution (1 Go de données musicales peuvent être traitées en 60 secondes ou moins),
3. minimale en termes de paramètres significatifs générés pour l'apprentissage :
1. (obligatoire) approche STFT,
2. (facultatif) approche MFCC.
6. Programmer des arbres de décision :
1. (obligatoire) générer automatiquement le code C++ à compiler pour exécuter la prise de décision sur la cible depuis le CART Python fourni ou Skearn,
2. (facultatif) proposer une implémentation de CART en C++-20 à partir de celle proposée en Python,
4. (facultatif) proposer une implémentation simple de l'exécution d'une Random Forest en C++-20 en se servant des codes générés automatiquement.
7. Programmer une SVM :
1. (obligatoire) Élaborer une SVM optimale à l'aide de Scikit Learn, à partir des paramètres extraits en C++,
2. (obligatoire) Implémenter la prédiction *un contre un* en C++-20 sur la cible.
8. Programmer un réseau de neurones :
1. (obligatoire) Implémenter un ANN en C++,
2. (facultatif) Implémenter un ANN en C++ en utilisant le paradigme objet,
9. (facultatif) Comparer vos implémentations avec TensorFlow sur Raspberry Pi,
10. (obligatoire) Comparer les approches et faire un tableau synthétique des caractéristiques et des performances de chacune des approches (CART, RF, SVM, ANN).
## Évaluation pour le 18/01/2022 (dépôt Moodle) :
- Rapport au format PDF police 11 de 10 pages maximum qui rend compte précisément de votre travail.
- Le code source (C++/Python/Matlab)
...@@ -57,7 +57,7 @@ void write_csv(std::string filename, ...@@ -57,7 +57,7 @@ void write_csv(std::string filename,
std::map<FTYPE, DataVector> compute_features_for(std::filesystem::path &file_path) { std::map<FTYPE, DataVector> compute_features_for(std::filesystem::path &file_path) {
auto data = readAuFile(file_path.string()); auto data = readAuFile(file_path);
auto features = stft(data); auto features = stft(data);
return features; return features;
} }
...@@ -66,7 +66,7 @@ void compute_set_of_features(std::vector<std::filesystem::path> &files) { ...@@ -66,7 +66,7 @@ void compute_set_of_features(std::vector<std::filesystem::path> &files) {
std::vector<std::pair<std::filesystem::path, std::map<FTYPE, DataVector>>> all_features; std::vector<std::pair<std::filesystem::path, std::map<FTYPE, DataVector>>> all_features;
for (auto file: files) { for (auto file: files) {
std::cout << "Reading --> " << file.filename() << std::endl; std::cout << "Reading --> " << file.filename() << std::endl;
auto data = readAuFile(file.string()); auto data = readAuFile(file);
auto features = stft(data); auto features = stft(data);
all_features.push_back(std::make_pair(file, features)); all_features.push_back(std::make_pair(file, features));
//std::cout << "Training parameters size --> " << features[FTYPE::BINAVG].size() << "x" << features[FTYPE::BINSTDEV].size() << std::endl; //std::cout << "Training parameters size --> " << features[FTYPE::BINAVG].size() << "x" << features[FTYPE::BINSTDEV].size() << std::endl;
......
#ifndef AU_READING_H #ifndef AU_READING_H
#define AU_READING_H #define AU_READING_H
#include "globals.h"
//TODO USE THESE HEADERS ELEMENTS TO READ .AU FILES
//32 bit word (unsigned) field Description/Content Hexadecimal numbers in C notation //32 bit word (unsigned) field Description/Content Hexadecimal numbers in C notation
//0 magic number the value 0x2e736e64 (four ASCII characters ".snd") //0 magic number the value 0x2e736e64 (four ASCII characters ".snd")
//1 data offset the offset to the data in bytes, must be divisible by 8. The minimum valid number is 24 (decimal), since this is the header length (six 32-bit words) with no space reserved for extra information (the annotation field). The minimum valid number with an annotation field present is 32 (decimal). //1 data offset the offset to the data in bytes, must be divisible by 8. The minimum valid number is 24 (decimal), since this is the header length (six 32-bit words) with no space reserved for extra information (the annotation field). The minimum valid number with an annotation field present is 32 (decimal).
...@@ -37,11 +34,10 @@ ...@@ -37,11 +34,10 @@
//5 channels the number of interleaved channels, e.g., 1 for mono, 2 for stereo; more channels possible, but may not be supported by all readers. //5 channels the number of interleaved channels, e.g., 1 for mono, 2 for stereo; more channels possible, but may not be supported by all readers.
DataVector readAuFile(const std::string fileName) { DataVector readAuFile(std::filesystem::path &file_path) {
//TODO DataVector dataVector;
DataVector data; return dataVector;
return data; };
}
#endif //AU_READING_H #endif //AU_READING_H
//
// Created by o on 07/12/2020.
//
#ifndef ETYPES_H #ifndef ETYPES_H
#define ETYPES_H #define ETYPES_H
......
...@@ -44,7 +44,7 @@ select_train_test_files(std::vector<std::filesystem::path> files, double ratio) ...@@ -44,7 +44,7 @@ select_train_test_files(std::vector<std::filesystem::path> files, double ratio)
std::random_device random_device; std::random_device random_device;
//std::mt19937 engine{66}; //std::mt19937 engine{66};
std::mt19937 engine{random_device()}; std::mt19937 engine{random_device()};
std::uniform_int_distribution<int> dist(0, files.size()-1); std::uniform_int_distribution<int> dist(0, files.size() - 1);
std::set<std::filesystem::path> training_files_set; std::set<std::filesystem::path> training_files_set;
std::set<int> indexes; std::set<int> indexes;
for (std::size_t k = 0; k < training_size; k++) { for (std::size_t k = 0; k < training_size; k++) {
...@@ -66,5 +66,4 @@ select_train_test_files(std::vector<std::filesystem::path> files, double ratio) ...@@ -66,5 +66,4 @@ select_train_test_files(std::vector<std::filesystem::path> files, double ratio)
} }
#endif //FILE_HELPERS_H #endif //FILE_HELPERS_H
#ifndef GLOBAL_H #ifndef GLOBAL_H
#define GLOBAL_H #define GLOBAL_H
#include "etypes.h" #include "etypes.h"
constexpr std::size_t N = 512; // WINDOW SIZE constexpr std::size_t N = 512; // WINDOW SIZE
constexpr real Fs = 22050.0; // SAMPLING FREQUENCY constexpr real Fs = 22050.0; // SAMPLING FREQUENCY
const std::size_t FFT_SIZE = N / 2; const std::size_t FFT_SIZE = N / 2;
constexpr std::size_t CLASS_N = 10; // CLASS NUMBER constexpr std::size_t CLASS_N = 10; // CLASS NUMBER
constexpr std::size_t FEAT_N = 512; // FEATURES NUMBER (if AVG and STD) constexpr std::size_t FEAT_N = 512; // FEATURES NUMBER STFT (if AVG and STD)
constexpr std::size_t OVO_CLASS_N = 45; // One Versus One CLASS NUMBER constexpr std::size_t OVO_CLASS_N = CLASS_N * (CLASS_N - 1) / 2; // One Versus One CLASS NUMBER
constexpr std::size_t MEL_N = 26;
constexpr std::size_t MEL_FILTERS_N = MEL_N - 2;
#endif //GLOBAL_H #endif //GLOBAL_H
...@@ -55,6 +55,33 @@ MUSIC_STYLE music_style_from_string(std::string str) { ...@@ -55,6 +55,33 @@ MUSIC_STYLE music_style_from_string(std::string str) {
} }
} }
MUSIC_STYLE music_style_from_int(unsigned int s) {
switch (s) {
case 0:
return MUSIC_STYLE::BLUES;
case 1:
return MUSIC_STYLE::CLASSICAL;
case 2:
return MUSIC_STYLE::COUNTRY;
case 3:
return MUSIC_STYLE::DISCO;
case 4:
return MUSIC_STYLE::HIPHOP;
case 5:
return MUSIC_STYLE::JAZZ;
case 6:
return MUSIC_STYLE::METAL;
case 7:
return MUSIC_STYLE::POP;
case 8:
return MUSIC_STYLE::REGGAE;
case 9:
return MUSIC_STYLE::ROCK;
default:
throw std::logic_error("to_int: MUSIC_STYLE enum values not found.");
}
}
std::ostream &operator<<(std::ostream &os, MUSIC_STYLE music_style) { std::ostream &operator<<(std::ostream &os, MUSIC_STYLE music_style) {
os << music_style_to_string(music_style); os << music_style_to_string(music_style);
return os; return os;
......
//
// Created by o on 12/11/2021.
//
#ifndef EML_MUSIC_STYLE_HELPERS_H #ifndef EML_MUSIC_STYLE_HELPERS_H
#define EML_MUSIC_STYLE_HELPERS_H #define EML_MUSIC_STYLE_HELPERS_H
...@@ -22,6 +18,9 @@ std::string music_style_to_string(const MUSIC_STYLE &s); ...@@ -22,6 +18,9 @@ std::string music_style_to_string(const MUSIC_STYLE &s);
MUSIC_STYLE music_style_from_string(std::string str); MUSIC_STYLE music_style_from_string(std::string str);
MUSIC_STYLE music_style_from_int(unsigned int s);
std::ostream &operator<<(std::ostream &os, MUSIC_STYLE music_style); std::ostream &operator<<(std::ostream &os, MUSIC_STYLE music_style);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <iterator> #include <iterator>
#include "etypes.h" #include "etypes.h"
template<typename T> template<typename T>
std::ostream &operator<<(std::ostream &s, const std::vector<T> &v) { std::ostream &operator<<(std::ostream &s, const std::vector<T> &v) {
s << '['; s << '[';
...@@ -32,4 +33,5 @@ std::ostream &operator<<(std::ostream &s, const std::array<T, SIZE> &a) { ...@@ -32,4 +33,5 @@ std::ostream &operator<<(std::ostream &s, const std::array<T, SIZE> &a) {
} }
return s << ']'; return s << ']';
} }
#endif //PRINT_HELPERS_H #endif //PRINT_HELPERS_H
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#include <vector> #include <vector>
constexpr std::array<Complex, FFT_SIZE> twiddle_factors() { constexpr std::array<Complex, N / 2> twiddle_factors() {
std::array<Complex, FFT_SIZE> t; std::array<Complex, N / 2> t;
for (std::size_t k = 0; k < FFT_SIZE; k++) { for (std::size_t k = 0; k < N / 2; k++) {
t[k] = std::polar(1.0, -2.0 * std::numbers::pi * k / N); t[k] = std::polar(1.0, -2.0 * std::numbers::pi * k / N);
} }
return t; return t;
...@@ -59,6 +59,7 @@ void ite_dit_fft(std::vector<Complex> &x) { ...@@ -59,6 +59,7 @@ void ite_dit_fft(std::vector<Complex> &x) {
std::size_t step = stages - stage; std::size_t step = stages - stage;
std::size_t halfSize = currentSize / 2; std::size_t halfSize = currentSize / 2;
for (std::size_t k = 0; k < problemSize; k = k + currentSize) { for (std::size_t k = 0; k < problemSize; k = k + currentSize) {
//for (std::size_t k = 0; k <= problemSize - currentSize; k = k + currentSize) {
for (std::size_t j = 0; j < halfSize; j++) { for (std::size_t j = 0; j < halfSize; j++) {
auto u = x[k + j]; auto u = x[k + j];
auto v = x[k + j + halfSize] * tf[j * (1 << step)]; auto v = x[k + j + halfSize] * tf[j * (1 << step)];
...@@ -81,11 +82,12 @@ constexpr std::array<real, N> hamming_window() { ...@@ -81,11 +82,12 @@ constexpr std::array<real, N> hamming_window() {
} }
void windowing(const std::array<real, N> &w, std::vector<Complex> &s) { template<typename T>
std::transform(s.begin(), void windowing(const std::array<real, N> &w, std::vector<T> &s) {
s.end(), std::transform(s.cbegin(),
s.cend(),
s.begin(), s.begin(),
[&, index = -1](Complex c)mutable { [&, index = -1](T c)mutable {
index++; index++;
return w[index] * c; return w[index] * c;
}); });
......
...@@ -21,9 +21,7 @@ ...@@ -21,9 +21,7 @@
#include <fstream> #include <fstream>
#include <cstdio> #include <cstdio>
#include <cmath> #include <cmath>
#include <string> #include <string>
#include <iostream>
#include <filesystem> #include <filesystem>
#include <vector> #include <vector>
#include "../global.h" #include "../global.h"
...@@ -209,11 +207,11 @@ void wavFileDetails(const std::string fileName) { ...@@ -209,11 +207,11 @@ void wavFileDetails(const std::string fileName) {
header->data = std::make_shared<chunk>(data_chunk); header->data = std::make_shared<chunk>(data_chunk);
std::cout << "(36-39) Data Marker: " << header->data->fcc << std::endl; std::cout << "(36-39) Data Marker: " << header->data->fcc << std::endl;
std::cout << "(40-43) Size of data : " std::cout << "(40-43) Size of data : "
<< header->data->cb_size << header->data->cb_size
<< " B, " << " B, "
<< header->data->cb_size / (1.0 * (1 << 20)) << header->data->cb_size / (1.0 * (1 << 20))
<< " MiB" << " MiB"
<< std::endl; << std::endl;
// calculate no.of samples // calculate no.of samples
long num_samples = (8 * header->data->cb_size) / (header->fmt_data->channels * header->fmt_data->bits_per_sample); long num_samples = (8 * header->data->cb_size) / (header->fmt_data->channels * header->fmt_data->bits_per_sample);
...@@ -224,12 +222,11 @@ void wavFileDetails(const std::string fileName) { ...@@ -224,12 +222,11 @@ void wavFileDetails(const std::string fileName) {
// calculate duration of file // calculate duration of file
float duration_in_seconds = (float) header->riff->cb_size / header->fmt_data->bytes_rate; float duration_in_seconds = (float) header->riff->cb_size / header->fmt_data->bytes_rate;
std::cout << "Approx.Duration in seconds: " << duration_in_seconds << std::endl; std::cout << "Approx.Duration in seconds: " << duration_in_seconds << std::endl;
fclose(fin); fclose(fin);
} }
std::vector<Complex> readWavFile(const std::string fileName) std::vector<Complex> readWavFile(const std::string fileName) {
{
FILE *fin = fopen(fileName.c_str(), "rb"); FILE *fin = fopen(fileName.c_str(), "rb");
std::ifstream myFile(fileName); std::ifstream myFile(fileName);
std::vector<Complex> data; std::vector<Complex> data;
...@@ -239,10 +236,10 @@ std::vector<Complex> readWavFile(const std::string fileName) ...@@ -239,10 +236,10 @@ std::vector<Complex> readWavFile(const std::string fileName)
// std::cout << data_size << std::endl; // std::cout << data_size << std::endl;
uint8_t lower_bits; uint8_t lower_bits;
uint8_t higher_bits; uint8_t higher_bits;
for (std::size_t k = 0; k < data_size/2; k++){ for (std::size_t k = 0; k < data_size / 2; k++) {
myFile.read(reinterpret_cast<char *>(&higher_bits), sizeof(uint8_t)); myFile.read(reinterpret_cast<char *>(&higher_bits), sizeof(uint8_t));
myFile.read(reinterpret_cast<char *>(&lower_bits), sizeof(uint8_t)); myFile.read(reinterpret_cast<char *>(&lower_bits), sizeof(uint8_t));
data.push_back(static_cast<Complex>((signed short)((higher_bits << 8)+lower_bits))); data.push_back(static_cast<Complex>((signed short) ((higher_bits << 8) + lower_bits)));
} }
myFile.close(); myFile.close();
fclose(fin); fclose(fin);
...@@ -250,7 +247,7 @@ std::vector<Complex> readWavFile(const std::string fileName) ...@@ -250,7 +247,7 @@ std::vector<Complex> readWavFile(const std::string fileName)
} }
void readWavDir(std::string path) { void readWavDir(std::string path) {
for (const auto &entry : fs::directory_iterator(path)) for (const auto &entry: fs::directory_iterator(path))
std::cout << entry.path() << std::endl; std::cout << entry.path() << std::endl;
} }
......
# Programmation des séances
1. Présentation du cours (1h)
2. Extraction des paramètres des fichiers audio (3h) :
- **extraction des données brutes d'un fichier .au**,
- création d'un jeu de paramètres pour l'entrainement des algorithmes :
- **via STFT, moyennage et écart type**,
- via MFCC, moyennage et écart type.
3. Arbre de décision (2h) :
- **élaboration d'un arbre de décision de type CART** (Python brut et sklearn),
- **génération automatique du code de prise de décision en C++**,
- **programmation et test de la prédiction sur la cible**.
- extension de la solution aux Random Forests.
4. Séparateur à Vaste Marge (SVM) (3h) :
- **élaboration du classificateur**,
- **extraction des coefficients d'un classificateur optimal**,
- **programmation et test de la prédiction sur la cible**.
5. Réseaux de neurones (ANN) (3h)
- **élaboration du classificateur**,
- **programmation et test de la prédiction sur la cible**.
6. Améliorations, optimisation et mesure des performances (4h)
- **mesure et comparaisons des performances obtenues en terme de temps d'exécution, d'espace mémoire statique et dynamique nécessaire**,
- **analyse des résultats et conclusion**,
- MFCC plutôt que STFT pour limiter le nombre de paramètres d'entrée,
- Implémentation de la prédiction via Random Forest en C++,
- Utiliser le paradigme objet pour programmer les réseaux de neurones en C++ d'une manière générique,
- Programmer sur la cible en utilisant le moteur TensorFlow Light.
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
Ce projet GitLab est la base du code que vous devez rendre sur Moodle. Il faut en respecter l'esprit et l'organisation. Ce projet GitLab est la base du code que vous devez rendre sur Moodle. Il faut en respecter l'esprit et l'organisation.
# Embarquer la prédiction issue de l'apprentissage automatique ? # Embarquer la prédiction issue de l'apprentissage automatique ?
L'idée fondamentale de ce cours est de poser la problématique L'idée fondamentale de ce cours est de poser la problématique
...@@ -135,61 +134,3 @@ Ils seront automatiquement inscrits dans le fichier généré par write_csv. ...@@ -135,61 +134,3 @@ Ils seront automatiquement inscrits dans le fichier généré par write_csv.
- ANN : élaborer un réseau de neurones artificiel optimal, implémenter le réseau en C++ pour prédire sur la cible. - ANN : élaborer un réseau de neurones artificiel optimal, implémenter le réseau en C++ pour prédire sur la cible.
# Objectifs et évaluation --> 18/01/2022
## Programmation des séances
- Présentation du cours (1h)
- Extraction des paramètres via STFT (3h) pour utilisation avec tous les algorithmes suivants.
- Arbre de décision (2h) :
- élaboration d'un arbre de décision de type CART (Python brut et sklearn),
- génération automatique du code de prise de décision en C++,
- programmation sur la cible,
- tests sur la cible.
- Séparateur à Vaste Marge (SVM) (3h) :
- élaboration du classificateur,
- extraction des coefficients,
- programmation de la prédiction sur la cible,
- tests sur la cible.
- Réseaux de neurones (ANN) (3h)
- élaboration du classificateur,
- programmation de la prédiction sur la cible,
- tests sur la cible.
- Améliorations (4h)
- MFCC plutôt que STFT pour limiter le nombre de paramètres d'entrée,
- Implémentation de la prédiction via Random Forest en C++.
- Utiliser le paradigme objet pour programmer les réseaux de neurones en C++.
- Programmer sur la cible en utilisant le moteur TensorFlow Light.
## Objectifs :
1. (obligatoire) Implémenter en C++-20
1. en utilisant la bibliothèque standard
2. sans utiliser de bibliothèques externes
3. sur votre machine et sur la cible embarquée (dans notre cas Raspberry Pi 4).
2. (obligatoire) Veiller à donner la preuve que le code fonctionne sur la cible.
3. (obligatoire) Évaluer (et mesurer) les complexités temporelle et mémoire de vos algorithmes.
4. (obligatoire) Vérifier la performance de chaque classificateur embarqué sur les fichiers de test sélectionnés avant l'entraînement afin de les comparer.
5. Programmer une extraction de paramètres en C++ performante :
1. (obligatoire) compléter le fichier au_reading.h afin de [convertir les fichiers AU du dataset en DataVector en C++](https://en.wikipedia.org/wiki/Au_file_format).
2. (obligatoire) efficace dans son exécution (1 Go de données musicales peuvent être traitées en 60 secondes ou moins),
3. minimale en termes de paramètres significatifs générés pour l'apprentissage :
1. (obligatoire) approche STFT
2. (facultatif) approche MFCC
6. Programmer des arbres de décision :
1. (obligatoire) générer automatiquement le code C++ à compiler pour exécuter la prise de décision sur la cible depuis le CART Python fourni.
2. (facultatif) proposer un implémentation de CART en C++-20 à partir de celle proposée en Python.
4. (facultatif) proposer un algorithme de type Random Forest à partir du code de CART C++.
7. Programmer une SVM :
1. (obligatoire) Élaborer une SVM optimale à l'aide de Scikit Learn, à partir des paramètres extraits en C++.
2. (obligatoire) Implémenter la prédiction un contre un SVM en C++-20 sur la cible.
8. Programmer un réseau de neurones :
1. (obligatoire) Implémenter un ANN en C++.
2. (facultatif) Implémenter un ANN en C++ en utilisant le paradigme objet.
9. (facultatif) Comparer vos implémentations avec TensorFlow sur Raspberry Pi.
10. (obligatoire) Comparer les approches et faire un tableau synthétique des caractéristiques et des performances de chacune approche SVM à une approche NN.
## Évaluation pour le 18/01/2022 (dépôt Moodle) :
- Rapport au format PDF police 11 de 10 pages maximum qui rend compte précisément de votre travail.
- Le code source (C++/Python/Matlab)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment