Aivle Til 230414 5차 미니프로젝트 정리
Aivle Til 230414 5차 미니프로젝트 정리
title: AIVLE TIL (‘23.04.14) 5차 미니프로젝트 정리 date: 2023-04-14 12:42:39.192 +0000 categories: [AIVLE] tags: [‘aivle’] description: 첫 개인 별 캐글 경진대회 image: /assets/posts/2023-04-14-aivle-til-230414-5차-미니프로젝트-정리/thumbnail.png
Kaggle 전략
- 지난 2일간 배웠던 것은 크게 2개로 정리할 수 있다.
- Feature Importance를 이용한 다양한 데이터 탐색 방법
- 문제 하나를 여러 단계의 문제로 쪼개 서로 다른 모델을 학습하는 방법
- 이번 Kaggle 경진대회에서는 이 두 가지 전략을 집중 사용해보고자 하였다.
- 하지만 데이터셋에서 주어진 컬럼이 단 50여개로, Feature Extraction을 하기엔 턱없이 부족한 수였다. (이전에 500여개로 이루어진 칼럼을 받았을 때, 컬럼 개수가 대체로 70개쯤 미만이 되면 성능이 감소하는 현상이 있었다)
- 때문에 FI를 살피고, 중요한 특징만을 선택하는 전략 대신, 딥러닝을 통해 기존의 Feature로 부터 새로운 특징을 만들어내는 Feature Representation을 이용하기로 하였다.
문제를 여러개로 쪼개기
- 주어진 문제의 클래스는 인간의 행동을 나타내는데, ‘걷기’, ‘계단 오르기’, ‘계단 내려가기’, ‘서있기’, ‘앉아있기’, ‘누워있기’의 6가지가 있다.
AutoGluon
AutoGluon은 아마존에서 공개한 오픈소스 머신러닝 자동화 툴 킷으로, 기본적인 모델부터 LightGBM, CatBoost와 같은 SOTA 모델까지 탐색하여 최적의 모델 및 파라미터를 찾아준다.
지난 Dacon 경진대회 때 1위를 기록한 참가자가 별 다른 전처리 없이 AutoGluon을 사용했다는 것이 인상적이었기 때문에 이를 사용하기로 하였다.
동적 동작 vs 정적 동작
'걷기', '계단 오르기', '계단 내려가기'
를 한데 묶어 동적 동작,'서있기', '앉아있기', '누워있기'
를 한데 묶어 정적 동작으로 구분할 수 있다.
- 데이터를 확인해보면 명확히 알 수 있는데, 0~2(동적), 3~5(정적)끼리의 데이터 분포가 확연히 다른 특징들이 많이 존재한다.
- 즉 먼저 동적, 정적 동작을 구분하는 이진 분류문제를 풀고, 나뉜 데이터에 대해 각각 클래스 3개의 다중 분류 문제를 풀어보는 전략을 취할 수 있다.
- 그림을 그려보면 이와 같다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def get_answer(df_train, df_test):
## AutoGluon에 넣기 위해 데이터프레임을 쪼갬
# is_dynamic 이진분류
df_train_bi = df_train.drop(tgt, axis=1)
# 동적, 정적별 다중 클래스 분류
df_train_st = df_train.loc[df_train[tgt2]==0].drop(tgt2, axis=1)
df_train_dy = df_train.loc[df_train[tgt2]==1].drop(tgt2, axis=1)
## 이진분류 모델 생성
# 모델 설정
predictor = TabularPredictor(label=tgt2, problem_type='binary', eval_metric='f1_macro')
# 학습
predictor.fit(df_train_bi)
# 예측하기
y_pred_bi = predictor.predict(df_test)
# 예측값을 원래 데이터에 합병
temp = pd.concat([df_test, y_pred_bi], axis=1)
# 합병된 데이터에서 예측값을 바탕으로 데이터 분리
df_test_st = temp.loc[temp[tgt2]==0].drop(tgt2, axis=1)
df_test_dy = temp.loc[temp[tgt2]==1].drop(tgt2, axis=1)
del temp
## 다중 분류
# 다중분류(정적) 모델 설정
predictor_st = TabularPredictor(label=tgt, problem_type='multiclass', eval_metric='f1_macro')
# 학습
predictor_st.fit(df_train_st, num_gpus=1)
# 예측하기 (수동 평가)
y_pred_st = predictor_st.predict(df_test_st.drop('ID', axis=1))
# 예측값을 테스트 데이터에 추가
df_test_st['Activity'] = y_pred_st
# 다중분류(동적) 모델 설정
predictor_dy = TabularPredictor(label=tgt, problem_type='multiclass', eval_metric='f1_macro')
# 학습
predictor_dy.fit(df_train_dy, num_gpus=1)
# 예측하기 (수동 평가)
y_pred_dy = predictor_dy.predict(df_test_dy.drop('ID', axis=1))
# 예측값을 테스트 데이터에 추가
df_test_dy['Activity'] = y_pred_dy
## 정답추출
# 테스트 데이터에 ID열을 기준으로 병합(merge)
return pd.concat([df_test_st, df_test_dy])[['ID', 'Activity']]
# 병합된 칼럼에서 정답 및 ID가 포함된 정답칼럼 추출
df_answer = pd.merge(df_test, temp, on='ID')[['ID', 'Activity']]
del temp
return df_answer
- AutoGluon을 수행한 과정이다. 제출 양식에 맞추기 위해 ID를 기준으로 병합하는 과정을 추가하였다.
결과
- 4, 5가 바로 앉아있는 상태와 서있는 상태인데, 이 두 클래스를 굉장히 맞추기 어려워하는 경향이 있었다.
One & Rest
- 위 결과를 바탕으로 ‘STANDING’ 클래스인지 아닌지를 먼저 구분하고, 남은 5개의 클래스를 다중분류 해보는 것이 어떨까라는 생각을 하였다.
- 코드는 위 코드의 변형과정이므로 생략하고 결과만 보면 다음과 같다.
- 4번 클래스가 바로 ‘STANDING’ 클래스인데, recall이 꽤 감소한 것을 확인할 수 있었다. 대신 다른 클래스의 분류 정확도가 상승하여 결과적으로 비슷한 성능을 보였다.
Two & Rest
- 4, 5번 클래스를 모델이 특히 헷갈려하는 것 같아, 이 둘을 묶은 클래스에 속하는지 아닌지에 대한 이진분류 문제를 풀고, 다시 4, 5를 나누는 이진분류 문제와, 0~3을 구분하는 다중분류 문제를 풀도록 하였다.
- 결과적으로 가장 우수한 성능을 낸 전략이었다.
딥러닝
사용 레이어
- 기본적인 Dense Layer, Dropout Layer를 사용하여 딥러닝 모델링을 진행했다.
- 대신 에이블 강의시간에 모델의 학습률에 주기성을 부여하면 더 좋은 성능을 얻을 수 있다는 것을 배워 직접 시도해보는 것을 추가하였다.
스케줄러 - CosineDecayRestarts
1
2
3
4
5
6
7
8
tf.keras.optimizers.schedules.CosineDecayRestarts(
initial_learning_rate,
first_decay_steps,
t_mul=2.0,
m_mul=1.0,
alpha=0.0,
name=None
)
- 텐서플로우에서 제공하는 학습률 스케줄러이다.
- 이와 같이 learning rate를 코사인 곡선을 따라 감소시키다가
alpha
에 도달하면 다시 처음 learning rate로 hard restart하는 스케줄러이다. initial_learning_rate
: 학습률의 시작점first_decay_steps
:alpha
까지 몇 step(epoch)에 걸쳐 도달할지t_mul
: restart가 이루어 질 때마다first_decay_steps
에t_mul
만큼을 곱한다. t_mul이 2.0일 경우, 50 -> 100 -> 200 순으로 decay_step이 상승한다.m_mul
: restart가 이루어 질 때initial_learning_rate
에m_mul
만큼을 곱한다. m_mul이 0.5일 경우 1e-3 -> 5e-4 -> 2.5e-4 순으로 재시작 시 학습률이 변한다.alpha
: 학습률의 최저점
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from tensorflow.keras.backend import clear_session
from tensorflow.keras.layers import Input, Dense, Dropout
from tensorflow.keras.models import Model
from tensorflow.keras.callbacks import EarlyStopping, LearningRateScheduler
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.optimizers.schedules import CosineDecayRestarts
# Define the CosineAnnealingWarmRestarts schedule
schedule = CosineDecayRestarts(initial_learning_rate=1e-3,
first_decay_steps=50,
t_mul=2.0,
m_mul=0.6,
alpha=1e-6
)
# Define the optimizer with the initial learning rate
optimizer = Adam(learning_rate=schedule)
es = EarlyStopping(monitor='val_loss',
min_delta=0,
patience=100,
verbose=1,
restore_best_weights=True)
# 세션 클리어
clear_session()
# 레이어 연결
il = Input(shape=(len(x_train.columns),))
hl = Dense(256, activation='swish')(il)
hl = Dense(128, activation='swish')(hl)
hl = Dense(256, activation='swish')(hl)
hl = Dropout(0.2)(hl)
hl = Dense(512, activation='swish')(hl)
hl = Dropout(0.2)(hl)
hl = Dense(1024, activation='swish')(hl)
hl = Dropout(0.2)(hl)
hl = Dense(512, activation='swish')(hl)
hl = Dropout(0.2)(hl)
hl = Dense(256, activation='swish')(hl)
hl = Dropout(0.2)(hl)
ol = Dense(6, activation='softmax')(hl)
# 모델 선언
model = Model(il, ol)
# 컴파일
model.compile(loss=keras.losses.sparse_categorical_crossentropy,
metrics=['accuracy'],
optimizer=optimizer)
# 요약
model.summary()
model.fit(x_train, y_train, epochs=1000, verbose=1, validation_split=0.2, callbacks=[es])
결과
- 모델을 깊게도 쌓아보고, 얕게도 쌓아봤으나 4, 5를 여전히 구분하지 못하는 성능을 내었다.
- 남은 시간이 얼마 없었기에 이 이상 딥러닝에 많은 시간을 투자하지 못하였다.
후기
최종 결과
- 285명 중 99등을 기록하여 이번에도 상위 30% 이내에 드는 것은 실패하였다.
- 지난번 팀 프로젝트 때와 같이 다소 아쉽게 순위권을 놓쳤는데, 다음 미니 프로젝트때는 꼭 30% 이내에 들어보고 싶다.
아쉬웠던 점
- 컬럼이 생각보다 적게 주어져 FI를 이용해볼 수 없었던 점이 아쉬웠다.
- 또한 AutoGluon을 매우 기본적인 단계로 사용해서 충분한 성능을 뽑아보지 못한 것이 아쉬웠다. 경진대회가 끝날 때즘 fit에 여러가지 인자를 주어 튜닝할 수 있다는 것을 알았으나, 이미 시도하기 늦은 상황이었다.
새롭게 알게 된 점 (앞으로 배워야 할 것)
wandb
- 매번 모델을 돌릴 때마다 결과를 정리하고, 기록하는 것이 어려웠는데 이번에 다른 에이블러님의 발표에서
wandb
라는 것을 알게되었다. - 이번 미니 프로젝트를 통해 결과를 기록 및 분석하는 것이 정말 중요하다는 것을 깨달았는데, 이참에 wandb를 배워서 다음 미니 프로젝트 때 써먹어봐야겠다.
autogluon 튜닝
- 학습(fit)을 할 때 몇가지 인자를 주는 것을 통해 모델을 손쉽게 튜닝할 수 있다는 것을 알게 되었다.
- 추후 공식문서를 읽고 AutoGluon을 사용할 때 다양한 튜닝 옵션을 적용해봐야겠다. (개인 캐글 경진대회 등을 참여하는 것도 좋을 것 같다)
This post is licensed under CC BY 4.0 by the author.