Haru's 개발 블로그

[NLP] 한국어 경진 대회 Tip(Kospeech) 본문

머신러닝 & 딥러닝/NLP(자연어 처리)

[NLP] 한국어 경진 대회 Tip(Kospeech)

Haru_29 2023. 5. 16. 07:19

전 포스트에서는 대회에서 사용한 Kospeech에서 사용한 모델 Deep Speech2를 알아보았습니다. 이번에는 작년에 참가한 대회에서 현재는 학습을 다시하기에는 제약이 많지만 어떠한 변화를 주었는지에 대해 알아보려고 합니다.

 

대회 Tip

1. Epoch 변화주기 : Epoch 20회까지 숫자를 늘려주어서 학습을 시켰을 때 가장 train_loss, train_cer, val_loss, val_cer이 가장 낮았습니다. 그리고 20회이상 학습을 진행하니까 타임에러가 나왔고 유의미한 학습결과가 나오지 않았습니다.

args = argparse.ArgumentParser()

    # DONOTCHANGE: They are reserved for nsml
    args.add_argument('--mode', type=str, default='train', help='submit일때 해당값이 test로 설정됩니다.')
    args.add_argument('--iteration', type=str, default='0',
                      help='fork 명령어를 입력할때의 체크포인트로 설정됩니다. 체크포인트 옵션을 안주면 마지막 wall time 의 model 을 가져옵니다.')
    args.add_argument('--pause', type=int, default=0, help='model 을 load 할때 1로 설정됩니다.')

    args.add_argument('--use_cuda', type=bool, default=True)
    args.add_argument('--seed', type=int, default=42)
    args.add_argument('--num_epochs', type=int, default=20)
    args.add_argument('--batch_size', type=int, default=64)
    args.add_argument('--save_result_every', type=int, default=10)
    args.add_argument('--checkpoint_every', type=int, default=1)
    args.add_argument('--print_every', type=int, default=50)
    args.add_argument('--dataset', type=str, default='kspon')
    args.add_argument('--output_unit', type=str, default='character')
    args.add_argument('--num_workers', type=int, default=8)
    args.add_argument('--num_threads', type=int, default=16)
    args.add_argument('--init_lr', type=float, default=1e-06)
    args.add_argument('--final_lr', type=float, default=1e-06)
    args.add_argument('--peak_lr', type=float, default=1e-04)
    args.add_argument('--init_lr_scale', type=float, default=1e-02)
    args.add_argument('--final_lr_scale', type=float, default=5e-02)
    args.add_argument('--max_grad_norm', type=int, default=400)
    args.add_argument('--warmup_steps', type=int, default=1000)
    args.add_argument('--weight_decay', type=float, default=1e-05)
    args.add_argument('--reduction', type=str, default='mean')
    args.add_argument('--optimizer', type=str, default='adam')
    args.add_argument('--lr_scheduler', type=str, default='tri_stage_lr_scheduler')
    args.add_argument('--total_steps', type=int, default=200000)

    args.add_argument('--architecture', type=str, default='deepspeech2')
    args.add_argument('--use_bidirectional', type=bool, default=True)
    args.add_argument('--dropout', type=float, default=3e-01)
    args.add_argument('--num_encoder_layers', type=int, default=5)
    args.add_argument('--hidden_dim', type=int, default=1024)
    args.add_argument('--rnn_type', type=str, default='gru')
    args.add_argument('--max_len', type=int, default=400)
    args.add_argument('--activation', type=str, default='swish')
    args.add_argument('--teacher_forcing_ratio', type=float, default=1.0)
    args.add_argument('--teacher_forcing_step', type=float, default=0.0)
    args.add_argument('--min_teacher_forcing_ratio', type=float, default=1.0)
    args.add_argument('--joint_ctc_attention', type=bool, default=False)

    args.add_argument('--audio_extension', type=str, default='pcm')
    args.add_argument('--transform_method', type=str, default='fbank')
    args.add_argument('--feature_extract_by', type=str, default='kaldi')
    args.add_argument('--sample_rate', type=int, default=16000)
    args.add_argument('--frame_length', type=int, default=20)
    args.add_argument('--frame_shift', type=int, default=10)
    args.add_argument('--n_mels', type=int, default=80)
    args.add_argument('--freq_mask_para', type=int, default=18)
    args.add_argument('--time_mask_num', type=int, default=4)
    args.add_argument('--freq_mask_num', type=int, default=2)
    args.add_argument('--normalize', type=bool, default=True)
    args.add_argument('--del_silence', type=bool, default=True)
    args.add_argument('--spec_augment', type=bool, default=True)
    args.add_argument('--input_reverse', type=bool, default=False)
