Skip to content

bcaitech1/p4-dkt-no_caffeine_no_gain

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“ No Caffeine No Gain


ν”„λ‘œμ νŠΈ κΈ°κ°„ : 2021.05.24 ~ 2021.06.15

ν”„λ‘œμ νŠΈ 주제 : Deep Knowledge Tracing

[λͺ©μ°¨]



[Deep Knowledge Tracing μ†Œκ°œ]

DKTλŠ” Deep Knowledge Tracing의 μ•½μžλ‘œ 우리의 "지식 μƒνƒœ"λ₯Ό μΆ”μ ν•˜λŠ” λ”₯λŸ¬λ‹ λ°©λ²•λ‘ μž…λ‹ˆλ‹€.


λŒ€νšŒμ—μ„œλŠ” 학생 개개인의 이해도λ₯Ό κ°€λ¦¬ν‚€λŠ” 지식 μƒνƒœλ₯Ό μ˜ˆμΈ‘ν•˜λŠ” μΌλ³΄λ‹€λŠ”, 주어진 문제λ₯Ό λ§žμΆœμ§€ 틀릴지 μ˜ˆμΈ‘ν•˜λŠ” 것에 μ§‘μ€‘ν•©λ‹ˆλ‹€.



[Installation]

Dependencies

  • torch
  • pandas
  • sklearn
  • pycaret
  • tqdm
  • wandb
  • easydict
  • pytorch-tabnet
pip install -r requirements.txt


[Usage]

Dataset

ν•™μŠ΅μ— ν•„μš”ν•œ 데이터λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ 두 개의 .py νŒŒμΌμ„ 순차적으둜 μ‹€ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€.

$ p4-dkt-no_caffeine_no_gain# python make_elapsed.py
$ p4-dkt-no_caffeine_no_gain# python make_fixed_data.py

Train

λͺ¨λΈμ„ ν•™μŠ΅ν•˜κΈ° μœ„ν•΄μ„œλŠ” train.py λ₯Ό μ‹€ν–‰μ‹œν‚΅λ‹ˆλ‹€.

μ•„λž˜ Arguments 에 μžˆλŠ” argument 쀑 ν•„μš”ν•œ argumet λ₯Ό λ°”κΏ” μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

$ p4-dkt-no_caffeine_no_gain# python train.py

총 7κ°€μ§€μ˜ λͺ¨λΈμ„ 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • TABNET
  • LASTQUERY
  • SAINT
  • LGBM
  • BERT
  • LSTMATTN
  • LSTM

Inference

ν•™μŠ΅λœ λͺ¨λΈλ‘œ μΆ”λ‘ ν•˜κΈ° μœ„ν•΄μ„œλŠ” inference.py λ₯Ό μ‹€ν–‰μ‹œν‚΅λ‹ˆλ‹€.

ν•„μš”ν•œ argument λŠ” β€”-model_name κ³Ό β€”-model_epoch μž…λ‹ˆλ‹€.

$ p4-dkt-no_caffeine_no_gain# python inference.py --model_name "ν•™μŠ΅ν•œ λͺ¨λΈ 폴더 이름" --model_epoch "μ‚¬μš©ν•˜κ³ ν”ˆ λͺ¨λΈμ˜ epoch"

Arguments

train κ³Ό inference μ—μ„œ ν•„μš”ν•œ argument μž…λ‹ˆλ‹€.

# Basic
--model: model type (default:'lstm')
--scheduler: scheduler type (default:'plateau')
--device: device to use (defualt:'cpu')
--data_dir: data directory (default:'/opt/ml/input/data/train_dataset')
--asset_dir: asset directory (default:'asset/')
--train_file_name: train file name (default:'add_FE_fixed_train.csv')
--valid_file_name: validation file name (default:'add_FE_fixed_valid.csv')
--test_file_name: test file name (default:'add_FE_fixed_test.csv')
--model_dir: model directory (default:'models/')
--num_workers: number of workers (default:1)
--output_dir: output directory (default:'output/')
--output_file: output file name (default:'output')
--model_name: model folder name (default:'')
--model_epoch: model epoch to use (default:1)

