Doby's Lab

2023 제1회 철도 인공지능 경진대회 후기 (28등/68명) 본문

AI Projects/Contest Description

2023 제1회 철도 인공지능 경진대회 후기 (28등/68명)

도비(Doby) 2023. 10. 27. 19:38

✅ Intro

 

2023 제1회 철도 인공지능 경진대회

열차 주행 안전성 진단을 위한 탈선계수 예측 모델 개발 경진대회를 개최합니다!

aifactory.space

본 포스팅은 23.08.01 ~ 23.08.28의 대회 기간에 관한 로그입니다.

 

전역을 하면서 복학하기 전 1달 남은 시간 동안 어떤 것들을 해보아야 할지 고민을 하다가 AI 프로젝트의 전반적인 프로세스를 다시 한번 느껴보기 위해서 대회에 참여해 보아야겠다고 생각했습니다.

그리고, 처음으로 AI 대회를 나가는 것이기 때문에 경험적인 부분에서 더 스펙트럼을 넓힐 수 있고, 성적을 기대하기보다는 나의 부족한 부분들을 알아가 보자는 마음으로 임했습니다.

 

대회에 대한 정보는 동아리 친구들로부터 알게 되었으며 이 글을 통해 감사한 마음을 전합니다.

 

또한, 대회의 규정에 따라 데이터셋에 대한 정보를 드러내는 것은 금지되어 있습니다. 이에 따라 문제가 생길 시에 수정이나 삭제 조치를 하도록 하겠습니다.

더보기

대회 개요 중 일부
저작권 및 지적 재산권 관련
데이터셋 파일 및 데이터에 대한 설명 등 제공된 일체의 정보는 주최사 및 주관사의 자산이며 해당 정보는 본 대회의 참가 목적으로만 사용해야 하고, 그 외 용도로 타인에게 양도 및 대여, 재배포, 2차적 저작 및 상업적 용도로 이용할 수 없습니다.


✅ Category

카테고리는 아래와 구성되어 있지만, 전반적인 흐름에 대한 것이고, 동시에 이루어진 부분들이 대다수였습니다.
(e.g. 모델링을 하다가 다시 데이터 전처리를 해서 모델에 넘기는 경우)

  1. Intro
  2. Category
  3. 준비 과정 (Gradient Boosting)
  4. Tabular Data: 데이터 분석, 전처리, 그리고 모델링(XGB)
  5. Tabular 관점에서의 한계
  6. TIme Series: 시계열 데이터 분석 및 전처리, 그리고 모델링 (LSTM)
  7. Outro

✅ 준비 과정 (Gradient Boosting)

대회를 시작하기 전에 어떠한 데이터인가에 따라 분석 방법, 모델링 방법이 너무 가변적으로 달라지기 때문에 스케일을 줄이고자 대회 시작 4일 전에 공개된 샘플 데이터셋을 통해 어떤 방법으로 문제를 풀어볼 것인가를 고민해 보는 시간을 가졌습니다.

 

주어진 샘플 데이터셋을 핸들링 및 시각화를 해본 결과 Tabular Data로 접근하면 좋은 결과를 내볼 수 있겠다는 생각을 했습니다. 이와 관련하여 XGB는 Tabular Data계에서 SOTA라 불리고 있으며, XGB의 기반이 되는 Gradient Boosting을 공부해 보았습니다.

 

Gradient Boosting 관련하여 포스팅을 작성하려 했지만, 준비 기간 중에는 무리가 있어서 작성하지는 못 하였으나 엄청 매력적인 알고리즘인 것은 충분히 알 수 있었습니다. '앙상블을 함에 있어서 왜 병렬적인 학습을 못 하는가'가 의문이었는데 다음 Tree에서 이전의 Error를 Target으로 삼고 학습을 진행하여 앙상블을 한다는 부분에 의문을 해결할 수 있었으며 지금 글과 이야기가 어긋날지는 모르겠습니다만 인문학적으로도 매력적인 알고리즘 같았습니다.

 