self.conv = MaskCNN(
    nn.Sequential(
        nn.Conv2d(in_channels, out_channels, kernel_size=(41, 11), stride=(2, 2), padding=(20, 5), bias=False),
        nn.BatchNorm2d(out_channels),
        self.activation,
        nn.Conv2d(out_channels, out_channels, kernel_size=(21, 11), stride=(2, 1), padding=(10, 5), bias=False),
        nn.BatchNorm2d(out_channels),
        self.activation,
        #add 
    )
)
Checkpoint    Last Modified    Elapsed    Summary                                                                                                                                               Size
------------  ---------------  ---------  ----------------------------------------------------------------------------------------------------------------------------------------------------  -------
0             a day ago        11.760     epoch=0, train_loss=3.5592618863195438, train_cer=1.0764494612621858, val_loss=2.1020547920237473, val_cer=0.9766991930091087, number_of_files=1      1.01 GB
1             a day ago        4819.383   epoch=1, train_loss=1.7348406653526502, train_cer=0.7681894847567058, val_loss=1.5426763180500822, val_cer=0.7353026486030224, number_of_files=1      1.01 GB
2             a day ago        4810.987   epoch=2, train_loss=1.343946157928206, train_cer=0.644515216183276, val_loss=1.336513099937491, val_cer=0.6284053427386435, number_of_files=1         1.01 GB
3             a day ago        4828.580   epoch=3, train_loss=1.1266134636014955, train_cer=0.572658149809912, val_loss=1.2246161554354789, val_cer=0.5623228104036795, number_of_files=1       1.01 GB
4             21 hours ago     4833.185   epoch=4, train_loss=0.9827682919583769, train_cer=0.5243896165779541, val_loss=1.1264683265503639, val_cer=0.5169158122769922, number_of_files=1      1.01 GB
5             19 hours ago     4826.503   epoch=5, train_loss=0.8741946887358641, train_cer=0.48856181702938717, val_loss=1.1012097290141987, val_cer=0.48346853503956516, number_of_files=1    1.01 GB
6             18 hours ago     4822.173   epoch=6, train_loss=0.7936809696499099, train_cer=0.4619070024460985, val_loss=1.0517018914548426, val_cer=0.45802020216989014, number_of_files=1     1.01 GB
7             17 hours ago     4819.652   epoch=7, train_loss=0.7283174455675304, train_cer=0.44024486782060324, val_loss=1.0168149231072983, val_cer=0.4369902831721952, number_of_files=1     1.01 GB
8             15 hours ago     4798.579   epoch=8, train_loss=0.6775418591499328, train_cer=0.4219681634256878, val_loss=1.0210077602192353, val_cer=0.4198425310084487, number_of_files=1      1.01 GB
9             14 hours ago     4824.648   epoch=9, train_loss=0.626589700503227, train_cer=0.4071645996925643, val_loss=1.0050362500010943, val_cer=0.4054895310105189, number_of_files=1       1.01 GB
10            13 hours ago     4834.470   epoch=10, train_loss=0.5894669927389193, train_cer=0.3950662644273343, val_loss=1.0066698152022284, val_cer=0.3937360126213615, number_of_files=1     1.01 GB
11            11 hours ago     4861.094   epoch=11, train_loss=0.5583946103927416, train_cer=0.38415596463732954, val_loss=0.9973278750813073, val_cer=0.383102265476292, number_of_files=1     1.01 GB
12            10 hours ago     4858.129   epoch=12, train_loss=0.5243397537459675, train_cer=0.3746995654320188, val_loss=0.9900300904212753, val_cer=0.37360746688073077, number_of_files=1    1.01 GB
13            9 hours ago      4860.708   epoch=13, train_loss=0.5029882840009836, train_cer=0.3661715906068009, val_loss=0.9904915546296073, val_cer=0.3653241487302998, number_of_files=1     1.01 GB
14            7 hours ago      4839.798   epoch=14, train_loss=0.47899910632361714, train_cer=0.3586874364205705, val_loss=1.0012750718437258, val_cer=0.35798981920551165, number_of_files=1   1.01 GB
15            6 hours ago      4851.247   epoch=15, train_loss=0.46201296367196953, train_cer=0.35211397928088634, val_loss=0.9888368266039207, val_cer=0.35155708950864223, number_of_files=1  1.01 GB
16            5 hours ago      4844.409   epoch=16, train_loss=0.4403798975190546, train_cer=0.34619836146330546, val_loss=0.9912251739716921, val_cer=0.3456515039095942, number_of_files=1    1.01 GB
17            3 hours ago      4860.946   epoch=17, train_loss=0.4302739467885759, train_cer=0.3407571661931043, val_loss=1.005999902639884, val_cer=0.34033988784046504, number_of_files=1     1.01 GB
18            2 hours ago      4859.107   epoch=18, train_loss=0.4149482181133368, train_cer=0.33619895768125246, val_loss=0.9921487165930493, val_cer=0.3360098912764096, number_of_files=1    1.01 GB
19            an hour ago      4856.663   epoch=19, train_loss=0.4026499494426271, train_cer=0.33198544582549194, val_loss=1.0040585714611199, val_cer=0.33184158464586055, number_of_files=1   1.01 GB

 

 

