Salta el contingut

Experimentació - Ajust d’hiperparàmetres

A la Lliçó 2, vam aprendre com entrenar un model de detecció d’objectes YOLOv8 a MATLAB. A la Lliçó 4, vam veure com avaluar models utilitzant mètriques com la precisió, el recall, l’F1-score i la mAP. En aquesta lliçó, explorarem com dur a terme una experimentació sistemàtica variant els hiperparàmetres del model i la configuració de data augmentation per identificar configuracions òptimes.

Al final d’aquesta sessió, seràs capaç de:

  • Identificar i aplicar hiperparàmetres clau d’entrenament i de data augmentation, entenent-ne l’impacte sobre el rendiment del model.
  • Configurar l’Experiment Manager de MATLAB per executar múltiples proves utilitzant grid search o optimització bayesiana.

Recapitulació

A la Lliçó 2, vam veure que el codi següent es pot utilitzar per entrenar un model:

[yolov8Det, results] = trainYOLOv8ObjectDetector( ...
    configFile, ...
    baseModel, ...
    options, ...
    optionalArgs{:});

En aquella lliçó, només vam treballar amb el paràmetre Freeze de optionalArgs. En aquesta sessió, explorarem optionalArgs addicionals.

Hiperparàmetres del model

Pots trobar la llista completa d’hiperparàmetres, els seus valors per defecte i recomanacions a l’enllaç següent: Hiperparàmetres de Yolo.

Aquests són alguns dels hiperparàmetres opcionals:

  • time (float): Temps màxim d’entrenament en hores. Si s’estableix, l’entrenament s’aturarà automàticament quan s’arribi a aquest límit de temps, encara que no s’hagi completat el nombre d’èpoques especificat. És útil per a entrenaments amb restriccions de temps.
  • optimizer (str): Especifica l’optimitzador utilitzat durant l’entrenament. Les opcions habituals inclouen 'SGD', 'Adam', 'AdamW', 'RMSProp' o 'auto' per a una selecció automàtica segons el model i la tasca. L’optimitzador influeix en la velocitat i l’estabilitat de l’aprenentatge.
  • lr0 (float): Learning rate inicial que controla la velocitat amb què el model actualitza els pesos al començament de l’entrenament. Escollir un valor adequat és important per a un aprenentatge efectiu.
  • lrf (float): Fracció final del learning rate. Defineix la fracció del learning rate inicial (lr0) fins a la qual decaurà el learning rate al final de l’entrenament, sovint utilitzada amb planificadors de learning rate.
  • momentum (float): Factor de momentum utilitzat per optimitzadors com SGD o Adam, que controla la influència dels gradients passats en les actualitzacions actuals dels pesos, ajudant a estabilitzar i accelerar l’entrenament.
  • batch_size (int/ float) : El batch size es pot establir de tres maneres: com un enter (per exemple, batch=16) per a una mida fixa; com -1 per utilitzar automàticament aproximadament el 60% de la memòria de la GPU; o com una fracció entre 0 i 1 (per exemple, batch=0.70) per utilitzar aquesta fracció de la memòria de la GPU. El batch size afecta la velocitat d’entrenament i l’ús de memòria.
  • weight_decay (float): Coeficient de regularització L2 que penalitza pesos grans del model per reduir el sobreajustament i millorar la generalització.
  • patience (int): Nombre d’èpoques sense millora en les mètriques de validació després del qual l’entrenament s’atura abans d’hora. Ajuda a prevenir el sobreentrenament.

Exemple

optionalArgs = {
    'time', 1, ...
    'optimizer', 'SGD', ...
    'lr0', 0.01, ...
    'lrf', 0.0001, ...
    'momentum', 0.937, ...
    'batch', 16, ...
    'weight_decay', 0.0005, ...
    'patience', 10 ...
     'save', true, ...
};

Hiperparàmetres de data augmentation

Fins ara, els hiperparàmetres que hem definit estaven relacionats amb la configuració del model. A continuació, explicarem i definirem els hiperparàmetres de data augmentation. Pots trobar la llista completa d’hiperparàmetres de data augmentation a l’enllaç següent: Data Augmentation Yolo.

El data augmentation és una tècnica fonamental en machine learning que expandeix artificialment la mida i la diversitat d’un dataset d’entrenament. El seu propòsit principal és millorar el rendiment del model, reforçar la generalització i augmentar la robustesa introduint variacions controlades a les dades.

En el context dels models YOLO, el data augmentation consisteix a aplicar petites transformacions a les imatges originals d’entrenament per crear noves versions lleugerament modificades. Aquestes transformacions ajuden els models YOLO a adaptar-se a diferents condicions, com ara canvis d’il·luminació, escala o perspectiva, fent-los més fiables i efectius en escenaris del món real.