# Hyperparameters
--seed: random state (default:42)
--optimizer: optimizer type (default:'adamW')
--max_seq_len: max sequence length (default:20)
--hidden_dim: hidden dimension size (default:64)
--n_layers: number of layers (default:2)
--n_epochs: number of epochs (default:20)
--batch_size: batch size (default:64)
--lr: learning rate (default:1e-4)
--clip_grad: clip grad (default:10)
--patience: for early stopping (default:5)
--drop_out: drop out rate (default:0.2)
--dim_div: hidden dimension dividor in model to prevent too be large scale (default:3)

# Transformer
--n_heads: number of heads (default:2)
--is_decoder: use transformer decoder (default:True)

# TabNet
--tabnet_pretrain: Using TabNet pretrain (default:False)
--use_test_to_train: to training includes test data (default:False)
--tabnet_scheduler: TabNet scheduler (default:'steplr')
--tabnet_optimizer: TabNet optimizer (default:'adam')
--tabnet_lr: TabNet learning rate (default:2e-2)
--tabnet_batchsize: TabNet batchsize (default:16384)
--tabnet_n_step: TabNet n step(not log step) (default:5)
--tabnet_gamma: TabNet gamma (default:1.7)
--tabnet_mask_type: TabNet mask type (default:'saprsemax')
--tabnet_virtual_batchsize: TabNet virtual batchsize (default:256)
--tabnet_pretraining_ratio: TabNet pretraining ratio (default:0.8)

# Sliding Window
--window: Using Sliding Window augmentation (default:False)
--shuffle: shuffle Sliding Window (default:False)
--stride: Sliding Window stride (default:20)
--shuffle_n: Shuffle times (default:1)

# T-Fixup
--Tfixup: Using T-Fixup (default:False)
--layer_norm: T-Fixup with layer norm (default:False)

# Pseudo Labeling
--use_pseudo: Using Pseudo Labeling (default:False)
--pseudo_label_file: file path for Pseudo Labeling (default:'')

# log
--log_steps: print log per n steps (default:50)

# wandb
--use_wandb: if you want to use wandb (default:True)


[File Structure]

전체적인 File Structure μž…λ‹ˆλ‹€.

code
β”œβ”€β”€ README.md
β”œβ”€β”€ .gitignore
β”œβ”€β”€ args.py
β”œβ”€β”€ make_custom_data
β”‚   β”œβ”€β”€ make_elapsed.py - time κ΄€λ ¨ feature 생성
β”‚   β”œβ”€β”€ make_fixed_data.py - user μ •λ‹΅λ₯  기반으둜 valid 생성
β”‚   └── make_original_fixed_data.py - shuffleν•΄μ„œ valid 생성
β”‚
β”œβ”€β”€ dkt
β”‚   β”œβ”€β”€ criterion.py
β”‚   β”œβ”€β”€ dataloader.py
β”‚   β”œβ”€β”€ metric.py
β”‚   β”œβ”€β”€ model.py
β”‚   β”œβ”€β”€ optimizer.py
β”‚   β”œβ”€β”€ scheduler.py
β”‚   β”œβ”€β”€ trainer.py
β”‚   └── utils.py
β”œβ”€β”€ ensemble.py
β”œβ”€β”€ inference.py
β”œβ”€β”€ requirements.txt - dependencies
└── train.py



LSTM


  • sequence dataλ₯Ό 닀루기 μœ„ν•œ LSTM λͺ¨λΈμž…λ‹ˆλ‹€.

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class LSTM
    β”‚   β”œβ”€β”€ init()
    └── └── forward() : return predicts
    
    args.py
    β”œβ”€β”€ args.max_seq_len(default : 20)
    β”œβ”€β”€ args.n_layers(default : 2)
    β”œβ”€β”€ args.n_heads(default : 2)
    └── args.hidden_dim(default : 64)
    


LSTMATTN


  • LSTM λͺ¨λΈμ— Self-Attention을 μΆ”κ°€ν•œ λͺ¨λΈμž…λ‹ˆλ‹€.

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class LSTMATTN
    β”‚   β”œβ”€β”€ init()
    └── └── forward() : return predicts
    
    args.py
    β”œβ”€β”€ args.max_seq_len(default : 20)
    β”œβ”€β”€ args.n_layers(default : 2)
    β”œβ”€β”€ args.n_heads(default : 2)
    └── args.hidden_dim(default : 64)
    