그리고, 회귀 문제였기 때문에 이론적인 부분은 분류로 이해를 하고, RSS를 통한 회귀 방식에 대해서 공부하여 공부를 끝냈습니다. XGB까지 공부하기에는 시간이 부족했으며, '병렬적인 학습이 가능하다', 'Regularization이 가능하다'라는 정도만 인지하고 대회를 시작했습니다.

 

[Gradient Boosting을 공부했던 자료]

1) Gradient Boosting 이론

https://www.geeksforgeeks.org/ml-gradient-boosting/

 

Gradient Boosting in ML - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

2) Gradient Boosting Regression에 대한 이해

https://towardsdatascience.com/all-you-need-to-know-about-gradient-boosting-algorithm-part-1-regression-2520a34a502?gi=45bf3e3c4a72

 

All You Need to Know about Gradient Boosting Algorithm − Part 1. Regression

Algorithm explained with an example, math, and code

towardsdatascience.com


✅ 데이터 분석, 전처리, 그리고 모델링(XGB)

(최대한 데이터셋에 대한 정보를 드러내지 않도록 작성하였습니다.)

📄 데이터셋 핸들링

우선 데이터셋은 주행에 대한 데이터셋, 선로에 대한 데이터셋 크게 2가지로 나뉘었습니다. 주행에 대한 데이터셋은 열차의 구성 요소 중 하나에 따른 데이터로 5개의 데이터셋이 존재했습니다. 그리고, 모든 데이터셋들은 거리에 따른 정보였습니다.

 

학습을 시킬 때 어떤 shape로 모델에 전달해 줄까, 열차 구성 요소에 따른 모델을 5개 따로 만들어서 마지막에 하나로 앙상블시켜야 하는가 등 여러 핸들링 방법을 고민하다가 조건에 따른 split을 하는 트리 기반 모델인 점에서 하나의 모델을 가지고 진행을 해도 되겠다는 생각이 들었습니다. (물론 직선, 곡선에 따른 모델은 제각각으로 최종적으로 사용한 모델은 2개였습니다.)

 

그림으로 데이터셋 핸들링을 표현했을 때는 아래와 같습니다.

📄 데이터 분석 및 전처리

✏️ 결측치 및 이상치 처리

데이터 분석 부분은 사실 분석이라 할 정도로 깊이 들어가지는 않았습니다.

우선 대회용 데이터셋이라 그런지 Missing Value는 아예 없었고, 4분위수에 따른 Outlier도 하나도 없었습니다.

✏️ 상관 계수 분석

seaborn에서 제공하는 heatmap을 통해 상관계수를 파악하여 시각화하였고, 이 중에서 상관계수가 낮은 값들을 보이는 feature들을 파악하였습니다. 파악한 결과 공통적인 특징이 있었으며, 이런 특징과 관련된 feature들은 모두 drop 해주었습니다.

✏️ 종속 변수에 대한 오류

(이 부분을 꼭 말하고 싶은데 최대한 데이터셋에 대한 정보를 담으면 안 되기 때문에 돌려 돌려 말해보겠습니다.)

Score가 잘 나오다가 진행되는 과정에서 큰 오류가 있었는데 대회에서 점수를 매길 때 사용되는 데이터들은 참가자들도 정보를 가지고 있습니다. 더 자세하게 말하자면 X = 독립 변수, Y = 종속 변수라고 할 때, 참가자에게는 X가 주어집니다. 하지만, Y의 값은 모두 0으로 주어집니다. 참가자는 Y에 대한 예측값을 제출하여 Y값 차이에 대한 Error를 최소화한 사람이 Score가 좋은 방식입니다.

 

어쨌든, 이러한 사실을 인지하지 못 한 채 Y가 0인 데이터들을 모두 포함하여 모델링을 하였으니 이 데이터들을 제외하고, 다시 모델링을 하여 제출하였을 때는 Score가 더욱 안 좋았습니다. 이러한 이유를 찾기 위해 종속변수들의 분포를 체크했습니다. (feature 이름은 가리겠습니다.)