La llista següent descriu cada paràmetre d’augmentació, el seu paper i el seu impacte:

  • hsv_h (float): Ajusta el to de la imatge per una fracció de la roda de color (0.0 - 1.0). Introdueix variabilitat de color per ajudar el model a generalitzar en diferents condicions d’il·luminació.
  • hsv_s (float): Altera la saturació de la imatge per una fracció (0.0 - 1.0), afectant la intensitat del color. És útil per simular diverses condicions ambientals.
  • hsv_v (float): Modifica la brillantor (valor) de la imatge per una fracció (0.0 - 1.0), ajudant el rendiment en escenaris d’il·luminació diversos.
  • degrees (float): Rota aleatòriament la imatge dins d’un rang de 0.0 a 180 graus per millorar el reconeixement d’objectes en diferents orientacions.
  • translate (float): Desplaça la imatge horitzontalment i verticalment per una fracció de la seva mida (0.0 - 1.0), ajudant a detectar objectes parcialment visibles o desplaçats.
  • scale (float): Escala la imatge per un factor de guany (≥ 0.0), simulant objectes a diferents distàncies. Valor per defecte: 0.5.
  • shear (float): Aplica una deformació shear a la imatge en graus de -180 a +180, imitant diferents angles de visió.
  • perspective (float): Aplica una distorsió aleatòria de perspectiva (0.0 - 0.001) per millorar la comprensió espacial 3D.
  • flipud (float): Capgira la imatge verticalment amb una probabilitat determinada (0.0 - 1.0), augmentant la varietat de dades sense alterar les característiques de l’objecte.
  • fliplr (float): Capgira la imatge d’esquerra a dreta amb una probabilitat (0.0 - 1.0), útil per aprendre característiques simètriques i augmentar la diversitat del dataset.
  • mosaic (float): Combina quatre imatges d’entrenament en una sola amb una probabilitat (0.0 - 1.0), simulant escenes complexes i interaccions entre objectes per millorar la generalització.

Exemple

optionalArgs = {
    'hsv_h', 0.015, ...
    'hsv_s', 0.7, ...
    'hsv_v', 0.4, ...
    'degrees', 0.0, ...
    'translate', 0.1, ...
    'scale', 0.5, ...
    'shear', 0.0, ...
    'perspective', 0.0, ...
    'flipud', 0.0, ...
    'fliplr', 0.5, ...
    'mosaic', 1.0 ...
};

Creació d’un experiment

Per crear l’experiment, utilitzarem l’Experiment Manager de MATLAB.

Per obtenir més informació, consulta la documentació oficial: Documentació d’Experiment Manager i també pots consultar aquest projecte d’exemple: Exemple d’Experiment Manager.

Per llançar l’eina, podem executar l’ordre següent:

experimentManager

Un cop s’obri l’eina, hem de crear un Blank Project amb Custom Training.

image_0.png

image_1.png

Després de crear el nou projecte, hauríeu de veure una interfície similar a aquesta. Feu clic per editar la funció d’entrenament:

image_2.png

Definir la funció d’entrenament

Substitueix el codi existent per aquest.

L’únic que has de fer és definir el workingDirectory: l’has d’establir al directori on hem estat treballant fins ara.

Pots trobar el teu directori de treball actual executant l’ordre pwd (print working directory) al terminal.

A més a més, has d’especificar amb quins paràmetres vols experimentar.

En aquest exemple, experimentarem amb freeze, lr0 i lrf.

Per afegir més paràmetres, utilitza el mateix format.

function output = Experiment1_training1(params,monitor)
    addpath('help-module');
    workingDirectory = "Write here the directory where you are working (pwd)";
    cd(workingDirectory)

    configFile = fullfile(workingDirectory, 'datasets', 'fruits_3_4998', 'data.yaml');
    baseModel = 'yolov8s-oiv7.pt';
    options.MaxEpochs = 10;
    options.ImageSize = [128 128 3];

    opts = params;

    % Specify which parameters you want to experiment with
    optionalArgs = {
        % If no optimizer is specified, one will be chosen automatically.  
        % Note that parameters such as lr0 and momentum depend on the selected optimizer and may be ignored if incompatible.

        'optimizer', 'SGD' ...
        'freeze', opts.freeze, ...
        'lr0', opts.lr0, ...
        'lrf', opts.lrf
    };


    [yolov8Det, results] = trainYOLOv8ObjectDetector( ...
    configFile, ...
    baseModel, ...
    options, ...
    optionalArgs{:});

    %-----------------------------------------------------------------------------
    % This section contains code to display the results
    dict = results.results_dict;

    precision = double(dict{'metrics/precision(B)'});
    recall    = double(dict{'metrics/recall(B)'});
    mAP50     = double(dict{'metrics/mAP50(B)'});
    mAP5095   = double(dict{'metrics/mAP50-95(B)'});

    monitor.Metrics = ["Precision", "Recall", "mAP50", "mAP5095"];
    monitor.XLabel = "Epoch";

    % Path to the CSV file generated by Ultralytics
    saveDirStr = char(results.save_dir.as_posix());  % or .__str__() if this doesn't work
    csvPath = fullfile(saveDirStr, 'results.csv');

    if isfile(csvPath)
        data = readmatrix(csvPath);
        % Columns: epoch, box_loss, obj_loss, cls_loss, precision, recall, mAP_50, mAP_50-95
        train_boxloss = data(:, 2); 
        train_cls_loss = data(:, 3);
        train_dfl_loss = data(:, 4);
        precision = data(:, 5);
        recall    = data(:, 6);
        mAP50     = data(:, 7);
        mAP5095   = data(:, 8);
        val_boxloss = data(:, 9); 
        val_cls_loss = data(:, 10);
        val_dfl_loss = data(:, 11);
        epochs = size(data, 1);

        % Añadir todas las métricas a monitor
        % monitor.Metrics = [monitor.Metrics, "Train_BoxLoss", "Train_CLSLoss", "Train_DFLLoss", "Val_BoxLoss", "Val_CLSLoss", "Val_DFLLoss"];
        monitor.Metrics = [monitor.Metrics, "Train_BoxLoss", "Val_BoxLoss" ];
        monitor.XLabel = "Epoch";

        for epoch = 1:epochs
            monitor.recordMetrics(epoch, ...
                "Precision", precision(epoch), ...
                "Recall", recall(epoch), ...
                "mAP50", mAP50(epoch), ...
                "mAP5095", mAP5095(epoch), ...
                "Train_BoxLoss", train_boxloss(epoch), ...
                "Val_BoxLoss", val_boxloss(epoch));
                %"Train_CLSLoss", train_cls_loss(epoch), ...
                %"Train_DFLLoss", train_dfl_loss(epoch), ...
                %"Val_CLSLoss", val_cls_loss(epoch), ...
                %"Val_DFLLoss", val_dfl_loss(epoch));
        end
    else
        warning('No se encontró results.csv en %s', csvPath);
    end
    output.trainedDetector = yolov8Det;
    output.metrics = results.results_dict;
    output.modelPath = saveDirStr;
