Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesclar estratégias de pré-treino do SOTA 2020 com perda contrastiva #39

Closed
10 tasks
vitalwarley opened this issue Oct 23, 2023 · 39 comments
Closed
10 tasks
Assignees

Comments

@vitalwarley
Copy link
Owner

vitalwarley commented Oct 23, 2023

Achieving Better Kinship Recognition Through Better Baseline

The ArcFace [2] model was used for features extraction. This model was pre-trained on cleaned MS-Celeb-1M [3] dataset 3 and has the embedding dimension of 512.

We used Mxnet [28] for the implementation of our pipeline. For detection and feature extraction insightface python package was used. In particular, retinaface r50 v1 which is RetinaFace implementation with ResNet50 as the backbone and arcface r100 v1 which is modified ResNet101 trained with ArcFace loss on cleaned MS-Celeb-1M dataset.

Tal pré-treino é a primeira estratégia abaixo.

Image

We tested the simple fine-tuning using a classification layer (+classification) with a similar approach where the embeddings are normalized to have a unit L2 norm before the classification layer (+normalization).

Há mais detalhes sobre os hiperparâmetros e augmentações, todavia vou manter simples por agora.

Supervised Contrastive Learning for Facial Kinship Recognition

Image

Our network receives a face pair denoted by $(x, y)$ as input, and the extracted mid-level feature pair $(h_x, h_y)$ by the siamese backbone are fed into a MLP to obtain a low-dimensional feature pair $(f_x, f_y)$. Given a $n$ positive pairs $\mathcal{P} = {(x_i, y_i)}_{i=1}^n$ sampled from different families, the contrastive loss $L$ can be defined as:

$$ L = \frac{1}{2n} \sum_{i=1}^{n} \left[ L_c (x_i, y_i) + L_c (y_i, x_i) \right] \quad (1) $$

where

$$ L_c (x_i, y_i) = - \log \frac{e^{s(x_i,y_i)}/\tau}{\sum_{j=1}^{n} \left[ e^{s(x_i,x_j)}/\tau + e^{s(x_i,y_j)}/\tau \right]} \quad (2) $$

where $s(x, y)$ is defined as the cosine similarity between $x$ and $y$. In our supervised contrastive learning framework, negative samples are collected by combining positive samples from different families.

O poder dessa perda provavelmente vem da grande quantidade de exemplos negativos: 2 * (batch_size^2 - batch_size) pares negativos.


Basicamente, a diferença do SOTA 2021 para o 2020 é que aquele usou apenas a mesma rede (ArcFace, pré-treinada no ImageNet) com perda contrastiva. Isso é, não houve pré-treino em reconhecimento facial no MS-Celeb-1M, nem posterior ajuste fino na tarefa de classificação de famílias no FIW.

Roadmap

MS-Celeb-1M fine-tuning

  • Criar classe FRClassification que retorne (face, id)
  • Criar módulo FRClassifier que extenda a rede original para classificação de indivíduos
  • Realizar treinamento
  • Avaliar resultados
  • Decidir próximos passos

FIW Family fine-tuning

  • Criar classe KinFamilyClassification que retorne (face, family_id)
  • Criar módulo KinFamilyClassifier que extenda a rede original para classificação de famílias
  • Realizar treinamento
  • Avaliar resultados
  • Decidir próximos passos
@vitalwarley vitalwarley self-assigned this Oct 23, 2023
@vitalwarley
Copy link
Owner Author