여기서 파악할 수 있는 사실은 애초에 종속 변수들이 0에 근사한 값들이 많았기 때문에 오히려 Target이 0으로 잡혀있어도 좋은 Score를 냈었던 것입니다.

 

이러한 데이터(target이 0)를 전부 exculde를 할 것인가를 생각했을 때는 '그러면 안 된다'라고 생각했습니다. 결론적으로, 트리 모델에서 node가 split 되는 방식을 고려해 봤을 때, 우리가 맞추어야 할 데이터가 전혀 고려되지 않는다면 그게 결코 좋은 성능을 낼지언정 과연 범용적으로 사용될 수 있는 모델일까를 고민하게 되었습니다. (물론 성능이 좋진 않습니다.) 이 부분은 나중에 트리 모델의 한계에서도 다시 언급을 하겠습니다만 다시 말해 해당 데이터를 버리지는 못 한다는 결론이 내려졌습니다.

 

✏️ Data Imputation

그래서 0인 데이터에 대해 Imputation을 하는 방법을 고민했습니다.

 

1. Linear Regression을 사용한 Imputation

 

0이 아닌 데이터를 통해 Linear Regression 모델을 학습시켜서 학습시키고자 하는 데이터에 대한 종속변수를 predict 한 값을 훈련 데이터로 사용해 보았으나 Score가 많이 낮아서 실패했습니다.

 

2. SVD를 사용한 Imputation

 

선형대수학 개념 중 하나(특이값 분해)로 대회가 진행되던 당시에 같이 하고 있던 스터디에서 발견한 Data Imputation 기법이었는데 이 기법을 적용시킨 결과 Score가 좋아지진 않았지만 드라마틱한 효과는 없었습니다.

📄 모델링

모델링과 관련해서는 앞서 말한 대로 XGB를 사용하였으며 하이퍼파라미터 튜닝을 중심으로 계속 핸들링했기 때문에 크게 다룰 내용은 없으나 깨달은 사실이 하나 있었습니다. 이 부분은 Outro에서 마무리 지을 때 이야기 하도록 하겠습니다.

 

✏️ Final Modeling in Tabular Data

xgb_model = XGBRegressor(n_estimators=500,
                        learning_rate=0.05,
                        max_depth=30,
                        min_child_weight=5
                        )

multioutput_model = MultiOutputRegressor(xgb_model, n_jobs=mp.cpu_count()).fit(train_X.values, train_Y.values)

 

결론적으로 XGB를 사용한 Score(Error Metric)은 113.630375점으로 최종 Score이기도 합니다.


✅ Tabular 관점에서의 한계

XGB로 성능을 끌어올리려고 하면서 한계점을 느끼게 되었고, 시계열 데이터가 아닌가라는 관점에 있어서 한계점을 정리하고자 합니다.

📄 지속된 하이퍼 파라미터 튜닝

우선 지속적으로 하이퍼 파라미터 튜닝을 하였을 때, 성능이 계속 개선되었으나 특정 값이 여러 번의 Training으로 픽스되고, 나머지 변수들을 계속 바꿔주어도 더 이상은 XGB에서의 한계라고 생각이 들었습니다.

 

물론, 모델뿐만이 아닌 데이터 분석 혹은 전처리 측면에서도 '아직 부족한 것이 많기 때문에 조금 더 많은 인사이트가 있었다면 더 좋은 Score를 끌어내지 않았었을까'라는 생각이 있기도 합니다.

📄 트리 기반 모델의 한계

앞서 말한 트리 모델은 스플릿을 할 때 결국엔 Scale에 대해서 특정 기준을 잡아서 Split 됩니다. 대회에서도 마찬가지지만 만약에 문제해결을 위한 모델이라면 보다 넓은 범위에서 좋은 예측이 가능해야 하기 때문에 애초에 트리 기반 모델을 사용하는 것이 맞을까라는 의문을 가지게 되었습니다.