end

Definir els rangs dels hiperparàmetres

Un cop definida la funció d’entrenament, el pas següent és especificar el rang d’hiperparàmetres que es vol explorar. Això es fa dins de l’Experiment Manager.

Important: Els noms dels paràmetres que utilitzis aquí han de coincidir exactament amb els utilitzats a la funció d’entrenament. Per exemple:

image_3.png

Els noms dels paràmetres han de començar amb una lletra, seguida de lletres, dígits o guions baixos.

Exemples:

  • distance
  • a_2

Els valors dels paràmetres han de ser escalars o vectors. L’Experiment Manager fa una cerca exhaustiva executant una prova per a cada combinació única de valors de paràmetres especificada a la taula.

Exemples:

  • 0.01
  • 0.01:0.01:0.05
  • [0.01 0.02 0.04 0.08]
  • ["alpha" "beta" "gamma"]

Tipus de dades compatibles:

double | single | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64 | logical | string | char

Escollir una estratègia

Hi ha dos tipus d’estratègies:

  • Exhaustive Sweep: Executa un experiment per a cada combinació possible de tots els hiperparàmetres especificats.
  • Optimització bayesiana: Especifiques hiperparàmetres amb els seus rangs de valors i el nombre d’iteracions que s’han d’executar. A cada iteració, l’algorisme selecciona les combinacions d’hiperparàmetres més prometedores basant-se en els resultats anteriors, evitant així haver de provar tot l’espai de paràmetres, que sovint és enorme.

Quan s’utilitza l’optimització bayesiana, cal especificar el tipus de cada variable, el nombre màxim de proves (és a dir, les configuracions màximes a provar) i, opcionalment, un temps màxim d’execució. A més a més, cal especificar quina mètrica s’utilitzarà com a objectiu d’optimització. Aquesta mètrica s’ha d’enregistrar durant l’entrenament. En el nostre cas, la mètrica recomanada és mAP5095, ja que té en compte tant la precisió de localització de les bounding boxes com la correcció de la predicció de classe.

image_4.png

Executar l’experiment

Un cop definida l’estratègia, pots fer clic a RUN per iniciar l’experiment.

A la pestanya d’entrenament, després que es completi cada iteració, pots revisar les mètriques d’aquella iteració.

image_5.png

A més a més, si fas clic al botó Training Plot situat a la part superior central, s’obrirà una finestra nova amb gràfics que mostren l’evolució de les mètriques definides a la funció d’entrenament al llarg de les èpoques per a la prova seleccionada:

image_6.png

Per seleccionar una prova, simplement fes-hi clic a la taula amb el ratolí.

image_7.png

image_8.png

Tensor Board

Una altra opció per visualitzar les mètriques d’entrenament és TensorBoard. El pots llançar utilitzant l’ordre següent, que iniciarà un servidor local. Després, obre el navegador web i ves a l’URL següent: http://localhost:6006/

pyInterpreter = char(getPythonInterpreter());
logdir = fullfile(pwd)

if ispc
    command = ['start "" "' pyInterpreter '" -m tensorboard.main --logdir "' logdir '"'];
else 
    command = [pyInterpreter ' -m tensorboard.main --logdir "' logdir '" &'];
end

disp(command) 
system(command); 

disp('✅ TensorBoard is running in the background (http://localhost:6006/)...');