BERT


  • Huggingface μ—μ„œ BERT ꡬ쑰λ₯Ό κ°€μ Έμ™€μ„œ μ‚¬μš©ν•©λ‹ˆλ‹€. λ‹€λ§Œ, pre-trained λͺ¨λΈμ΄ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— Transformer-encoder 와 κ°™μŠ΅λ‹ˆλ‹€.

  • ν˜„μž¬ λͺ¨λΈμ—μ„œλŠ” bert_config 의 is_decoder λ₯Ό True 둜 μ£Όμ–΄ Transformer-decoder 둜 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class Bert
    β”‚   β”œβ”€β”€ init()
    └── └── forward() : return predicts
    
    args.py
    β”œβ”€β”€ args.max_seq_len(default : 20)
    β”œβ”€β”€ args.n_layers(default : 2)
    β”œβ”€β”€ args.n_heads(default : 2)
    β”œβ”€β”€ args.is_decoder(default : True)
    └── args.hidden_dim(default : 64)
    


LGBM


  • tabular dataμ—μ„œ 쒋은 μ„±λŠ₯을 λ³΄μ΄λŠ” Machine Learning λͺ¨λΈμž…λ‹ˆλ‹€.

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class LGBM
    β”‚   β”œβ”€β”€ init()
    └── └── fit() : return trained model
    


SAINT


  • Kaggle Riiid AIEd Challenge 2020의 Hostκ°€ μ œμ‹œν•œ solution μž…λ‹ˆλ‹€.

  • Transformer와 λΉ„μŠ·ν•œ ꡬ쑰의 λͺ¨λΈλ‘œ Encoder와 Decoderλ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€.

  • μΈμ½”λ”λŠ” feature μž„λ² λ”© μŠ€νŠΈλ¦Όμ— self-attention λ ˆμ΄μ–΄λ₯Ό μ μš©ν•˜κ³  λ””μ½”λ”μ—μ„œ self-attention λ ˆμ΄μ–΄μ™€ 인코더-디코더 attention λ ˆμ΄μ–΄λ₯Ό 응닡 μž„λ² λ”©κ³Ό μΈμ½”λ”μ˜ 좜λ ₯ μŠ€νŠΈλ¦Όμ— λ²ˆκ°ˆμ•„ μ μš©ν•˜λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

  • Paper Review : [Saint λͺ¨λΈ 뢄석]

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class Saint
    β”‚   β”œβ”€β”€ init()
    └── └── forward() : return predicts
    
    args.py
    β”œβ”€β”€ args.max_seq_len(default : 20)
    β”œβ”€β”€ args.n_layers(default : 2)
    β”œβ”€β”€ args.n_heads(default : 2)
    └── args.hidden_dim(default : 64)
    


LastQuery


  • Kaggle Riiid AIEd Challenge 2020의 1st place solutionμž…λ‹ˆλ‹€.

  • transformer encoder의 μž…λ ₯으둜 sequence의 λ§ˆμ§€λ§‰ query만 μ‚¬μš©ν•˜μ—¬ μ‹œκ°„λ³΅μž‘λ„λ₯Ό 쀄이고, encoder의 output을 LSTM에 λ„£μ–΄ ν•™μŠ΅ν•˜λŠ” λ°©μ‹μ˜ λͺ¨λΈμž…λ‹ˆλ‹€.

  • Paper Review : [Last Query Transformer RNN for knowledge tracing 리뷰]

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class LastQuery
    β”‚   β”œβ”€β”€ init()
    └── └── forward() : return predicts
    
    args.py
    β”œβ”€β”€ args.max_seq_len(default : 20)
    β”œβ”€β”€ args.n_layers(default : 2)
    β”œβ”€β”€ args.n_heads(default : 2)
    β”œβ”€β”€ args.hidden_dim(default : 64)
    └── args.Tfixup(default : False)
    


TABNET


  • tabular dataμ—μ„œ MLλͺ¨λΈλ³΄λ‹€ 더 μš°μˆ˜ν•œ μ„±λŠ₯을 λ³΄μ΄λŠ” Deep-learning modelμž…λ‹ˆλ‹€.

  • dataμ—μ„œ Sparse instance-wise feature selection을 μ‚¬μš©ν•˜μ—¬ 자체적으둜 μ€‘μš”ν•œ feature 선별해낸 ν›„ ν•™μŠ΅ν•˜λŠ” 방식을 μ‚¬μš©ν•˜λ©°, feature μ„ λ³„μ‹œ non-linearν•œ processing을 μ‚¬μš©ν•˜μ—¬ learning capacityλ₯Ό ν–₯μƒμ‹œν‚΅λ‹ˆλ‹€.

  • Sequentialν•œ multi-step architectureλ₯Ό κ°€μ§€κ³ μžˆμœΌλ©°, feature masking으둜 Unsupervised ν•™μŠ΅λ„ κ°€λŠ₯ν•©λ‹ˆλ‹€.

  • Paper Review : [Tabnet λ…Όλ¬Έ 리뷰]

  • κ΅¬ν˜„

    model.py
    β”œβ”€β”€ class TabNet
    β”‚   β”œβ”€β”€ TabNetPreTrainer
    β”‚   β”œβ”€β”€ TabNetClassifier
    β”‚   β”œβ”€β”€ get_scheduler()
    β”‚   β”œβ”€β”€ get_optimizer()
    └── └── forward() : return models
    
    trainer.py
    β”œβ”€β”€ tabnet_run(args, train_data, valid_data)
    β”œβ”€β”€ get_tabnet_model(args)
    └── tabnet_inference(args, test_data)
    
    train.py
    └── tabnet_run()
    
    args.py
    β”œβ”€β”€ args.tabnet_pretrain(default : False)
    β”œβ”€β”€ args.use_test_to_train(default : False)
    β”œβ”€β”€ args.tabnet_scheduler(default:'steplr')
    β”œβ”€β”€ args.tabnet_optimizer(default:'adam')
    β”œβ”€β”€ args.tabnet_lr(default:2e-2)
    β”œβ”€β”€ args.tabnet_batchsize(default:16384)
    β”œβ”€β”€ args.tabnet_n_step(default:5)
    β”œβ”€β”€ args.tabnet_gamma(default:1.7)
    β”œβ”€β”€ args.tabnet_mask_type(default:'saprsemax')
    β”œβ”€β”€ args.tabnet_virtual_batchsize(default:256)
    └── args.tabnet_pretraining_ratio(default:0.8)
    

[Input CSV File]

λ°μ΄ν„°λŠ” μ•„λž˜μ™€ 같은 ν˜•νƒœμ΄λ©°, ν•œ 행은 ν•œ μ‚¬μš©μžκ°€ ν•œ 문항을 ν’€μ—ˆμ„ λ•Œμ˜ 정보와 κ·Έ 문항을 λ§žμ·„λŠ”μ§€μ— λŒ€ν•œ 정보가 담겨져 μžˆμŠ΅λ‹ˆλ‹€. λ°μ΄ν„°λŠ” λͺ¨λ‘ Timestamp κΈ°μ€€μœΌλ‘œ μ •λ ¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.


  • userID μ‚¬μš©μžμ˜ κ³ μœ λ²ˆν˜Έμž…λ‹ˆλ‹€. 총 7,442λͺ…μ˜ 고유 μ‚¬μš©μžκ°€ 있으며, train/test셋은 이 userIDλ₯Ό κΈ°μ€€μœΌλ‘œ 90/10의 λΉ„μœ¨λ‘œ λ‚˜λˆ„μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.
  • assessmentItemID λ¬Έν•­μ˜ κ³ μœ λ²ˆν˜Έμž…λ‹ˆλ‹€. 총 9,454개의 고유 문항이 μžˆμŠ΅λ‹ˆλ‹€.
  • testId μ‹œν—˜μ§€μ˜ κ³ μœ λ²ˆν˜Έμž…λ‹ˆλ‹€. λ¬Έν•­κ³Ό μ‹œν—˜μ§€μ˜ κ΄€κ³„λŠ” μ•„λž˜ 그림을 μ°Έκ³ ν•˜μ—¬ μ΄ν•΄ν•˜μ‹œλ©΄ λ©λ‹ˆλ‹€. 총 1,537개의 κ³ μœ ν•œ μ‹œν—˜μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€.

  • answerCode μ‚¬μš©μžκ°€ ν•΄λ‹Ή 문항을 λ§žμ·„λŠ”μ§€ 여뢀에 λŒ€ν•œ 이진 데이터이며 0은 μ‚¬μš©μžκ°€ ν•΄λ‹Ή 문항을 ν‹€λ¦° 것, 1은 μ‚¬μš©μžκ°€ ν•΄λ‹Ή 문항을 맞좘 κ²ƒμž…λ‹ˆλ‹€.
  • Timestamp μ‚¬μš©μžκ°€ 해당문항을 ν’€κΈ° μ‹œμž‘ν•œ μ‹œμ μ˜ λ°μ΄ν„°μž…λ‹ˆλ‹€.
  • KnowledgeTag λ¬Έν•­ λ‹Ή ν•˜λ‚˜μ”© λ°°μ •λ˜λŠ” νƒœκ·Έλ‘œ, μΌμ’…μ˜ 쀑뢄λ₯˜ 역할을 ν•©λ‹ˆλ‹€. νƒœκ·Έ 자체의 μ •λ³΄λŠ” 비식별화 λ˜μ–΄μžˆμ§€λ§Œ, 문항을 κ΅°μ§‘ν™”ν•˜λŠ”λ° μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 912개의 고유 νƒœκ·Έκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