📄 시계열 데이터에서의 관점

해당 데이터셋은 거리에 따른 데이터들이 정리가 되어있습니다. 어느 순간부터 거리를 시간으로 본다면 이건 시계열 기반 모델이 될 수 있지 않을까라는 생각을 했고, 트리 기반 모델의 한계를 넘어설 수 있을 거라 생각했습니다. 하지만, 이때 당시 저는 XGB를 사용해 본 것도 처음이었고, RNN 쪽은 건드려 보지도 않았었습니다.


✅ Time Series: 시계열 데이터 분석 및 전처리, 그리고 모델링 (LSTM)

'시계열 데이터가 아닌가?'라는 새로운 관점이 생기긴 했어도 이 쪽 부분을 다루어 본 적도 없고, 이미 대회 데드라인은 1주 반을 남긴 상태였습니다. 사실 이 시점에서 에너지를 다 쏟아 많이 지치기도 했었습니다만 최선을 다 해보고 싶었습니다.

📄 개념 정리

RNN과 LSTM, GRU에 관해 빠른 공부가 필요했기에 잘 정리된 강의 자료를 유튜브에서 찾을 수 있었습니다.

 

[딥러닝 자연어처리 RNN 개념을 30분 안에 정리해 드립니다ㅣ서울대 AI 박사과정]

https://www.youtube.com/watch?v=Hn3GHHOXKCE

[ 딥러닝 자연어처리 LSTM , GRU 개념을 13분 안에 정리해 드립니다ㅣ서울대 AI 박사과정 ]

https://www.youtube.com/watch?v=rbk9XFaoCEE

📄 데이터 분석 및 전처리

당연히 시계열 데이터 분석 쪽도 처음이었기 때문에 급하게 Decomposition을 공부하여 Trend, Seasonal, Cycle, Residual 4가지로 분해하여 시각적으로 판단하기에 영향을 끼칠 거 같은 요소들과 원본 데이터들을 모두 학습시킬 수 있게 하였습니다.

또한, 기존의 데이터셋은 Time이 기준이 아니었기 때문에 Time step의 간격과 길이를 어느 정도로 잡아야 할 지도 큰 관건이었습니다.

📄 모델링 (LSTM)

앞서 빠르게 개념 공부를 한 결과 LSTM이 가장 좋을 거라 판단하여 LSTM으로 모델링을 했습니다. 이 과정에서 예전에 공부한 Batch Normalization까지 적용을 시키고, 더 성능을 좋게 하고 싶었기에 Hierarchical 한 구조로 LSTM을 2-Layer로 쌓았습니다.

 

✏️ Final Modeling in Time Series Data

model = tf.keras.models.Sequential()

model.add(tf.keras.layers.LSTM(units=64, 
                               input_shape=train_x.shape[-2:], 
                               dropout=0.1, 
                               recurrent_dropout=0.1,
                               activation='tanh',
                               return_sequences=True))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.LSTM(units=32, 
                               dropout=0.1, 
                               recurrent_dropout=0.1,
                               activation='tanh',
                               return_sequences=True))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Dense(10))
model.add(tf.keras.layers.Dense(4))

model.compile(optimizer=tf.keras.optimizers.RMSprop(learning_rate=0.001),
              loss='mse')

early_stopping_cb = tf.keras.callbacks.EarlyStopping(patience=10, verbose=1,
                                                  restore_best_weights=True)

learning_rate_reduction_cb = tf.keras.callbacks.ReduceLROnPlateau(
    monitor='val_loss', patience = 7, verbose=1, factor=0.5, min_lr=0.00001,
    cooldown=5
)

 

✏️ 치명적인 논리적 오류 (?)

하지만 이와 관련해서도 치명적인 오류가 있었으며 Target에 대한 값들에 대한 것이었습니다.

아직 자세하게 공부를 하지 않아서 이게 오류인지도 정확히는 잘 모르겠습니다만 시계열에 대한 Target은 현재에 대응하는 종속 변수 값이 아닌 일정 시간이 지난 후의 종속 변수 값을 Target으로 삼는 부분을 보게 되었을 때, '아 잘못했었구나'라는 것을 알게 되었습니다. 물론 아직 정확하지는 않습니다.

 

결과적으로, LSTM을 통한 접근 방식은 XGB보다 더욱 안 좋은 Score를 받았었습니다.

 

이때쯤엔 대회가 거의 마무리되었었고, 저도 복학을 하여 딜레이 시켜둔 일정이 많았기에 Exit을 했습니다.


✅ Outro

📄 끈기(?)

대회에 대해서 전반적인 이벤트들을 작성하면서 첫 대회에 대한 회고를 해보았습니다.

대회 규정과 관련해서 모든 내용을 작성하지는 못 하는 점과 핵심적인 것만 다루어도 많다는 생각에 전부 다 다루지는 않았습니다. (깃허브에라도 코드를 올리고 싶지만 걸리는 부분이 많아서 모델 부분만 코드를 여기에라도 올려봅니다.)

 

첫 대회다 보니 경험을 바라고 나간 대회였지만, 시간이 가면 갈수록 더 불타오르고, 밤새 고민하고 있는 스스로를 봤습니다. 어쩌면 정말 오랜만에 저의 끈기를 확인한 순간이었지 않았나 싶습니다.

 

하지만, 반대로 그만 둘 때는 그만 둘 줄도 알아야 한다는 교훈도 있었습니다. 모든 것을 잘할 수는 없으며 그에 대해서 항상 스트레스를 받으면 안 되겠다는 생각을 했습니다. (왜냐하면, 대회 때문에 밀린 일들이 많았었거든요..)

📄 팀의 필요성

모든 것을 혼자 하다 보니 프로젝트를 해나감에 있어서도 한계가 분명히 있음을 느꼈습니다. 그리고, 대회 리더보드에서도 대부분은 팀으로의 플레이가 좋은 Score를 가져가는 것을 보았기 때문에 나중에는 분업이 된 상태로 멋진 팀과 대회에 나가보고 싶습니다.

📄 코드 핸들링 능력 향상 필요

이번에 대회 중간에 환기 목적을 오펜하이머를 보고 와서 그런지 그런 생각이 많이 들었습니다. 오펜하이머의 시대에는 이론 물리학과 실험 물리학이 있었다고 합니다. 오펜하이머는 이론 쪽은 빠삭하지만, 실험 쪽은 많이 부족했다고 합니다. 영화가 끝나고 오펜하이머에 대해 궁금하며 알아보다가 본 내용이었습니다.

 

이러한 부분이 저도 어느 정도 공감(?)이 되었습니다. AI의 이론 쪽은 재밌다 보니 더 알아보고, 정리하고, 상상하고 이런 공부를 많이 했었지만 막상 코드로 해당 모델을 핸들링을 한 경험이 많이 없었구나라는 것을 알게 되었고, 대회를 통해 앞으로는 공부를 할 때 코드 부분도 고려를 많이 해야겠다는 생각을 많이 하게 되었습니다.

 

+ 그래서 방학 중에 Pytorch를 다루어볼까라는 계획을 어느 정도 잡고 있습니다.

📄 첫 대회 68명 중 28등! 끝!

어쨌든 저의 첫 대회가 잘 끝났습니다. 2달이나 지나서 쓰는데 이제 와서 보니 정말 최선을 다 했었구나 라는 생각이 듭니다. 68명 중에 28등이라는 것도 그때 당시엔 부족하다고 느꼈으나 최선의 결과라고 받아들여집니다.

 

대회 끝!

 

P.S. 정말 오랜만에 길게 쓰는 블로그 글이네요! 다음 프로젝트도 이미 해둔 게 있으니 빠른 시간 내에 작성하겠습니다.

728x90