728x90

요약

  • 트리계열 모델의 Ensemble 

 

여러 모델을 실험한 결과 트레 계열 모델이 그나마 좋은 성능을 보입니다. 그래서 오늘은 이러한 모델을 가지고 ensemble을 해봤습니다.

models = [
    ('xgboost', XGBRegressor(random_state=2021)),
    ('lgb', lgb.LGBMRegressor(random_state=2021)),
    # ('rf', RandomForestRegressor(n_jobs = -1,random_state=2021))
]
params = {
    'xgboost': {
        "gamma": np.linspace(0,0.5,20),
        "max_depth": range(2, 6), 
        "learning_rate" : [0.001,0.01,0.1],
        "n_estimators": [80,100,150,170]
    },
    'lgb': {
        "gamma": [0.0],
        "max_depth": range(2, 6), 
        "learning_rate" : [0.001,0.01,0.1],
        "n_estimators": [80,100]
    },
    'rf': {
        "max_depth": range(2, 6),
        "min_samples_split": range(2, 6),
        "min_samples_leaf": range(2, 6), 
        "n_estimators": [80,100,120],
        }
}

kfold = KFold(n_splits=10, shuffle=True, random_state=2021)
Ensamble_predictions = np.zeros(test.shape[0])
for model_name, model in models:
    param_grid = params[model_name]
    grid = GridSearchCV(model, cv=kfold, n_jobs=-1, param_grid=param_grid, scoring = 'neg_mean_squared_error')
    grid = grid.fit(X_train[x_columns], Y_train)

    model = grid.best_estimator_
    valid_predictions = model.predict(X_test[x_columns])
    score = evaluate(Y_test, valid_predictions)['mse'][0]
    print("{0},score:{1},best_params_:{2} ".format(model_name, score, grid.best_params_))
    
    if model_name =='lgb':
      Ensamble_predictions += model.predict(test[x_columns])*0.5
    else:
      Ensamble_predictions += model.predict(test[x_columns])*0.5

 

xgboost,score:1307.199983522324,best_params_:{'gamma': 0.0, 'learning_rate': 0.1, 'max_depth': 3, 'n_estimators': 80} 
lgb,score:1160.1852960080262,best_params_:{'gamma': 0.0, 'learning_rate': 0.1, 'max_depth': 5, 'n_estimators': 80}

데이콘에 제출했던 앙상블은 randomforest까지 포함하여 lgb는 0.5, xgb,rf는 각각 0.25씩 분배한 것입니다. 제출한 결과 2정도 성능이 나빠졌습니다. lgb 단일 모델로 한 것보다 성능이 더 안좋아져서 셋중에 가장 성능이 떨어진 rf를 제외하여 위 코드처럼 진행했습니다. 제출은 내일이나 가능할 것같습니다. 

 

아직은 결론은 짓지 않았지만 현재까지는 staking,, ensemble 와 같이 다른 모델과 혼합한 결과물은 대체로 괄목할만한 결과를 보진 못했습니다. 단일 모델로 사용하는게 현재까지는 유리 해 보입니다

728x90
728x90

요약

  • rush_hour 파생변수 추가
  • Dense Layer 추가

1. Rush_hour 파생변수 추가

#잔차분포 확인
Xtrain_predictions = best_model.predict(X_train[x_columns])
sns.displot(x=Xtrain_predictions-Y_train)
plt.show()

grid의 best model로 잔차 분포를 확인해 봤습니다. 제 생각에는 성능을 저하시키는 요인이 양 끝 부분에 차지한 loss들 때문이라고 생각했습니다. max, min 값의 인덱스를 가지고 데이터를 살펴보았습니다.

 

min(Xtrain_predictions-Y_train),max(Xtrain_predictions-Y_train)
(-162.76608924934504, 118.88818750028724) #245, 1387

 

df.loc[[245,1387]]

위 결과는 rush_hour를 미리 적용한 결과물입니다. 처음에는 출퇴근 시간인 18시 ,8시에 가장 많은 Loss가 있었습니다. 그래서 rush hour시간에 급증하는 포인트를 주기 위해서 아래와 같은 코드로 변수를 추가했습니다.

 

# 출근 시간: 7,8,9  퇴근시간:17,18,19시 기준
df['rush_hour'] = df['hour'].apply(lambda x: 1 if x== 7 or x==8 or x==9 
                                   or x==17 or x==18 or x==19 else 0 )

해당 변수를 넣은 후 돌린 결과 리더보드에서 상위 10% 안에 들수 있었습니다. 해당 변수의 lgb 피처 중요도를 보면 낮은 수치를 기록했습니다.

이는 아마 출퇴근 시간의 데이터가 적어서 그런게 아닐까 생각합니다. 하지만 미처 해결하지 못한 문제점이 있습니다.   

해당 이미지의 결과를 보면, 16시에 예측값이 target 보다 아주 적게 예측을 했고, 8시에는 37보다 크게 예측을 했습니다. 변수를 보면 이둘의 차이를 설명해줄만한 것이 없습니다. 제 생각엔 8시인 출근 피크 시간에 수요가 적다는 것은 아침 유동인구가 비교적은 주말이나 공유일일 확률이 크다고 봅니다. 줄곧 고민을 해보았지만 아직까지는 실마리를 찾지 못했습니다. Feature들을 가지고 군집화를 통해 내가 모르고 있던 구분을 해주지 않을까 시도 해봤지만 이 역시 잘 되지 않았습니다. 새로운 변수를 찾기 위해서 Dense층의 비선형을 이용하면 어떨가 싶어서 Dense를 추가했습니다.

 

 

2. Dense Layer 추가

import os 
from tensorflow.keras.layers import Dense, Flatten, Input,Dropout , BatchNormalization
from tensorflow.keras import regularizers
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import ModelCheckpoint,ReduceLROnPlateau,EarlyStopping

MODEL_SAVE_FOLDER_PATH = '/content/weights/' 
if not os.path.exists(MODEL_SAVE_FOLDER_PATH): 
  os.mkdir(MODEL_SAVE_FOLDER_PATH)

model_path = MODEL_SAVE_FOLDER_PATH + 'weights.{epoch:02d}-{val_loss:.2f}.hdf5'

#ModelCheckpoint
mcp_cb = ModelCheckpoint(filepath=model_path, monitor='val_loss', 
                         save_best_only=True, save_weights_only=False, mode='min', verbose=1)

#ReduceLROnPlateau
rlr_cb = ReduceLROnPlateau(monitor='val_loss', factor=0.3, patience=15, mode='min', verbose=1)

#EarlyStopping
ely_cb = EarlyStopping(monitor='val_loss', patience=20, mode='min', verbose=1)


def create_model():
  input_tensor = Input(shape=(X_train[x_columns].shape[1],))
  x = Flatten()(input_tensor)
  x = Dense(12, activation='relu',kernel_regularizer=regularizers.l2(0.001))(x)
  # x= BatchNormalization()(x)
  x = Dense(10, activation='relu',kernel_regularizer=regularizers.l2(0.001))(x)
  # x= BatchNormalization()(x)
  output = Dense(1, activation='relu')(x)
  model = Model(inputs=input_tensor, outputs=output)
  return model

def train():
  model = create_model()
  model.compile(optimizer=Adam(0.001), loss = 'mse', metrics=['mse'])
  history= model.fit(X_train[x_columns],Y_train,
                      epochs=200,
                      batch_size=4,
                      validation_data=(X_test[x_columns], Y_test),
                    callbacks=[mcp_cb,ely_cb])
  return history
history = train()

 

#그래프 시각화
plt.figure(figsize=(10,10))
plt.plot(history.history['mse'], label='train_mse')
plt.plot(history.history['val_mse'],label='val_mse')
plt.legend()
plt.show()

 

from tensorflow.keras.models import load_model

#학습된 가중치 불러오기
weights_path = '/content/weights/weights.35-2130.14.hdf5'
def load_trained_model(weights_path):
   model = create_model()
   model.load_weights(weights_path)
   return model
model = load_trained_model(weights_path)

#Test Predict
dense_model=model.predict(test[x_columns])
submission.iloc[:,1] = dense_model
submission.set_index("id")
submission.to_csv('dense_2130.csv', index=False)

Dense를 이용해본 결과, 39점을 받으면서 기본보다 안좋은 성능을 받았습니다. 지금까지 많은 모델을 실험해 본 결과  트리계열의 모델이 가장 좋은 성능을 보이고 있습니다. 다음 시간에는 트리계열의 모델로만 구성된 ensemble 및 stacking model을 시도해볼 계획입니다.  

 

 

 

 

 

 

 

 

728x90
728x90

해당 실습은 iflearn "CNN_Fundamental" 강의에서 사용되었습니다. 실습 진행 순서대로 list-up 했습니다 

 

 

1. Gradient Descent_01

Gradient_Descent.ipynb
0.02MB

Gradient_Desecent 내용은 딥러닝 수학 강의에서 배웠으므로 따로 이론을 정리하지 않았습니다.

 

 

2. Fashion_MNIST_02

fashion-mnist-practice-02.ipynb
0.04MB

2021.10.04 - [Data Diary] - 2021-10-04,05(딥러닝 CNN_기본 특징 설명)

 

2021-10-04(딥러닝 CNN_기본 특징 설명)

CNN은 이미지를의 일 부분을 자동으로 뽑아서 featrue로 사용한다. 반면 머신러닝은 일일히 feature를 뽑기 때문에 효율이 떨어진다. 또한 가변적으로 feature들이 변하기 때문에 성능에도 큰 영향을

ghdrldud329.tistory.com

 

 

 

3. Conv_practice_03

conv-practice-03.ipynb
0.02MB

 

2021.10.04 - [Data Diary] - 2021-10-04,05(딥러닝 CNN_기본 특징 설명)

 

2021-10-04(딥러닝 CNN_기본 특징 설명)

CNN은 이미지를의 일 부분을 자동으로 뽑아서 featrue로 사용한다. 반면 머신러닝은 일일히 feature를 뽑기 때문에 효율이 떨어진다. 또한 가변적으로 feature들이 변하기 때문에 성능에도 큰 영향을

ghdrldud329.tistory.com

 

 

4. CIFAR10_Custom1

cifar10-custom1.ipynb
0.04MB

 

2021.10.08 - [Data Diary] - 2021-10-07(CNN_배치정규화 &따릉이 12)

 

2021-10-07(CNN_배치정규화 &따릉이 12)

1. 따릉이 수요예측 데이터 분리 시, random_state에 따른 학습 성능 차이가 크다는걸 확인하게 되었습니다. 왜그런지 추측을 해본다면 현재 갖고 있는 train data만 1300건 정도 밖에 없습니다. 게다가 F

ghdrldud329.tistory.com

 

 

5. CIFAR10_Custom_Aug1 

cifar10-custom-cb-filters-decay.ipynb
0.03MB
cifar10-custom-aug1.ipynb
0.02MB

2021.10.08 - [Data Diary] - 2021-10-08(CNN_Global AG, 가중치 규제, Augmentation)

 

2021-10-08(CNN_Global AG, 가중치 규제, Augmentation)

Global Average 각 채널 별로 평균값을 추출한다 . 이는 파라미터를 효과적으로 줄이는 효과가 있어서 오버핏팅을 상쇄시킬수 있다. 단, 채널 수가 적은 상태에서 적용하면 오히려 Flatten보다 성능 저

ghdrldud329.tistory.com

 

 

6. CIFAR10_pretrained & CatnDog_Gen(ImageDataGenerator)

cifar10-pretrained.ipynb
0.02MB
catndog-gen.ipynb
0.04MB

2021.10.12 - [Data Diary] - 202-10-12(CNN_Pretained & Keras Generator의 이해)

 

202-10-12(CNN_Pretained & Keras Generator의 이해)

오늘 학습내용은 거의 실습 위주로 진행해서 이론내용은 많지 않았습니다! 특히 사전 학습은 같은 경우는 앞서 프로젝트에서 한번 해봤기 때문에 나름 익숙했습니다. *ImageDataGenerator ImageDataGenera

ghdrldud329.tistory.com

 

 

7. Albumentations_Aug

albumentations-aug.ipynb
0.03MB

2021.10.15 - [Data Diary] - 2021-10-15(CNN_Augmentation)

 

2021-10-15(CNN_Augmentation)

오늘은 Augmentation의 전용패키지에 대해 필기한 내용을 업로드 해보았습니다 :) keras ImageDataGenerator에는 제약적인 부분이 있다. Augmentation을 무조건 많이 한다고해서 성능이 좋아지지 않는다. 각 이

ghdrldud329.tistory.com

 

728x90

'실습 note' 카테고리의 다른 글

딥러닝 수학 실습과제 모음 9~12  (0) 2021.09.04
딥러닝 수학 1~7 실습과제 모음  (0) 2021.08.13
Mask-RCNN 실습모음(2021-07-29~02)  (0) 2021.08.02
EfficientDet 실습모음(2021-07-27~28)  (0) 2021.07.27
YOLO 실습 모음  (0) 2021.07.21
728x90

실습내용은 아래 링크에서 확인할 수 있습니다.

2021.10.05 - [실습 note] - CNN_Fundamental 실습 모음

 

CNN_Fundamental 실습 모음

해당 실습은 iflearn "CNN_Fundamental" 강의에서 사용되었습니다. 실습 진행 순서대로 list-up 했습니다 1. Gradient Descent_01 Gradient_Desecent 내용은 딥러닝 수학 강의에서 배웠으므로 따로 이론을 정리하..

ghdrldud329.tistory.com

 

 

CNN은 이미지를의 일 부분을 자동으로 뽑아서 featrue로 사용한다. 반면 머신러닝은 일일히 feature를 뽑기 때문에 효율이 떨어진다. 또한 가변적으로 feature들이 변하기 때문에 성능에도 큰 영향을 주었다.

딥러닝은 Universal 한 Feature를 유연성 있게 뽑아준다. 한개의 뉴런 당 하나의 이미지 part를 맡게 된다. 예를들어 고양이 사진에 뉴런 100개라면, 고양이 사진을 100개 부분으로 개별적으로 본다는 것이다. 다시 돌아와서 convolutional laters에서 feature 특징들이 모이게 되면 이를 "feature map"이라 부른다. 이 feature map을 Dense layer에 넣게 된다. 해당 Dense layer를 Fully connected layer 혹은 Classifier layer 라고 부른다. 해당 layer는 실제와 예측을 비교해가면서 가중치를 updata해 가는데, 이때 가중치의 updata는 Feature Extractor 가중치까지 영향을 준다. 학습하기 전 FE에서는 이미지의 특징을 정답없이? 방향성 없이 FE를 진행한다. 그러다가 특정 target에 대한 Loss가 발생하게 되고, 가중치들이 Updata가 되면서, FE가 특정 target에 대한 특징을 뽑게 된다. 다시말해서 target이 고양이 이고, input 이미지가 고양이가 찍혀 있는 공원이라고 했을때, updata가 되면서 인풋 이미지의 벤치, 하늘, 사람 등 고양이를 제외한 배경들의 가중치는 줄어들게 되고, 고양이에 해당된 가중치들이 업데이트 된다. 고양이이라는 이미지에 맞춰서 FE를 뽑게 된다.

Low level Feature 에서는 주로 이미지를 구성하는 "선"의 특징들로 구성되어 있다. 그 다음 단계인 Mid에서는 더 상세한 특징이 보다는 "추상적인" 특징들이 뽑힌다. layer가 깊어질수록 추상적인 이미지가 뽑힌다.

위 그림을 보듯이, layer가 깊어질수록 뭉개지면서 추상적인 이미지가 생기게 됨을 확인할수있다.

왼쪽 새 이미지의 한 부분에 대해서 Feature를 만든다. 이렇게 만든 Feature에 layer를 추가하여 추상적인 이미지를 뽑는다. 이 과정을 반복하여 만든 Featrue들을 Classifier layer에 넣어서 최종적으로 판단하게 된다. CNN = Feature Extractor + Classifier networt로 구성되어 있다. 최선의 FE를 위해서 필터 가중치를 updata 시킨다. 그리하여 최적의 Feature를 생성한다.

왼쪽처럼 필터를 적용하면 이미지가 작아진다. 그래서 오른쪽의 Zero padding을 사용하여 원본이미지를 7*7로 만들고 필터 계산하여 원본 사이즈인 5*5로 만들수 있다. 참고로 필터는 여러개의 커널로 구성되어 있다.

 

 

*Kernal size 특징

커널사이즈를 높일수록 계산될 파라미터들이 많아진다. 7*7는 Alexnet에서 사용된 이후로 잘 사용되지 않고 있다.

 

 

*Feature Map 개요

Feature map이란 필터들을 적용한 결과를 말한다. 4개의 feature map이 있다는건 4개의 필터를 적용했기 때문이다. 위 형식이 CNN의 기본 과정이다.

 

 

 

*Stride

 

 

 

*Padding

원본이미지를 유지하기 위해서 상하좌우 겉 테두리에 0값을 넣는게 패딩이다.

패딩의 목적은 layer가 길어질수록 feature map이 작아지는 문제점을 막기 위함이다. 모서리 부분에는 패딩에 의해서 중첩 계산이 발생하므로 모서리의 특징이 보다 더 강화가 된다.

 

 

 

*Pooling

Pooling은 Pool size 만큼 stride가 동일하게 적용된다. 만일 동일하게 하지 않을 시, 중첩되는 부분이 발생하기 때문에 이를 방지하고자 겹치지 않게 Pooling을 하게 된다.보통 Average Pooling은 잘 사용되지 않는다. 뽑고자 하는 특징과 그렇지 않는 특징이 혼합된 경우에 평균으로 계산하면 target 특징을 잘 표현하지 못하게 되기 때문이다. Max을 이용하여 가장 뚜렷하고 특징적인 부분을 뽑고자 Max Pooling을 주로 선호한다. 보통 2*2 Max Pooling을 이용한다.

leNet, AlexNet에는 Conv2d(S/P) -> Pooing 매커니즘 토대를 닦아 놓았다. VGG에서는 이러한 매커니즘을 충실히 반영한 모델이다. 하지만 최근 모델에는 Pooling을 자제하고 Stride를 이용하려는 경향이 강해지고 있다.

 

 

 

*채널과 커널의 이해

중요하게 봐야 할 점은 Input과 kernel 연산 -> "더하기" -> 2차원의 Output이 생성된다는 점이다.

bias 1을 위 그림처럼 일일히 더해줘야 한다.

*피처맵 크기 공식

s=2 적용시, 가장 오른쪽 부분이 계산 안될수가 있다. 그래서 s=2일때는 주의를 기울어야한다. 빨간 줄 부분이 연산되지 않는 부분이다.

이러한 부분을 해결하기 위해서 padding을 사용한다. s=2일때 padding='same'을 사용하게 된다. 이때 padding의 의미가 달라진다. s=1일때는 input과 output size를 동일하게 한다는 의미였지만, 위 그림을 보면 (3,3,1)로 출력 되었다. 즉, 빠지는 부분 없이 연산을 하겠다 라는 의미로 s=2에서는 padding이 사용된다.

padding='same'을 하게 되면 6*6 -> 8*8로 변한다. 사실 7*7만 있어도 빠지는 부분없이 연산이 가능하다. 그래서 위 이미지처럼 zero 패딩을 수동으로 입력할수 있다. (1,0) -> 위로 패딩 한줄 ,(1,0) -> 왼쪽에 패딩 한줄 이다. 빨간 박스를 보면 위,왼쪽에 빨간선이 추가가 된걸 확인할수 있다. 그렇다면 "아래 한줄, 오른쪽 한줄"은 무엇일까 (0,1),(0,1) 이다.

728x90
728x90

https://colab.research.google.com/drive/1CsnK5YrMDtSiAeQezPmw_7YPjZlg_8uS?hl=ko 

 

Google Colaboratory Notebook

Run, share, and edit Python notebooks

colab.research.google.com

dacon의 따릉이 자전거 이용 예측 프로젝트입니다. 

현재 기준으로 데이콘 리더보드에서 6위를 기록하고 있습니다.

감사합니다 :)

728x90

'projects' 카테고리의 다른 글

Face Mask Detection  (0) 2021.08.25
동서발전 태양광 발전량 예측 프로젝트_dacon  (0) 2021.06.29
뉴욕 택시수요예측  (0) 2021.02.16
국민청원글 토픽모델링  (0) 2021.01.18
CNN_BTS 멤버 image classification  (0) 2021.01.10
728x90

우리가 원하는 포인트는 가장 최저점을 나타내는 global point이다. 하지만 위 그림처럼 local 포인트에 빠지거나, 평평한 부분인 saddle 포인트를 만나면서 최저점이라고 인식하는 오류를 범할수 있다. 이를 해결하기 위해 다양한 optimizer들이 등장했다.

주요 Optimizer들이다. momentum은 GD값을 조정하고, adagrad,rmsprop은 lr을 조정한다. adam은 GD,lr 모두 조정하면서 최적점을 찾는다.

 

 

 

*Momentum

과거의 GD에 Momentum 가중치를 적용하여 새로운 GD를 계산한다. 기존의 GD는 wt+1 = wt- GD 이다. momentum은 이 GD에다가 감마라는 가중치를 적용해 준다. 헷갈리지 말아야 할점은 새롭게 구한 gradient에 감마를 곱하는게 아니다. 바로 이전에 구했던 GD에 감마를 곱한 뒤 새롭게 구한 GD에 더해준다. 식으로 표현하면

Wt+1 = 과거 GD - (새롭게 구한 gradient + 감마 * 과거 gradient)이다. GD는 gradient Descent이며 gradient와는 다른 값이다.

 

과거의 gradient을 감안하면 어떤 점이 좋은가?

현재 local 포인트에 갇혔다고 가정해 본다. 과거 gradient 두개 값을 더해주어서 local 지역을 빠져 나가게끔 힘을 보탤수가 있다.

각 입력되는 데이터의 크기에 따라 loss가 증감을 반복하기 때문에 SGD같은 경우엔 지그재그로 학습이 된다. 이럴경우 학습시간이 느려질뿐만 아니라 학습 자체가 안될수 있기 때문에 지그재그 학습 현상은 지양해야한다. momentum을 사용하면 이러한 지그재그 현상을 줄일수 있다.

 

 

*AdaGrad(Adaptive Gradient)

입력 데이터의 크기에 따라 각각의 가중치 학습속도에서 차이가 발생한다. 이때 AdaGrad를 활용하여 적게 학습된 가중치에는 lr을 크게 설정하고, 많이 학습된 가중치에는 작은 lr을 적용한다. 참고로, 각각의 가중치 학습 속도가 다를 경우 최적점에 도달하기엔 한계있다.

식을 보면 lr의 분모가 생겼음을 알수 있다. 해당 분모 값을 통해 비율을 조절하게 된다.분모에 있는 엡실론의 역할은 분모가 0이 되는걸 방지하기 위함이다. St를 보면 Gradient의 제곱을 해주는데 그 이유는 마이너스,플러스값이 나올수 있기 때문이다.

Gradient의 제곱은 언제나 양이기 때문에 계속 증가할 수밖에 없다. 그래서 lr 값이 아주 작게 설정되는 문제점을 안고 있다. 이를 해결한 것이 RMSprop이다.

 

 

 

* RMSprop

오래된 Gradient값에 가중치를 적용하여 영향력을 줄이도록 제한한다. 예를들어 위 분홍색 식에서 감마가 0.9라고 한다면 오래된 Gradient인 St-1에 0.9가 계속 곱해진다. 0.9*0.9*0.9*~~*0.9*오래된 Gradient +(1-0.9)*new Gradient.

 

 

 

* Adam(Adaptive Moment Estimation)

RMSProp와 거의 흡사하다. 차이점이 있다면 Momentum을 지수 가중 평균법으로 변경한 점이다. 또한 Adam은 베타1,베타2로 조절한다.

728x90
728x90

iflearn의 CNN 완벽가이드를 새로 시작했습니다. 초반 강의는 딥러닝 수학 강의 내용과 겹쳐서 내용은 생략했습니다. 

활성화 함수 part부터 업로드 합니다.

 

활성화 함수는 사용하는 이유는 비선형성으로 만들기 위함이다. 활성화 함수가 없다면 선형함수로써 왼쪽처럼 구분이 된다. 하지만 오른쪽 처럼 비선형이 적용되면 과적합 문제가 발생하기 쉽다. 활성화 함수 별 사용용도를 아래 그림을 통해 확인한다.

각 활성화 함수별 사용 용도가 각각 다르다.

 

 

*Sigmoid 함수 특성

X값이 양으로 100 이든 1000이든 출력은 1로 수렴이 된다. X값이 음수로 -100이든 -1000이든 출력은 0으로 수렴이 된다. 이때 sigmoid의 미분를 표현한 파란색 분포를 보겠다. X가 음수든 양수든 커질수록 어찌됐든 1과0으로 수렴하기 때문에 양쪽 사이드가 감소하는 모양을 띈다. 미분은 "내가 변했을때 넌 얼만큼 변해?" 의 양을 나타낸다. 다시말해 X가 얼마나 커지든 작아지든 나는 0과 1로만 수렴하기 때문에 변화의 한계가 존재한다. 이로인해 Vanishing Gradient 문제가 발생하게 된다.(은닉층으로 사용할 시)

시그모이드를 미분하면 0이 출력되는 현상때문에 위 그림처럼 층이 깊어질수록 Gradient값이 점점 사라지게 된다.

그래서 시그모이드는 이진분류를 수행할때 주로 사용된다. 왼쪽 선형식으로는 1과0으로 구분하기가 쉽지 않다. 이를 시그모이드를 통해 확률 0.5를 기준으로 1과0으로 분류할수 있다.

 

 

 

*Hyperbolic Tangent 함수 특성

시그모이드와는 달리 -1~1사이의 값을 취급하지만 같은 문제점을 안고 있다. X값에 따라 결국은 수렴을 하기때문에 vanishing이 발생한다.

 

 

*ReLU(Rectified Linear Unit)함수 특성

입력값이 0보다 작으면 0으로 출력하고, 0보다 크면 수렴이 하지 않고 똑같이 출력한다. 그래서 오른쪽 그림의 미분이 0으로 떨어지지 않고 1을 반환한다.

 

 

*SoftMax함수 특성

시그모이드는 0.9이면 "1"이라고 값을 "하나만" 출력해준다. 반면 소프트 맥스는 이를 여러개로 반환할수 있다. 위 그림처럼 output layer를 소프트맥스에 넣게 되면 그에 맞는 확률값으로 반환해준다. 반환된 확률 값중 가장 큰 값을 선택하여 클래스를 결정한다.

 

 

*Cross Entropy Loss

분류일 경우엔 예측값과 실제값 사이의 Cross Entropy를 구하여 Gradient Descent를 계산한다. 위 그림의 하단 식에서 i는 data의 건수를 의미한다. ex) 첫번째 이미지는 i=1로 표현할수 있겠다. 따라서 m은 데이터의 건수를 의미한다. Loss를 보면 m으로 나누기 때문에 Cross entropy의 평균을 Loss로 사용하고 있음을 알수있다.

하단을 먼저 보면, output layer에서 위 처럼 값이 들어오고, 이를 softmax을 통과하면 가장 큰 확률값의 인덱스를 통해 클래스를 결정하게 된다. 이때의 Loss를 구하는 것은 아래 식을 통해 자세히 보겠다.

C는 class의 갯수이다. 예를들어 고양이 부터 강아지까지 5종류의 동물을 나타낸다. 이때, CE의 값은 위 식처럼 계산된다. 식을 통해 알수 있는 점은 0인 클래스, 즉 정답이 아닌 클래스는 모두 더해봤자 log0=0이므로 0이다. Loss는 오직 Class=1일때 구할수 있다.

---

왼쪽 그래프에서 값을 크~게 잘못 예측하게 되면 loss 값 또한 커지는 걸 볼수있다.

 

시그모이드는 0 or 1 이진 분류를 나타내고자 할때 사용된다. 만일 0.7이라는 예측값을 얻었을때의 loss는 얼마인가를 생각해 보자. 이진 분류이기 때문에 두가지 경우로 생각해 볼수 있다. 실제 값이 1인 경우와 0인 경우 일것이다. 실제값이 1일때의 loss 값, 실제값이 0일때의 loss값을 알아내야 한다. 그래서 식이 softmax 와는 조금 다르다. 실제값이 1이라면

뒤에 있는 값이 0이 될것이다. 1-1 = 0 이니까. 반대로 실제값이 0이라면

위에 해당 부분이 0이 되고 뒷부분 식에서 loss값을 구할수 있게 된다.

728x90
728x90

*주요 요약

  • seasonal 추가
  • 오존,미세먼지,초미세먼지 변수 -> 카테고리로 변경

 

지금까지 여러 파생변수를 만들어 보고 실험해 봤는데 대부분이 쓸모 없었습니다 아마 오늘을 끝으로 변수에 대한 FE는 마무리가 될것 같습니다. 다음 시간부터는 최적의 모델링을 찾는데 시간을 쓸것 같습니다 

 

 

1. Seasonal 추가

시계열 기법중에 분해기법이 있습니다. 계절성 정보를 넣으면 예측에 유리할 것같아서 시도 해봤습니다. 제가 가지고 있는 데이터는 날짜 형식이 아니며, 순서도 뒤죽박죽이기 때문에 grouby로 hour 별 mean 값을 구한 뒤, 가짜 날짜 변수를 생성하여 seasonal을 구했습니다. 그 후 각 시간별 seasonal 정보를 매칭시켜서 원본 데이터에 적용했습니다. 

train_tem = train.groupby('hour').mean().reset_index()
train_tem['Date'] = pd.date_range(start='2017-04-01 00:00:00', end='2017-04-01 23:00:00', freq='H')
train_tem['Date'] = pd.to_datetime(train_tem['Date'])
train_tem.set_index(train_tem['Date'], inplace=True)
train_tem=train_tem.asfreq('H')
result = sm.tsa.seasonal_decompose(pd.concat([train_tem['count'],train_tem['count']], axis=0),model='additive', freq=24)
result.seasonal
Date
2017-04-01 00:00:00    -36.915619
2017-04-01 01:00:00    -61.075729
2017-04-01 02:00:00    -77.272450
2017-04-01 03:00:00    -87.305237
2017-04-01 04:00:00    -95.157696
2017-04-01 05:00:00    -95.567532
2017-04-01 06:00:00    -84.124909
2017-04-01 07:00:00    -46.321630
2017-04-01 08:00:00     28.006239
2017-04-01 09:00:00    -15.141302
2017-04-01 10:00:00    -29.879007
2017-04-01 11:00:00    -20.354417
2017-04-01 12:00:00      3.219353
2017-04-01 13:00:00     11.367714
2017-04-01 14:00:00     25.907878
2017-04-01 15:00:00     44.284927
2017-04-01 16:00:00     60.417714
2017-04-01 17:00:00     78.451047
2017-04-01 18:00:00    153.481648
2017-04-01 19:00:00     92.924271
2017-04-01 20:00:00     56.186566
2017-04-01 21:00:00     60.134381
2017-04-01 22:00:00     39.563616
2017-04-01 23:00:00     -4.829827
2017-04-01 00:00:00    -36.915619
2017-04-01 01:00:00    -61.075729
2017-04-01 02:00:00    -77.272450
2017-04-01 03:00:00    -87.305237
2017-04-01 04:00:00    -95.157696
2017-04-01 05:00:00    -95.567532
2017-04-01 06:00:00    -84.124909
2017-04-01 07:00:00    -46.321630
2017-04-01 08:00:00     28.006239
2017-04-01 09:00:00    -15.141302
2017-04-01 10:00:00    -29.879007
2017-04-01 11:00:00    -20.354417
2017-04-01 12:00:00      3.219353
2017-04-01 13:00:00     11.367714
2017-04-01 14:00:00     25.907878
2017-04-01 15:00:00     44.284927
2017-04-01 16:00:00     60.417714
2017-04-01 17:00:00     78.451047
2017-04-01 18:00:00    153.481648
2017-04-01 19:00:00     92.924271
2017-04-01 20:00:00     56.186566
2017-04-01 21:00:00     60.134381
2017-04-01 22:00:00     39.563616
2017-04-01 23:00:00     -4.829827
Name: count, dtype: float64

 

seasonal_df = pd.DataFrame(result.seasonal)
seasonal_df = seasonal_df.iloc[:24].reset_index(drop=True)
seasonal_df
      count
0	-36.915619
1	-61.075729
2	-77.272450
3	-87.305237
4	-95.157696
5	-95.567532
6	-84.124909
7	-46.321630
8	28.006239
9	-15.141302
10	-29.879007
11	-20.354417
12	3.219353
13	11.367714
14	25.907878
15	44.284927
16	60.417714
17	78.451047
18	153.481648
19	92.924271
20	56.186566
21	60.134381
22	39.563616
23	-4.829827

 

def seasonal_fill(x):
  value = float(seasonal_df[seasonal_df.index==x].values)
  return value
df['seasonal'] = train['hour'].apply(seasonal_fill) 
df.head()

 

 

 

 

2. 오존,미세먼지,초미세먼지 변수 -> 카테고리로 변경

해당 아이디어는 다른 분의 블로그를 보면서 참고했습니다. 왜 이 생각을 못했을까 했어요 

# 오존, 좋음/보통/나쁨/매우나쁨 을 기상청 기준으로 다른 class 부여
df['hour_bef_ozone'] = df['hour_bef_ozone'].apply(lambda x : 0 if x <= 0.03 else 
                                                                   1 if 0.03 < x and x <= 0.09 else 
                                                                   2 if 0.09 < x and x <= 0.151 else
                                                                   3 if 0.151 < x else x)

# 미세먼지, 좋음/보통/나쁨/매우나쁨 을 기상청 기준으로 다른 class 부여
df['hour_bef_pm10'] = df['hour_bef_pm10'].apply(lambda x : 0 if x <= 30 else 
                                                                 1 if 30 < x and x <= 80 else 
                                                                 2 if 80 < x and x <= 150 else
                                                                 3 if 150 < x else x)

# 초미세먼지, 좋음/보통/나쁨/매우나쁨 을 기상청 기준으로 다른 class 부여
df['hour_bef_pm2.5'] = df['hour_bef_pm2.5'].apply(lambda x : 0 if x <= 15 else 
                                                                   1 if 15 < x and x <= 35 else 
                                                                   2 if 35 < x and x <= 75 else
                                                                   3 if 75 < x else x)

#One-Hot Encoding
df = pd.get_dummies(df, columns=['hour_bef_ozone','hour_bef_pm10','hour_bef_pm2.5'])

해당 변수를 원핫 인코딩 전/후 모두 비교해 봤는데, 결과적으로는 미미한 영향이었습니다. 애초에 target과 연관성이 적었던 변수들이기 때문입니다. 그래도 이번 계기로 데이터를 바라보는 시각이 조금은 넓어진 느낌을 받았습니다 :)

 

728x90

+ Recent posts