[Feature]

elapsed: μœ μ €κ°€ 문제λ₯Ό ν‘ΈλŠ”λ°μ— μ†Œμš”ν•œ μ‹œκ°„

time_bin: 문제λ₯Ό ν‘Ό μ‹œκ°„λŒ€(μ•„μΉ¨, 점심, 저녁, μƒˆλ²½)

classification: λŒ€λΆ„λ₯˜(ν•™λ…„)

paperNum: μ‹œν—˜μ§€ 번호

problemNum: 문제 번호

user_total_acc: μœ μ €μ˜ 총 μ •λ‹΅λ₯ 

test_acc: 각 μ‹œν—˜μ§€μ˜ 평균 μ •λ‹΅λ₯ 

assessment_acc: 각 문제의 평균 μ •λ‹΅λ₯ 

tag_acc: 각 νƒœκ·Έμ˜ 평균 μ •λ‹΅λ₯ 

total_used_time: μœ μ €κ°€ ν•˜λ‚˜μ˜ μ‹œν—˜μ§€λ₯Ό λ‹€ ν‘ΈλŠ”λ°μ— μ†Œμš”ν•œ μ‹œκ°„

past_correct: μœ μ €λ³„ κ³Όκ±° 맞좘 문제의 수

past_content_count: μœ μ €-λ¬Έμ œλ³„ 과거에 동일 문제λ₯Ό λ§Œλ‚œ 횟수

correct_per_hour: μ‹œκ°„(hours)별 μ •λ‹΅λ₯ 

same_tag: 동일 νƒœκ·Έλ₯Ό μ—°μ†μœΌλ‘œ ν’€μ—ˆλŠ”μ§€ 유무(T/F)

cont_tag: μ—°μ†μœΌλ‘œ ν‘Ό 동일 νƒœκ·Έ 개수(0~)

etc...


[Contributors]



[Collaborative Works]

Gitflow 브랜치 μ „λž΅

β†’ 92개의 Commits, 26개의 Pull Requests



Github issues & projects 둜 일정 관리

β†’ 28개의 Issues



β†’ Modeling Project μ—μ„œ 관리



Notion μ‹€ν—˜λ…ΈνŠΈλ‘œ μ‹€ν—˜ 곡유

β†’ 39개의 μ‹€ν—˜λ…ΈνŠΈ



Notion 제좜기둝으둜 제좜 λ‚΄μ—­ 곡유

β†’ 155개의 제좜기둝



πŸ“ Notion

ν”Όμ–΄λ“€μ˜ Ground Rule, μ‹€ν—˜λ…ΈνŠΈ, ν”Όμ–΄μ„Έμ…˜ λ“± ν•œλ‹¬ κ°„μ˜ 행보λ₯Ό ν™•μΈν•˜μ‹œλ €λ©΄ λ‹€μŒ 링크λ₯Ό ν΄λ¦­ν•˜μ„Έμš”.



[Reference]

Papers

Dataset

  • i-Scream edu Dataset