Dataset usado por Shadrikov (2020) é MS1M_v2: MS1M-ArcFace (cito em #18 (comment)). Encontramos-o aqui; precisamente, nesse link.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Oct 25, 2023

  • Clonar insightface
  • Criar venv (usei Python 3.11) para o insightface e instalar pacotes em insightface/requirements.txt e insightface/recognition/arcface_paddle/requirement.txt
    • Remover sklearn do .txt
    • Remover a versão pinada do scikit-learn e opencv-python
    • Adicionar mxnet
  • Altera <VIRTUALENVS_DIR>/insightface/lib/python3.11/site-packages/mxnet/numpy/utils.py", na linha 37, onde tem bool = onp.boolparabool = bool`. Ou remove a linha.
  • Desempacota as imagens: python insightface/recognition/arcface_paddle/tools/mx_recordio_2_images.py --root_dir datasets/faces_emore --output_dir datasets/faces_emore

Foram 1h47min para terminar o processo. 5822653 amostras divididas em 85741 classes.


Apenas ao fim lembrei/percebi que o pessoal do deepinsight disponibilizam os modelos pré-treinados. Todavia, para o modelo em PyTorch, o pré-treino foi realizado no MS1MV2, cujo modelo mxnet usado pelo Shadrikov foi pré-treinado. Mais detalhes sobre os datasets:

  • MS1MV2 (87k IDs, 5.8M images)
  • MS1MV3 (93k IDs, 5.2M images)

Vou resgatar os códigos do ano passado para completar essa tarefa.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Oct 25, 2023

CLI

╚═╡(kinship) [9:47] λ python val.py --data-dir ../datasets/faces_emore --insightface --weights models/ms1mv3_arcface_r100_fp16.pth --task pretrain --test

Modificações

  • Adicionar argumentos a tm.Accuracy

Problemas

  • lfw não foi carregado
  • cfp_fp e agedb_30 foram carregados, todavia houve um erro ao tentar acessar uma chave inexistente no checkpoint
    • Usei --ckpt-path, mas o correto era --weights

Resultados

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   Runningstage.testing    ┃                           ┃                           ┃
┃          metric           ┃       DataLoader 0        ┃       DataLoader 1        ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│       agedb_30/acc        │    0.9825000762939453     │    0.9825000762939453     │
│       agedb_30/norm       │    23.078630447387695     │    23.078630447387695     │
│    agedb_30/threshold     │    1.2489999532699585     │    1.2489999532699585     │
│        cfp_fp/acc         │    0.9877142906188965     │    0.9877142906188965     │
│        cfp_fp/norm        │     22.41592788696289     │     22.41592788696289     │
│     cfp_fp/threshold      │    1.2700002193450928     │    1.2700002193450928     │
└───────────────────────────┴───────────────────────────┴───────────────────────────┘

Similar aos resultados originais com mxnet

Image


Próximo passo é revisar a #24 e continuar com roadmap dessa issue.

vitalwarley added a commit that referenced this issue Oct 25, 2023
Some adjustments were needed: add `tm.Accuracy` arguments

Ref.: #39
@vitalwarley
Copy link
Owner Author

vitalwarley commented Oct 26, 2023

Na #24, temos

  • Using arcface_torch (pre-trained model equivalent to ArcFace R100 MXNET) I got AUC = 0.7198 (vs 0.6717 from my pre-trained model) and ACC = 0.66 (same with mxnet).

Sendo assim, creio que usar o modelo pré-treinado é válido. Posso, então, pular o primeiro roadmap: MS-Celeb-1M fine-tuning. Antes de continuar para o segundo, no entanto, vou usar o modelo como está (pré-treinado em reconhecimento facial) para tarefa de verificação de parentesco com perda contrastiva (SOTA 2021).

A hipótese é que as features aprendidas no reconhecimento facial vão aumentar a acurácia reportada pelo trabalho #26.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Oct 27, 2023

╚═╡(rfiw2021) [21:40] λ python Track1/train.py --batch_size 20 --sample Track1/sample0 --save_path Track1/models/arcface_fr_ft_kv.pth --epochs 80 --beta 0.08 --log_path Track1/logs/arcface_fr_ft_kv.txt --gpu 0 --insightface ../hybrid/models/ms1mv3_arcface_r100_fp16.pth
...
*************
epoch 1
...
contrastive_loss:3.287279
...
auc is 0.807662 
auc improve from :0.000000 to 0.807662
save model Track1/models/arcface_fr_ft_kv.pth

Já começou bem. AUC tem que passar de 0.865929 (#26).

@vitalwarley
Copy link
Owner Author

vitalwarley commented Oct 27, 2023

Não melhorou no treinamento.

arcface_fr_ft_kv

Nem no conjunto de validação para computação do limiar

auc :  0.8616017331936722
threshold : 0.06821151822805405

Usando o modelo original obtivemos AUC = 0.8671 e threshold = 0.1155.

Ainda assim, a média subiu 0.0023

Model Pretrained on train loss train auc val auc threshold bb ss sibs fd md fs ms gfgd gmgd gfgs gmgs avg
ArcFace ImageNet - 0.8646 0.8634 0.1132 0.8065 0.8135 0.7891 0.7586 0.7836 0.8113 0.7717 0.7788 0.7361 0.6571 0.6369 0.7898
ArcFace MS1MV3 0.08127 0.8598 0.8616 0.0682 0.7953 0.8183 0.7938 0.7804 0.8044 0.8096 0.7535 0.7675 0.7249 0.6408 0.5810 0.7921

Em detalhes, essas são as diferenças

Metric Relative Difference
bb -0.0112
ss 0.0048
sibs 0.0047
fd 0.0218
md 0.0208
fs -0.0017
ms -0.0182
gfgd -0.0113
gmgd -0.0112
gfgs -0.0163
gmgs -0.0559
avg 0.0023

É importante salientar que mantive os mesmos hparams, inclusive a lr. Talvez o próximo passo seja tuná-los, especialmente se considerarmos que o modelo não melhora a partir da época ~40.

vitalwarley added a commit that referenced this issue Oct 31, 2023
Also fixed the dataset `__getitem__` label definition.

Ref.: #39
@vitalwarley
Copy link
Owner Author

Tratei de avaliar o que precisava ser feito para realizar o ajuste fino em classificação de família. Basicamente, complementar o dataset.py de forma a poder retornar, se necessário, indivíduo e família; e complementar NetClassifier com um novo esquema de inferência para o caso de uma embedding apenas.

Precisamos, também, verificar

  • Número de famílias
  • Número de famílias uniforme em cada set
  • Possivelmente dispensar as mesmas imagens do mesmo indivíduo nos conjuntos

Próximo passo é revisar Shadrikov em busca de saber como ele preparou os dados para essa etapa.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 7, 2023

Ontem revisei o paper e código. Descobri que o SOTA 2020 tem uma família a mais no train set. Nada tão problemático.

Agora a noite eu adaptei o código de treino do Shadrikov. Estou conseguindo treinar. Todavia não dei muita atenção aos hparams usados. Só queria o código funcional.

Loaded insightface model.
[Epoch: 1, Mini-batch:   100] loss: 6.472
[Epoch: 1, Mini-batch:   200] loss: 6.341
[Epoch: 1, Mini-batch:   300] loss: 6.175
[Epoch: 2, Mini-batch:   100] loss: 5.884

Serão 20 épocas. É apenas um teste. Amanhã busco deixar o script 100% igual para de fato treinarmos o modelo.

vitalwarley added a commit that referenced this issue Nov 7, 2023
@vitalwarley
Copy link
Owner Author

[Epoch: 19, Mini-batch:   300] loss: 0.191
[Epoch: 20, Mini-batch:   100] loss: 0.157
[Epoch: 20, Mini-batch:   200] loss: 0.163
[Epoch: 20, Mini-batch:   300] loss: 0.161

Tal treinamento durou menos de 1h. Ontem falei que era apenas um teste. Mesmo assim, vou agora realizar treinamento em verificação de parentesco. É bom que já esquematizo todo o pipeline.


Acontece que não há treinamento em verificação de parentesco. Segue minhas anotações de agora a noite

  • Sec. III - B

    • Given the information for each person about their family association, we can construct a family classification problem similar to the recent methods in face recognition [16], [2], [17] and metric learning for image retrieval [23], [24]
      - He then uses the categorical cross-entropy loss.
    
  • Sec. IV - B

    • Re-detected and aligned (as described in III-A) faces were given to the feature extractor model to obtain image embeddings. Performance of this approach (pretrained on fig. 1) was used as a baseline to test our hypotheses.
      - With the ArcFace model pretrained on the MS1MV3.
    
    • First, we tried to add a simple classification layer and finetune the whole model on the train set... After that, we added L2 normalization of the embeddings and retrained the model starting with pre-trained weights.
      - Não há menção de treinamento de verificação de parentesco. O modelo gerado após o treinamento já foi utilizado diretamente no val e test set.
    
  • Sec. IV - C

    • We tested the simple fine-tuning using a classification layer (+classification) with a similar approach where the embeddings are normalized to have a unit L2 norm before the classification layer (+normalization). Both on our validation data and test set the second approach was superior.
  • Considerando o que aprendi acima, próximos passos

    • Adaptar verification.py para usar modelo que treinei.

    • Avaliar resultados.

    • Ajustar train_fiw_clf.py para estar equivalente ao train.py do Andrei Shadrikov.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 8, 2023

Antes de adaptar o verification.py, estou realizando outro treinamento com normalização das embeddings antes da camada de classificação. O script de verificação compara as três estratégias, logo adaptá-lo dessa forma será mais útil.

╚═╡(kinship) [22:13] λ python train_fiw_clf.py --dataset-path ../fitw2020/train-faces-det --insightface-weights models/ms1mv3_arcface_r100_fp16.pth --output-dir arcface_fiw_clf_norm
Loaded insightface model.
[Epoch: 1, Mini-batch:   100] loss: 6.451
[Epoch: 1, Mini-batch:   200] loss: 6.317
[Epoch: 1, Mini-batch:   300] loss: 6.168

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 14, 2023

Shadrikov (2020) used

  • retinaface_r50_v1 from insightface to re-detect and align faces. They're here.
  • arcface_r100_v1, also from insightface, which I am trying to train, and fed sample validation pairs from these re-detected and aligned images. The baseline below is the result of this approach.

2022-04-22-164921_839x711_scrot

  • The next step was to fine-tune the whole model on the train set with a simple classification layer.
  • The final experiment was to add an L2 normalization of the embeddings and retrain the original pre-trained model.
    • From what I understood, this normalization occurred before the classification layer. That is, we have here a pre-trained model + classification layer + normalization layer.
  • The selected binarization threshold was that which gave a False Positive Rate (FPR) of 0.2

Originally posted by @vitalwarley in #18 (comment)

Meus resultados atuais cujo objetivo é apenas validar minha adaptação do treinamento e verificação

roc

É, meio que esperado. Não reproduzi os treinamentos com os mesmos hparams e afins.

@vitalwarley
Copy link
Owner Author

Considerando os resultados acima, penso que posso continuar com mesclagem das estratégias apenas após reproduzir o primeiro gráfico do comentário anterior. Isso é, a estratégia de classificação precisa alcançar AUC = 0.7762 e a estratégia com adição de normalização das features precisa alcançar AUC = 0.7912.

Note que usei o mesmo dataset de Shadrikov.

vitalwarley added a commit that referenced this issue Nov 15, 2023
`val_fiw_clf.py` was adapted from `fit2020/verification.py`.

Ref.: #39
vitalwarley added a commit that referenced this issue Nov 15, 2023
- Also created a new directory with hybrid approach, while preserving my last year reproduction trial of Shadrikov..

Ref.: #39
@vitalwarley
Copy link
Owner Author

╚═╡(kinship) [21:53] λ python train.py --dataset-path ../fitw2020/train-faces-det --insightface-weights models/ms1mv3_arcface_r100_fp16.pth --output-dir experiments
Loaded insightface model.
Total number of steps: 330
Start training at 2023-11-14 21:54:40
[Epoch:  1, Step:   100] loss: 6.476, accuracy: 0.002, lr: 5.000e-05
[Epoch:  1, Step:   200] loss: 6.414, accuracy: 0.003, lr: 1.000e-04
[Epoch:  1, Step:   300] loss: 6.360, accuracy: 0.006, lr: 1.000e-10
[Epoch  1] accuracy: 0.007, time: 0:02:24.531955 [steps/second: 2.283]
Finished training at 2023-11-14 21:57:04.

Teste do script OK. Vamos agora treinar de verdade.

vitalwarley added a commit that referenced this issue Nov 15, 2023
- Added `update_lr` function
- Added `log` function
- Set seed

Ref.: #39
vitalwarley added a commit that referenced this issue Nov 15, 2023
- Added `update_lr` function
- Added `log` function
- Set seed

Ref.: #39
vitalwarley added a commit that referenced this issue Nov 15, 2023
- Added `update_lr` function
- Added `log` function
- Set seed

Ref.: #39
@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 15, 2023

Treinamento de ontem

[Epoch: 20, Step:  6370] loss: 5.805, accuracy: 0.079, lr: 1.0000000000002073e-10
[Epoch: 20, Step:  6470] loss: 5.847, accuracy: 0.074, lr: 1e-10
[Epoch: 20, Step:  6570] loss: 5.817, accuracy: 0.076, lr: 1e-10
[Epoch 20] accuracy: 0.076, time: 0:02:26.393322 [steps/second: 2.254]
Finished training at 2023-11-14 23:24:47.

Provavelmente a causa foi o clip_grad

            torch.nn.utils.clip_grad_norm_(model.parameters(), CLIP_GRADIENT)

que é definido como 1. Antes de adicioná-lo, a acurácia estava subindo rapidamente

Start epoch at 2023-11-14 22:29:39
[Epoch:  4, Step:  1090] loss: 4.984, accuracy: 0.211, lr: 9.999999999999999e-05
[Epoch:  4, Step:  1190] loss: 4.862, accuracy: 0.228, lr: 9.999999999999999e-05
[Epoch:  4, Step:  1290] loss: 4.750, accuracy: 0.246, lr: 9.999999999999999e-05

Os detalhes de implementação de Shadrikov foram esses

Finetune the whole model on the train set with stochastic gradient descent with base learning rate of 0.0001, momentum 0.9, linear warmup for first 200 batches of size 64, linear cooldown for last 400 batches, multiplying learning rate by 0.75 on epochs 8, 14, 25, 35, 40 and gradient clipping 1.5 for 50 epochs.

embora em seu train.py existam diferenças (lr_steps com épocas 50 e 60 adicionadas, clip_gradient com valor 1.0, num_epoch com valor 20).


Treinamentos de hoje

Desativei gradient clipping.

Classificação (20231115091006)

lr
loss
accuracy

Classificação com normalização (20231115095948)

Epoch 19 - Acc: 0.056, Time: 0:02:31.561763, Steps/s: 2.177
Epoch 20 | Step  6370 - Loss: 6.310, Acc: 0.059, LR: 0.0000000001
Epoch 20 | Step  6470 - Loss: 6.314, Acc: 0.055, LR: 0.0000000001
Epoch 20 | Step  6570 - Loss: 6.316, Acc: 0.056, LR: 0.0000000001
Epoch 20 - Acc: 0.056, Time: 0:02:31.601180, Steps/s: 2.177
Finished training at 2023-11-15 10:49:59.

Investigarei a causa. Talvez aqui que de fato precise haver gradient clipping, dado que as features agora são normalizadas, isso é, assume valores em [-1, 1]?

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 15, 2023

Validação (20231115152543)

Modelos 20231115091006 e 20231115095948.

 λ python val.py --logdir experiments/validation --baseline-weights models/ms1mv3_arcface_r100_fp16.pth --classification-weights experiments/20231115091006/model_epoch_20.pth --normalization-weights experiments/20231115095948/m
odel_epoch_20_norm.pth --dataset-path ../fitw2020/val-faces-det

roc

vitalwarley added a commit that referenced this issue Nov 15, 2023
@vitalwarley
Copy link
Owner Author

Epoch 19 | Step  6040 - Loss: 6.325, Acc: 0.053, LR: 0.0000562500
Epoch 19 | Step  6140 - Loss: 6.307, Acc: 0.055, LR: 0.0000562500
Epoch 19 | Step  6240 - Loss: 6.326, Acc: 0.056, LR: 0.0000082883
Epoch 19 - Acc: 0.056, Time: 0:02:25.123843, Steps/s: 2.274
Epoch 20 | Step  6370 - Loss: 6.310, Acc: 0.059, LR: 0.0000000001
Epoch 20 | Step  6470 - Loss: 6.314, Acc: 0.055, LR: 0.0000000001
Epoch 20 | Step  6570 - Loss: 6.316, Acc: 0.056, LR: 0.0000000001
Epoch 20 - Acc: 0.056, Time: 0:02:26.108392, Steps/s: 2.259
Finished training at 2023-11-15 16:35:13.

Como que um treinamento em classificação de famílias que não converge é melhor do que um que converge?

╚═╡(kinship) [16:39] λ python val.py --logdir experiments/validation --baseline-weights models/ms1mv3_arcface_r100_fp16.pth --classification-weights experiments/train/20231115091006/model_epoch_20.pth --normalization-weights experiments/train/20231115154700/model_epoch_20_norm.pth --dataset-path ../fitw2020/val-faces-det
Validating with 10000 pairs.
Loaded insightface model.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 500/500 [00:58<00:00,  8.57it/s]
Baseline AUC: 0.7183
Loaded insightface model.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 500/500 [01:00<00:00,  8.29it/s]
Classification AUC: 0.6704
Loaded insightface model.
Feature normalization ON.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 500/500 [01:01<00:00,  8.11it/s]
Normalization AUC: 0.7196

AUC da estratégia com normalização não mudou, no entanto.

roc

vitalwarley added a commit that referenced this issue Nov 16, 2023
- Also added scaling by 32 in normalization (seems like ArcFace scale).

Ref.: #39
@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 16, 2023

lr
loss
accuracy
roc

Reproduzi a estratégia de classificação, embora tenha faltado alguns centésimos. A solução foi inicializar corretamente a camada de classificação. Isso tinha sido feito nos meus códigos antigos, algo que deixei passar despercebido. Próximo passo é entender a não-convergência da estratégia de normalização.

@vitalwarley
Copy link
Owner Author

Desativei gradient clipping para estratégia de normalização. Houve melhoria na AUC, mas ainda aquém do esperado (0.79).

loss
accuracy
roc

@vitalwarley
Copy link
Owner Author

Sem gradient clipping os resultados foram piores.

Treinamento

+ Classificação

plot

+ Normalização

plot

Validação

roc

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 17, 2023

Adapted ChatGPT summary from week report

Here's a revised table that includes separate columns for the AUC results of the classification and normalization strategies, as well as columns for loss and accuracy for each strategy:

Date Experiment Change(s) Implemented AUC (Classification) AUC (Normalization) Loss (Classification) Accuracy (Classification) Loss (Normalization) Accuracy (Normalization)
Nov 13, 2023 1 Adaptation to PyTorch, without hyperparameter consideration 0.6641 0.6697 Not specified Not specified Not specified Not specified
Nov 14, 2023 1 Added original hyperparameters from train.py Not evaluated Not evaluated High Low High Low
Nov 15, 2023 1 Disabled Gradient Clipping in normalization 0.6704 0.7196 < 1 (~0.25) 1 Not specified Not specified
2 Re-enabled Gradient Clipping for normalization Unchanged Unchanged Not specified Not specified Not specified Not specified
3 Initialized classification layer with normal distribution 0.7703 Not specified < 4 (+ Noisy) ~0.6 Not specified Not specified
Nov 16, 2023 1 Disabled Gradient Clipping 0.7703 0.7530 < 4 (+ Noisy) ~0.6 Not specified Not specified
2 Set Gradient Clipping to 1.5 (as per paper) 0.7304 0.7325 < 6 (++ Noisy) ~0.2 < 6 (++ Noisy) ~0.2
3 Increased epochs to 50, Gradient Clipping at 1.5 0.7596 0.7558 < 5.6 (++ Noisy) ~0.3 < 5.5 (++ Noisy) ~0.35
4 No Gradient Clipping, 50 epochs 0.7256 0.7058 ~1.5 ~0.98 ~0.2 1

This table now provides a more detailed breakdown of the AUC results, loss, and accuracy for both the classification and normalization strategies across your various experiments. It highlights the dynamic nature of model training and the impact of different changes on these metrics.

Analyzing the table of your experiments, several key insights emerge:

  1. Impact of Gradient Clipping:

    • The use of gradient clipping showed mixed results. Disabling it sometimes improved the AUC, but in other cases, it led to worse outcomes. This suggests that the optimal setting for gradient clipping might be context-dependent and needs careful tuning. In experiment 4, removing gradient clipping seemed to stabilize the training but at the cost of lower AUCs.
  2. Hyperparameter Sensitivity:

    • The results vary significantly with changes in hyperparameters, as seen in the experiments conducted on November 14 and 15. This underlines the sensitivity of deep learning models to hyperparameter settings, emphasizing the need for meticulous tuning.
  3. Training Stability vs. Performance:

    • There is a noticeable trade-off between training stability (as reflected in loss and accuracy variance) and performance (AUC). For instance, experiments on November 16 indicate more stable training with lower performance when gradient clipping was removed.
  4. Normalization Strategy Challenges:

    • The normalization strategy consistently underperformed compared to the classification strategy in terms of AUC. This suggests that the approach or its specific implementation might need revisiting or further optimization.
  5. High Accuracy with Overfitting Concerns:

    • In some experiments, particularly Experiment 4 on November 16, you achieved very high accuracy levels (near 1.0). While impressive, this could be indicative of overfitting, especially if such accuracy is not mirrored in validation or test datasets.
  6. Non-convergence and AUC Improvement Paradox:

    • In some cases, such as the November 15 Experiment 1, models that did not converge (in terms of loss and accuracy) still achieved a reasonable AUC. This suggests that the model might be learning useful discriminatory features that are not fully captured by the loss and accuracy metrics.
  7. Influence of Training Duration:

    • Extending the training duration (Experiment 3 on November 16) didn't significantly improve the AUC, suggesting that simply training longer is not the solution and that other factors (like model architecture, data quality, or learning rate scheduling) might be more critical.

These insights indicate that while there's progress, achieving the desired balance between stability, convergence, and high AUC requires further experimentation and perhaps more fundamental changes in approach, such as revisiting the model architecture or data preprocessing methods.


Importante lembrar que a taxa de aprendizado no passo N depende do total de épocas. Sendo assim, os experimentos 3 e 4 de ontem tem uma taxa de aprendizado diferente depois da época 20 -- o cooldown é feito nos 400 passos finais. São 330 passos por época com um batch_size = 48 (o autor relata tamanho 64). Além disso, em épocas pré-definidas há uma escala da taxa por 0.75.

vitalwarley added a commit that referenced this issue Nov 17, 2023
@vitalwarley
Copy link
Owner Author

Date Experiment Change(s) Implemented Epochs Batch Size AUC (Classification) AUC (Normalization) Loss (Classification) Accuracy (Classification) Loss (Normalization) Accuracy (Normalization)
Nov 13, 2023 1 Adaptation to PyTorch, without hyperparameter consideration 20 48 0.6641 0.6697 Not specified Not specified Not specified Not specified
Nov 14, 2023 1 Added original hyperparameters from train.py Not specified Not specified Not evaluated Not evaluated High Low High Low
Nov 15, 2023 1 Disabled Gradient Clipping in normalization Not specified Not specified 0.6704 0.7196 < 1 (~0.25) 1 Not specified Not specified
2 Re-enabled Gradient Clipping for normalization Not specified Not specified Unchanged Unchanged Not specified Not specified Not specified Not specified
3 Initialized classification layer with normal distribution Not specified Not specified 0.7703 Not specified < 4 (+ Noisy) ~0.6 Not specified Not specified
Nov 16, 2023 1 Disabled Gradient Clipping Not specified Not specified 0.7703 0.7530 < 4 (+ Noisy) ~0.6 Not specified Not specified
2 Set Gradient Clipping to 1.5 (as per paper) Not specified Not specified 0.7304 0.7325 < 6 (++ Noisy) ~0.2 < 6 (++ Noisy) ~0.2
3 Increased epochs to 50, Gradient Clipping at 1.5 50 48 0.7596 0.7558 < 5.6 (++ Noisy) ~0.3 < 5.5 (++ Noisy) ~0.35
4 No Gradient Clipping, 50 epochs 50 48 0.7256 0.7058 ~1.5 ~0.98 ~0.2 1
Nov 16, 2023 5 Multiplied image by 255 50 64 0.5181 0.5193 ~5.2 (+/- 0.5) ~0.25, with frequent fluctuations ~5 (+/- 0.5) ~0.35, with frequent fluctuations
Nov 17, 2023 1 batch_size = 64 and fp16=True in backbone; baseline model is fp16 50 64 0.7510 0.7481 ~5.3 (+/- 0.4) ~0.25, with frequent fluctuations ~5.2 (+/- 0.3) ~0.3, with frequent fluctuations

Vou usar guildai e reproduzir alguns experimentos para facilitar análise.

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 18, 2023

Usei as ideias aqui, especialmente o último comentário. Em alguns experimentos, verifiquei que o máximo batch_size suportado é 46. Embora exista uma GPU com 12GB, não dá para condicionar experimentos com maiores tamanhos de batch nela.

Planejei 2 * 3 * 3 * 3 = 54 experimentos com o comando abaixo.

➜  hybrid git:(main) ✗ guild run train --stage-trials --quiet train-dataset-path=fitw2020/train-faces-det val-dataset-path=fitw2020/val-faces-det insightface-weights=models/ms1mv3_arcface_r100_fp16.pth output-dir=exp 'normalize=[yes,no]' 'clip-gradient=[0, 1, 1.5]' 'num-epoch=[20, 50, 100]' 'batch-size=[16, 32, 46]' -y

Incerto quando vai acabar, mas são 6 experimentos sendo executados simultaneamente, então talvez não demore tanto. Com um `batch-size=46', uma época (incluindo a validacão) levou 5 minutos. Logo, ChatGPT nos diz que...

Para calcular o tempo total necessário para completar os 54 experimentos, podemos usar as seguintes informações:

  1. Cada época (incluindo validação) leva 5 minutos com um batch-size de 46.
  2. O número total de épocas varia entre os experimentos (20, 50 ou 100 épocas).
  3. São 6 experimentos sendo executados simultaneamente.
  4. No total, planejamos realizar 54 experimentos.

Vamos assumir que o tempo para uma única época é mais ou menos constante, independente do número de épocas. Este é um ponto importante, pois se o tempo por época variar significativamente com diferentes batch-sizes, nossa estimativa pode ser imprecisa.

Cálculo do Tempo

  1. Tempo para uma única época: 5 minutos.
  2. Tempo para cada configuração de época:
    • Para 20 épocas: (20 \times 5) minutos.
    • Para 50 épocas: (50 \times 5) minutos.
    • Para 100 épocas: (100 \times 5) minutos.
  3. Número de experimentos por configuração de época: Como existem 3 configurações de num-epoch e um total de 54 experimentos, cada configuração será usada em (54 / 3 = 18) experimentos.
  4. Tempo total por configuração de época: Calcularemos para cada uma das três configurações.
  5. Tempo total: Somaremos o tempo de todas as configurações e dividiremos pelo número de experimentos que podem ser executados simultaneamente (6).

Vamos fazer esses cálculos.

Os cálculos indicam que serão necessárias aproximadamente 2550 minutos para completar todos os 54 experimentos, o que corresponde a cerca de 42.5 horas.

Portanto, você pode esperar que todos os experimentos sejam concluídos em aproximadamente 1.8 dias, assumindo que os experimentos são executados continuamente e que o tempo por época é constante para diferentes configurações de batch-size.

Essa é uma estimativa, e o tempo real pode variar com base em fatores como a eficiência da CPU/GPU, a complexidade dos dados e a carga de trabalho do sistema.


Atualmente o script salva sempre o melhor modelo de acordo com AUC. Abaixo alguns experimentos ainda em curso

2023-11-18-102245_2518x1342_scrot

2023-11-18-102814_2560x1440_scrot

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 19, 2023

Há três experimentos rodando ainda. Boa parte daqueles com batch-size=46 deram OOM pouco depois de iniciado. Resultados parciais

image
2023-11-19-085646_2560x1440_scrot

epoch refere-se à época atual, pois o experimento ainda está em curso.

Interessante esses dois grupos de experimentos onde em uns o AUC sobe rapidamente, enquanto noutros não. Segue abaixo minha interpretação, que escrevi ontem

Sobre esses resultados intermediários. Vale a pena contrastar com os outros que convergiram apenas ao fim do experimento. O que eu penso: não há apenas features para reconhecimento facial e reconhecimento de parentesco, mas também para algo que intersecta ambos. Alguns experimentos atingiram maior AUC ao fim da terceira época, cuja acurácia não passava de 0.5. Ao longo do treinamento, tais experimentos sofreram uma queda na AUC, ao passo que a acurácia melhorava. Em outra palavras, o modelo aprendeu as features que discriminam parentesco, mas rapidamente deu lugar às que discriminam famílias. Outros experimentos conseguiram manter um trade-off ao longo do treinamento; as features que discriminam parentesco foram aprendidas aos poucos; inevitavelmente features que poderiam discriminar famílias não foram aprendidas, dado a baixa acurácia (< 0.5).

Conclusões parciais sobre os hiper-parâmetros (considerando que avaliei apenas alguns)

  • Maior num-epoch
  • Maior clip-gradient
  • Ativar normalize (possivelmente; +0.023 de AUC do melhor experimento com normalização para o melhor sem normalização)
  • Menor batch-size

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 20, 2023

image
image

Conclusões atualizadas: não está mais tão claro que hparams são melhores, exceto que clip-gradient aparentemente não pode ser desativado. Quase todos experimentos (11/13) com clip-gradient=0 tiverem auc < 0.71. Foram esses experimentos com convergência rápida seguida de uma posterior decadência.

Ontem havia agendado mais experimentos para clip-gradient de 2 e 2.5 com batch-size de 16 e 32. Resultados já estão nos plots acima. Coloquei mais experimentos com batch-size de 8 e 44.

guild run train --stage-trials --quiet train-dataset-path=fitw2020/train-faces-det val-dataset-path=fitw2020/val-faces-det insightface-weights=models/ms1mv3_arcface_r100_fp16.pth output-dir=exp 'normalize=[yes,no]' 'clip-gradient=[1, 1.5, 2, 2.5]' 'num-epoch=[20, 50, 100]' 'batch-size=[8, 44]' -y

Questões

Que experimentos são esses que tem um rápido crescimento comparado aos demais?

image

Aparentemente são aqueles que têm clip-gradient=2.5, todavia não consegui avaliar os demais hparams conjuntos.

@vitalwarley
Copy link
Owner Author

Consegui obter os dados do tensorboard e avaliar precisamente aqueles experimentos com rápido crescimento e posterior decrescimento

See plot

epoch_auc_vs_hparams_2023-11-21_15-27-03

clip-gradient = 0 é realmente a causa.

Relativo aos experimentos cujo crescimento é rápido e estável ao longo do treinamento

See plot

epoch_auc_vs_hparams_2023-11-21_15-43-16

batch-size e clip-gradient aparentam serem o diferencial...

@vitalwarley
Copy link
Owner Author

vitalwarley commented Nov 21, 2023

Interessante também notar quais hparams e valores nos dá melhor acurácia.

Ver plot

epoch_acc_vs_hparams_2023-11-21_15-57-55

@vitalwarley
Copy link
Owner Author

Ganho em AUC (discriminação entre parentes ou não) não necessariamente segue ganho em ACC (discriminação entre famílias), mas pode ser falta de exploração. É bom lembrar que até o momento eu variei apenas 4 hparams.

Peek.2023-11-21.16-05.mp4

@vitalwarley
Copy link
Owner Author

Recapitulando os meus objetivos...

  1. Reproduzir estratégias do SOTA2020 com PyTorch
    • Baseline: modelo pré-treinado em reconhecimento facial no MS1MV3 (93k IDs, 5.2M images))
    • Classificação de famílias
    • Classificação de famílias com normalização das features
  2. Reproduzir SOTA2021 com PyTorch (meu código)
    • ResNet101 sem pré-treino em reconhecimento facial, mas treinada diretamente em verificação de parentesco com perda contrastiva
  3. Mesclar SOTA2020 e SOTA2021
    • Usar modelo resultante do treinamento de classificação de famílias em uma tarefa de verificação de parentesco

A razão para esse 3o objetivo (principal objetivo) é a seguinte. O SOTA2020 aprende a discriminar parentesco usando, em parte, atributos úteis à classificação de famílias. Em parte, pois, como podemos ver no gráfico 2, a acurácia de classificação de famílias (epoch_acc) não passa de 0.5 para os melhores modelos de verificação de parentesco (aqueles com maior epoch_auc) -- incrível ou estranhamente, epoch_acc assume maiores valores quando clip-gradient = 0 (ver comentário e gráfico 1). Nesses casos, podemos dizer que a rede preserva atributos úteis à classificação de famílias enquanto desenvolve atributos úteis à discriminação de parentesco para todas as famílias. Esses atributos tem origem "familiar", isso é, alguns atributos que ajudam a discriminar famílias, indiretamente ajudam a discriminar parentesco, porque inevitavelmente famílias diferentes (logo parentescos) estão distantes uma das outras.

Em outras palavras, podemos dizer que há uma combinação de features para reconhecimento facial (aprendido pelo modelo baseline) e reconhecimento de parentesco (aprendido estratégia do SOTA2020), que acaba culminando nas features para verificação de parentesco. Nesse sentido, o SOTA2021 vem à calhar: a perda contrastiva compara uma amostra com outras 2 * (batch_size^2 - batch_size) amostras negativas. O modelo é ensinado a aprender features mais "genéricas" no que diz respeito a discriminação de parentesco -- features que talvez não sejam "familiares".

A minha estratégia, portanto, visa responder: é possível combinar as features do modelo SOTA2020 (reconhecimento facial, reconhecimento de famílias, reconhecimento de parentesco indireto) com as features do modelo SOTA2021 (reconhecimento de parentesco direto)?

Para o primeiro objetivo, foram mais de 200 experimentos com diferentes variações em alguns hparams

  • batch-size
  • clip-gradient
  • normalize
  • num-epoch

Enquanto que não consegui reproduzir fielmente o melhor resultado do SOTA2020 (0.7912), ao menos cheguei perto em alguns casos.

Próximos passos

  • Complementar train.py para treinamento de verificação de parentesco como no SOTA2021

Gráficos

Gráfico 1: melhor experimento com clip-gradient=0

image

Comparado aos melhores experimentos abaixo, como explicar a diferença no epoch_acc e epoch_auc? Apresentei uma ideia aqui.

Gráfico 2: scatter plot dos experimentos realizados

image

Gráfico 3: melhor experimento com normalize=false

image

Gráfico 4: melhor experimento com normalize=true

image

vitalwarley added a commit that referenced this issue Nov 26, 2023
@vitalwarley
Copy link
Owner Author

  • Complementar train.py para treinamento de verificação de parentesco como no SOTA2021

image
image
image

Resultados com diferentes modelos: R101 sem pré-treino, R101 pré-treinada no MS1MV3, R101 após pré-treino na MS1MV3 (reconhecimento facial) e FIW (classificação de famílias). Esse último modelo não foi o melhor que consegui, mas o melhor que eu tinha disponível no notebook -- os demais estão na RIG1. Mantive todos os outros hparams iguais (bs, lr, beta, passos por época), exceto número de épocas, que foram 20 em vez de 80, para ter um feedback mais rápido, todavia, implementação da validação completa (para encontrar o limiar) e do teste adicionaram 8min por época.

Os resultados anteriores, com script original, estão descritos aqui.

Resultados publicados

  • AUC: não publicado
  • Limiar: não publicado.
  • Acurácia: 0.80

Resultados obtidos via reprodução com scripts originais

  • AUC para seleção do modelo: 0.865929 (local) / 0.864550 (RIG)
  • AUC para seleção do limiar: 0.8634 (RIG)
  • Limiar: 0.1132 (RIG)
  • Acurácia: 0.7899 (RIG)

Resultados obtidos via reprodução com meus scripts

╚═╡(kinship) [11:26] λ guild compare -Fo train-kv --table -cc run,.time,=batch-size,=insightface-weights,=normalize,=num-epoch,acc,auc,best_threshold_auc,loss,threshold
run       time     batch-size  insightface-weights                                 normalize  num-epoch  acc       auc       best_threshold_auc  loss      threshold
ff026101  3:23:16  25                                                              no         20         0.604156  0.667352  0.660579            3.250999  0.510895
6d8c6c23  3:30:57  25          runs/99799c5e8e32419e91178b1dbe38e770/exp/best.pth  no         20         0.780162  0.836251  0.836983            0.633000  0.522662
a2cf02d7  3:25:36  25          models/ms1mv3_arcface_r100_fp16.pth                 no         20         0.794480  0.851867  0.856323            0.884999  0.517818
  • auc refere-se à AUC para seleção do modelo durante o treinamento
    • Só agora percebi que as demais métricas são computadas para qualquer modelo durante o treinamento.
  • best_threshold_auc refere-se à melhor AUC para seleção do threshold -- é outro conjunto de validação mesmo, 20x maior
  • acc refere-se à acurácia do modelo no test set usando threshold

Podemos ver que a2cf02d7, o experimento que usou o modelo pré-treinado em reconhecimento facial (sem ajuste fino em classificação de famílias), teve o melhor resultado de acurácia média (0.794480) comparado ao resultado que obtive (0.7899) . Nos gráficos acima, no entanto, o melhor resultado desse experimento (0.7968) acontece antes (época 13).

@vitalwarley
Copy link
Owner Author

É importante notar que o conjunto de dados usado para AUC obtida pelo SOTA2020 difere daquele do SOTA2021.

Assim que a RIG1 ficar online, resgatarei o melhor modelo relativo ao SOTA2020 para um novo experimento. Vou desativar a computação das métricas best_threshold_auc e acc durante o treinamento por duas razões: 1) vazamento de dados/contaminação do modelo, dado que invariavelmente vou olhar para essas métricas; 2) custo de tempo.

vitalwarley added a commit that referenced this issue Nov 27, 2023
@vitalwarley
Copy link
Owner Author

vitalwarley commented Dec 1, 2023

Resgatei o melhor modelo treinado no esquema do SOTA2020 (classificação de famílias) e o usei em alguns experimentos variando tamanho do batch e taxa de aprendizado.

guild run train-kv --stage-trials --background  root-dir=rfiw2021/Track1 train-dataset-path=rfiw2021/Track1/sample0/train_sort.txt val-dataset-path=rfiw2021/Track1/sample0/val_choose.txt output-dir=exp insightface-weights=runs/36be050267c2473b897b1aa8fb9d3b07/exp/best.pth normalize=yes 'lr=[1e-4, 1e-5, 1e-6]' 'batch-size=[12, 24, 36, 48, 60]' -y

O objetivo é AUC > 0.864550.

@vitalwarley
Copy link
Owner Author

Nenhum experimento conseguiu alcançar o objetivo.

image
image

@vitalwarley
Copy link
Owner Author

#38 (comment)
#46 (comment)

Nada melhor.

image

@vitalwarley
Copy link
Owner Author

Só agora notei que usei um beta extremamente alto.

image

@vitalwarley
Copy link
Owner Author

Despachando mais alguns experimentos.

You are about to stage trials for train-kv as a batch (18 trials)
  batch-size: 10
  beta: [0.02, 0.05, 0.08]
  device: '0'
  insightface-weights: models/ms1mv3_arcface_r100_fp16.pth
  lr: 0.0001
  normalize: [yes, no]
  num-classes: 570
  num-epoch: [80, 100, 105]
  output-dir: exp
  root-dir: rfiw2021/Track1
  steps-per-epoch: 100
  train-dataset-path: rfiw2021/Track1/sample0/train_sort.txt
  val-dataset-path: rfiw2021/Track1/sample0/val_choose.txt
Continue? (Y/n)

Fico pensando na lr também. No gráfico do comentário temos um crescimeento rápido antes do degradamento do modelo.

@vitalwarley
Copy link
Owner Author

Despachando mais alguns experimentos.

You are about to stage trials for train-kv as a batch (18 trials)
  batch-size: 10
  beta: [0.02, 0.05, 0.08]
  device: '0'
  insightface-weights: models/ms1mv3_arcface_r100_fp16.pth
  lr: 0.0001
  normalize: [yes, no]
  num-classes: 570
  num-epoch: [80, 100, 105]
  output-dir: exp
  root-dir: rfiw2021/Track1
  steps-per-epoch: 100
  train-dataset-path: rfiw2021/Track1/sample0/train_sort.txt
  val-dataset-path: rfiw2021/Track1/sample0/val_choose.txt
Continue? (Y/n)

Fico pensando na lr também. No gráfico do comentário temos um crescimeento rápido antes do degradamento do modelo.

#46 (comment)

@vitalwarley
Copy link
Owner Author

vitalwarley commented Dec 10, 2023

Despachando mais alguns experimentos.

You are about to stage trials for train-kv as a batch (18 trials)
  batch-size: 10
  beta: [0.02, 0.05, 0.08]
  device: '0'
  insightface-weights: models/ms1mv3_arcface_r100_fp16.pth
  lr: 0.0001
  normalize: [yes, no]
  num-classes: 570
  num-epoch: [80, 100, 105]
  output-dir: exp
  root-dir: rfiw2021/Track1
  steps-per-epoch: 100
  train-dataset-path: rfiw2021/Track1/sample0/train_sort.txt
  val-dataset-path: rfiw2021/Track1/sample0/val_choose.txt
Continue? (Y/n)

De fato, um beta menor, mas não muito, tende a dar melhores resultados em AUC. Todavia, resultados ainda são aquém do ideal (>0.86). O batch de 10 não melhora os resultados, ao contrário do que eu tinha suspeitado.

image
image

Por outro lado, o treino é mais estável, isso é, AUC não decresce drasticamente ao longo do treino.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant