[2023 스마트농업 AI 경진대회 #4] AI 해커톤 진행 과정

윤하은·2023년 10월 3일
0

AI Hackathon

목록 보기
4/5
post-thumbnail

모델 선정


3. AutoGluon

AutoML for Image, Text, Time Series, and Tabular Data

이미지, 텍스트 및 테이블 데이터셋을 사용하는 실제 응용 프로그램을 위해 딥 러닝 및 머신 러닝을 자동화하는 새로운 오픈 소스 AutoML 라이브러리다.

출처 : https://towardsdatascience.com/autogluon-deep-learning-automl-5cdb4e2388ec


AutoGluon은 팀원의 소개로 알게되었다. 머신 러닝 작업을 자동화하여 다양한 모델을 내부적으로 조합하고, 최적의 알고리즘과 하이퍼파라미터를 선택함으로써 최고의 예측 성능을 달성할 수 있다.

import numpy as np
import pandas as pd
from autogluon.tabular import TabularPredictor, TabularDataset
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score

train_df = pd.read_csv('2023_smartFarm_AI_hackathon_dataset.csv') 
train_data = TabularDataset(train_df)

eval_metric = 'accuracy' 
r2_metric = 'r2'
rmse_metric = 'root_mean_squared_error'


# autogluon train
predictor = TabularPredictor(
    label=label, 
    eval_metric=rmse_metric, 
    path=output_directory
).fit(
    train_data,
    presets='best_quality', 
    time_limit=time_limit, 
    ag_args_fit={'num_gpus': 0, 'num_cpus': 8}
    )
    

predictor.save(predictor_directory)

AutoGluon을 사용하면 위와 같이 쉽게 모델을 훈련시킨 후 저장할 수 있다. 아래는 저장한 모델을 불러와서 사용한 코드다.

loaded_predictor = TabularPredictor.load(output_directory)  

test_df = TabularDataset(X_test) 
prediction = loaded_predictor.predict(test_df)

rmse = np.sqrt(mean_squared_error(y_test, prediction))
r2score = r2_score(y_test, prediction)

해커톤 시작 6시간 후였던 첫번째 제출에서 AutoGluon을 이용한 코드를 제출했는데, 주최측에서 AutoML 라이브러리는 사용이 불가능하다는 연락을 받았다.




4. 앙상블 알고리즘

Bagging을 사용한 대표적인 결정 트리 앙상블 모델인 Random Forest가 좋은 성능을 보이는것을 확인하고, 여러 앙상블 기법을 시도해보는 것으로 방향을 틀었다.

아래는 그 중 Stacking을 시도했던 코드다. 스태킹의 기본 모델로 사용할 여러 회귀 모델을 초기화 하고, 기본 모델들과 메타 모델을 활용하여 스태킹을 수행한다.

import numpy as np
import lightgbm as lgb

from sklearn.ensemble import (
    RandomForestRegressor, ExtraTreesRegressor,
    GradientBoostingRegressor, HistGradientBoostingRegressor,
)
from xgboost import XGBRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.multioutput import MultiOutputRegressor
from sklearn.metrics import mean_squared_error
from sklearn.base import BaseEstimator, RegressorMixin

from sklearn.model_selection import KFold
from sklearn.base import clone


model_xgb = XGBRegressor()
GBoost = GradientBoostingRegressor()
LightGB = lgb.LGBMRegressor()
RF = RandomForestRegressor()
ETR = ExtraTreesRegressor()
DT = DecisionTreeRegressor()
HGBR = HistGradientBoostingRegressor()

models = [model_xgb, GBoost, LightGB, ETR, DT, HGBR]

class StackingModel(BaseEstimator, RegressorMixin):
    def __init__(self, base_models, meta_model, n_folds=5):
        self.base_models = base_models
        self.meta_model = meta_model
        self.n_folds = n_folds

    def fit(self, X, y):
        self.base_models_ = [list() for model in self.base_models]
        self.meta_model_ = clone(self.meta_model)
        kfold = KFold(n_splits=self.n_folds, shuffle=True)

        # 메타 모델의 훈련 데이터를 저장하기 위한 빈 배열
        meta_train_data = np.zeros((X.shape[0], len(self.base_models) * y.shape[1]))

        for i, model in enumerate(self.base_models):
            for train_index, holdout_index in kfold.split(X, y):
                instance = clone(model)
                multi_target_instance = MultiOutputRegressor(instance)
                self.base_models_[i].append(multi_target_instance)
                multi_target_instance.fit(X[train_index], y[train_index])
                y_pred = multi_target_instance.predict(X[holdout_index])
                meta_train_data[holdout_index, i*y.shape[1]:(i+1)*y.shape[1]] = y_pred

        self.meta_model_ = MultiOutputRegressor(self.meta_model_)
        self.meta_model_.fit(meta_train_data, y)
        return self

    def predict(self, X):
        meta_features = np.zeros((X.shape[0], len(self.base_models) * y_train.shape[1]))

        for i, base_models in enumerate(self.base_models_):
            for model in base_models:
                y_pred = model.predict(X)
                meta_features[:, i*y_train.shape[1]:(i+1)*y_train.shape[1]] += y_pred
        meta_features /= self.n_folds

        return self.meta_model_.predict(meta_features)


# 스태킹 모델 초기화
stacked_model = StackingModel(base_models=models, meta_model=RandomForestRegressor())

# 모델 훈련 및 예측
stacked_model.fit(X_train.values, y_train.values)
y_pred = stacked_model.predict(X_test.values)

rmse = np.sqrt(mean_squared_error(y_test, y_pred))
r2score = r2_score(y_test, y_pred)

여러 모델과 Bagging, Stacking 등 다양한 앙상블 기법의 조합을 시도해 봤지만 RMSE가 2만 이하로 줄어들지 않았다.

여기서도 결측치 처리, 특성 엔지니어링, 스케일링 및 정규화 등의 데이터 전처리를 시도하였으나, 오히려 모델의 성능이 저하되어 결국 데이터 전처리를 수행하지 않은 데이터셋을 사용했다.

데이터 스케일링이 모델 학습에 중요한 요소라고 생각하고 있었는데, 트리 기반의 앙상블 모델은 데이터의 스케일에 크게 영향을 받지 않는다는 사실을 알게 되었다. 평소에 딥러닝쪽으로만 공부 했던탓에 틀에 갇힌 생각에서 벗어나지 못하고 데이터 전처리를 시도했던것 같다. 이런 경우에는 어떤 방식으로 데이터 전처리를 수행해야 하는지 알아봐야겠다.



0개의 댓글