2. Regularization : weight가 너무 높지 않는 값을 가지기 위하여 Regularization은 모델의 복잡도를 낮추는 일을 합니다.

그래서 저는 Regularization 텀을 강하게 줘붜자!라는 생각을 가지게 되어 아래와 같은 변경사항을 주었습니다.

  • 모델 파라미터 수가 많아지고 모델이 깊어지는데, 그걸 뒷받침할 데이터가 부족한 상황
  • 레이어 마다 dropout을 0.8 주고 학습시간을 2-3배 늘림
  • Batch nomalization
    • TDNN/ECAPA-TDNN-1d, ResNet34-2d
  • Dropout (TDNN, ECAPA-TDNN)
    • Dropout rate : 0.8

 

3. Data Augmentation : Data augmentation는 갖고 있는 데이터셋을 여러 가지 방법으로 augment하여 실질적인 학습 데이터셋의 규모를 키울 수 있는 방법입니다. 따라서 저는 아래와 같은 내용을 참고하여 변경사항을 주었습니다.

  • 노이즈를 더해주거나, reverberation을 통과시켜서 데이터를 증강
  • 하지만 Noise도 외부데이터를 가져와서 써야되기 때문에 적용하기 힘듬
  • 그래서 화자 인식에서는 스펙트럼 도메인에서 Masking을 씌우는 방법으로 단순하게 적용
  • 음성 인식에서는 더 다양한 방법이 있는 것으로 알고 있음
    • Mix-up 등
  • SpecAugment
    • Frequency masking(0, 8)
    • Temporal masking(0, 10)

 

4. 앙상블 : 머신 러닝에서 앙상블은 단어 그대로 여러 단순한 모델을 결합하여 정확한 모델을 만드는 방법입니다. 다양한 분야의 머신 러닝 문제를 챌린지의 형태로 해결하는 플랫폼인 Kaggle에서는 복잡한 딥 러닝 알고리즘보다 간단한 머신 러닝 모델을 앙상블 방법을 기반으로 결합한 알고리즘이 우승하는 것을 많이 볼 수 있습니다. 그 만큼 머신러닝에서의 앙상블은 대회에서 좋은 성적을 내는데 중요하고 각 상황별로 모델을 조합시키는 것이 중요하다. 저는 아래와 같은 내용을 참고하여 변경사항을 주었습니다.

  • Weight를 평균
  • 단일 모델의 epoch별 averaged weights를 사용 (SWA)
  • Feature or speech representation-level Ensemble

여기서 SWA는 SGD를 이용하여 optimization을 진행할 때 일정 주기마다 weight를 average하여 를 update 시키는 방법이고 기존의 SGD보다 어 flatter한 solution을 찾는 방법이라고 합니다. 그래서 generalizatoin에 강하여 test셋에서 좋은 성능을 보인다고 합니다. 아래는 다른 블로거 분들깨서 논문을 정리한 내용을 아래 두었습니다.

https://hoya012.github.io/blog/SWA/

 

Averaging Weights Leads to Wider Optima and Better Generalization 리뷰

“Averaging Weights Leads to Wider Optima and Better Generalization” 논문을 리뷰하였습니다.

hoya012.github.io

 

 

 

https://simpling.tistory.com/23

 

논문 리뷰: Averaging Weights Leads to Wider Optima and Better Generalization(SWA)

"Averaging Weights Leads to Wider Optima and Better Generalization" - Pavel Izmailov (2019) 이번 논문은 Stochastic Weigths Averaging(SWA) 방법을 제시한 논문이다. 여러 캐글 대회에서 이 방법을 사용하여 우승을 하는 경우

simpling.tistory.com

 

아쉬웠던점

1. models 탐색 및 선정 : 현재 Kospeech에는 모델의 종류가 아래 7가지가 존재합니다.

1) Deep Speech 2

2) Listen, Attend and Spell (LAS)

3) Joint CTC-Attention LAS

4) RNN-Transducer

5) Speech Transformer

6) Jasper

7) Conformer

 

그때 당시에는 코드를 변경시켜서 Conformer만 테스트를 하였었는데 좋은 결과는 나오지 않았습니다. 그 뒤에 다른 모델을 변경시킬려고 했지만 학습하는데 계속해서 에러가 나와서 다른 글에서 Deep Speech2가 가장 효과적이었다라는 말을 들어서 Deep Speech2로 진행을 하였는데 다시 한번 한다면 여러 모델로 학습을 시킨다음 유의미한 데이터를 뽑을 것 입니다. 참고로 Kospeech에서는 여러 모델이 구현되어 있는데 각각에 코멘트를 달았습니다.

 

1. Deep Speech 2
Deep Speech 2는 연결주의 시간 분류(CTC) 손실이 있는 ASR 작업에서 더 빠르고 정확한 성능을 보여주었습니다. 이 모델은 이전의 엔드 투 엔드 모델에 비해 성능이 크게 향상된 것으로 강조되었습니다.

2. Listen, Attend and Spell (LAS)
이전에 "듣기, 참여 및 맞춤법"에서 제안한 아키텍처를 따르지만 성능 향상을 위해 일부 수정 사항이 추가되었습니다. 우리는 확장된 닷 제품 주의, 추가 주의, 위치 인식 주의, 다중 헤드 주의의 네 가지 다른 주의 메커니즘을 제공합니다. 주의 메커니즘은 모델의 성능에 많은 영향을 미칩니다.

3. RNN-Transducer
RNN-트랜스듀서는 주의 메커니즘을 사용하지 않는 시퀀스 대 시퀀스 모델의 한 형태입니다. 일반적으로 출력(문장)을 생성하기 위해 전체 입력 시퀀스(우리의 경우 파형)를 처리해야 하는 대부분의 시퀀스 대 시퀀스 모델과 달리, RNN-T는 입력 샘플을 지속적으로 처리하고 출력 기호를 스트리밍하여 음성 받아쓰기에 적합한 속성입니다. 우리의 구현에서 출력 기호는 알파벳의 문자입니다.

4. Speech Transformer
transformers는 자연어 처리(NLP) 분야의 강력한 아키텍처입니다. 이 아키텍처는 ASR 작업에서도 우수한 성능을 보였습니다. 또한 자연어 처리 분야에서 이 모델의 연구가 계속됨에 따라 이 모델은 추가적인 발전 가능성이 높습니다.

5. Joint CTC-Attention
제안된 아키텍처를 통해 CTC 기반 모델과 주의 기반 모델을 모두 활용할 수 있습니다. 인코더에 CTC를 추가하여 견고하게 만드는 구조입니다. 공동 CTC-주의는 LAS 및 음성 변환기와 함께 훈련될 수 있습니다.

6. Jasper
Jasper(Just Another Speech Recognizer)는 단대단 컨볼루션 신경 음향 모델입니다. Jasper는 CNN → BatchNorm → ReLU → 드롭아웃 블록 및 주거용 연결만으로 강력한 성능을 보여주었습니다.

7. Conformer
Conformer는 컨볼루션 neural networks와 transformers을 결합하여 오디오 시퀀스의 로컬 및 글로벌 종속성을 매개 변수 효율적인 방식으로 모델링합니다. Conformer는 최첨단 정확도를 달성하는 이전 트랜스포머 및 CNN 기반 모델을 크게 능가합니다.

 

그리고 아래의 사이트(Papers with Code)의 NLP항목에 들어가면 현재 핫한 다양한 SOTA 모델들을 한눈에 확인이 가능합니다.https://paperswithcode.com/sota

 

Papers with Code - Browse the State-of-the-Art in Machine Learning

11059 leaderboards • 4134 tasks • 8124 datasets • 95063 papers with code.

paperswithcode.com

 

2. Test Time Augmentation : Test Time Augmentation은 모델을 학습할 때에도 Data Argumentation을 한다는 것인데 이것이 학습을 할 때에 유의미한 결과를 찾지는 못했습니다. 당시에는 내용에 대한 이해도가 부족해서 아쉬웠습니다.

 

3. 마지막으로 처음 대규모 데이터를 활용하는 대회에 참여한 소감으로서 이렇게 좋은 환경에서 시험을 하는데 시간이 오래걸린다는 점에서 다시 한번 제약을 느끼기도 하였고 대규모 데이터 학습 경험을 가지게 되어 아래와 같은 내용을 주의해야된다라는걸 느끼게 되었습니다.

 

  1. 데이터 품질: 대규모 데이터를 사용하는 경우, 데이터의 품질을 유지하는 것이 중요합니다. 오류가 있는 데이터, 잘못된 레이블 또는 잡음이 있는 데이터는 모델의 성능을 저하시킬 수 있습니다. 그러한 경우에는 데이터를 선별하고 정제하여 품질을 향상시키는 작업이 필요합니다.
  2. 중복 및 다양성: 대규모 데이터셋에서 중복된 데이터의 존재 및 데이터의 다양성을 확인해야 합니다. 중복 데이터는 학습 과정에서 가중치를 과도하게 갖게 하고, 다양성 부족은 모델의 일반화 능력을 저하시킬 수 있습니다. 중복 데이터를 제거하고 다양한 데이터를 포함하는지 확인하여 학습 데이터의 품질을 개선할 수 있습니다.
  3. 사전 처리: 대규모 데이터를 학습하기 전에 데이터를 사전 처리하는 것이 중요합니다. 이는 토큰화, 정규화, 불용어 제거, 특수 문자 제거 등과 같은 작업을 포함할 수 있습니다. 이러한 사전 처리 단계는 데이터의 일관성을 유지하고 모델의 학습 효과를 향상시키는 데 도움이 됩니다.
  4. 컴퓨팅 자원: 대규모 언어 모델을 학습하는 데에는 많은 컴퓨팅 자원이 필요합니다. 학습에 필요한 하드웨어를 충분히 확보하고, 학습 파라미터를 조정하여 모델의 크기와 복잡도를 조절해야 합니다.
  5. 모델 복잡성: 대규모 데이터를 학습할 때 모델의 복잡성에 유의해야 합니다. 과도하게 복잡한 모델은 학습 데이터에 과적합될 수 있으며 일반화 능력이 저하될 수 있습니다. 적절한 모델 아키텍처와 파라미터를 선택하여 모델의 복잡성을 조절해야 합니다.
  6. 학습 시간: 대규모 데이터셋을 학습하는 작업은 시간이 많이 소요될 수 있습니다. 따라서 학습 시간을 고려하여 학습 일정을 계획하고 작업을 분산하거나 병렬화할 수 있는지 확인해야 합니다. → 평균 14시간

그리고 추후에는 언어 모델(BERT, ELECTRA 등)들도 공부를 해야겠다라는 점을 알게 되었습니다. 짧지만 2달동안 기존에는 이미지 분류를 통하여 AI에 대해 공부를 진행하였는데 NLP라는 새로운 분야를 경험을 하게되었고 그때부터 좋은 기억을 남게 되어서 현재까지 계속해서 공부를 진행해오고 있습니다.

 

Comments