LGBM
Light Gradient Boosting Machine의 약자인 LightGBM 은 원래 Microsoft에서 개발한 머신 러닝을 위한 무료 오픈 소스 분산 그래디언트 부스팅 프레임워크
알고리즘은 GOSS(Gradient-Based One-Side Sampling) 및 EFB(Exclusive Feature Bundling)라는 두 가지 새로운 기술을 사용하여 높은 수준의 정확도를 유지하면서 알고리즘을 더 빠르게 실행
Light GBM은 Gradient Boosting 프레워크로 Tree 기반 학습 알고리즘
단, LGBM은 100개 이상의 파라미터를 가지고있기 때문에 파라미터 튜닝이 어려움
과적합에 민감하여 10,000개 이상의 데이터에 사용을 추천
LGBM 학습 방식
출처 - https://www.analyticsvidhya.com/blog/2017/06/which-algorithm-takes-the-crown-light-gbm-vs-xgboost/
기존 트리들은 tree depth를 줄이기 위해 균형 트리 분할을 사용했지만 lightgbm은 불균형 트리방식을 사용(빠른 대신 과적합에 민감해짐)
알고리즘
GOSS(Gradient-Based One-Side Sampling
- one-side sampling
데이터 갯수를 내부적으로 줄여서 계산할 때, 큰 gradient를 가진 데이터는 놔두고 작은 gradient는 랜덤하게 드랍
- one-side sampling 문제점 해결
상태에서 훈련하면 정확도가 낮아지게 되는데 따라서 낮은 gradient의 값들은 가져와서 버린 샘플만큼 뻥튀기한다. 1 – a / b 를 곱해서 수를 맞춰준다.
- 전체적인 과정 흐름도
- 모델로 예측 및 loss 계산
- loss로 정렬 후 상위 N개 추출하여 topSet에 저장
이때 a 변수 사용 top 몇퍼센트를 가져갈지 예 30% 뽑는다면 0.3
- topSet을 제외한 나머지 데이터 셋중 일부반 추출
이때 b 변수 사용 30% 추출시 b = 0.3
- 위 두 단계에서 데이터 샘플링 완료 후 b로 추출된 데이터 셋의 weight를 1- a/b 취함
- 위 단계를 거쳐 약한 예측기를 만들어 전체 예측기에 추가
EFB(Exclusive Feature Bundling)
- 아이디어 1
실제 데이터에서는 원핫인코딩과 같이 0이 굉장히 많은 희소행렬 형태인 경우가 많다.
-> 사실 트리모델에서 이렇게 상호 배타적인 (컬럼중 하나에만 값이 있고 나머지는 0인 경우) feature들은 하나로 통합이 가능하며, 이를통해 많은 계산량을 아낄 수 있다.
- 아이디어 2
feature가 몇가지만 값이 같다면 (수치형으로는 correlation이 높은) 몇가지 값들의 충돌을 무시하고 합쳐버리면 계산량을 좀더 줄일수 있다. (거의 비슷한 row data)
즉, data수(row) x feature수(column)에서 row X 합쳐진column(bundle) 이 되어 상당한 수의 계산이 줄어들 수 있다.
LGBM 파라미터 (중요한 것만 정리)
파라미터 | 설명 | default | 비고 |
---|---|---|---|
max_depth |
Tree의 최대 깊이 - 과적합 및 모델 속도 등 | -1 | -1은 깊이제한 없음 |
num_leaves |
하나의 트리가 가질 수 있는 최대 리프 개수 | 31 | |
min_child_samples |
리프 노드가 되기 위해 최소한으로 필요한 레코드 수 | 20 | |
early_stopping_rounds |
학습 조기종료를 위한 early stopping interval 값 | None | |
boosting_type |
부스팅의 트리를 생성하는 알고리즘 | gbdt | |
reg_alpha, reg_lambda |
L1, L2 regularization | 0. | |
learning_rate |
학습 량 | ||
bagging_fraction |
데이터를 일부 발췌해서 다양성을 높이는 방법으로 사용 (민감한 옵션으로 feature_fraction과 잘 섞어서 사용 필요) | GOSS에서는 알아서 샘플링하는 과정이 있어서 에러 발생 | |
feature_fraction |
열 샘플링, 컬럼에 대한 샘플링을 통해 각각의 높임 | ||
num_iterations |
반복량 | ||
scale_pos_weight |
양성인 경우 데이터 뻥튀기, 불균형셋에서 유용할 수 있으나 너무 많은경우 정확도가 떨어짐 | 1.1~1.5 정도의 가벼운 수준 추천 | |
boosting/booster |
부스팅 방법 rf(random forest), gbdt(Gradient Boosted Decision Trees), dart(Drop out Regression Trees), goss(bradient-based one-side Sampling) | gbdt | 정확도가 중요할때는 딥러닝 드랍아웃과 같은 dart 적용. 샘플링을 이용한 goss(속도 업, 정확도 내려감) 적용 |
Metric/loss |
CE, MSE, MAE, MAPE, Log Transformation, Quantile 등 지원 |
Imbalance Problem
- down up dampling
- scale_pos_weight
Focal Loss
class imbalance문제를 해결하는데 사용되는 손실함수
이진 분류에서 사용되는 Cross Entropy(CE) 손실 함수로부터 비롯됨
- CE loss
CE loss는 아래와 같음
- y=1인 경우
-log(p)
- otherwise
-log(1-p)
모든 sample에 대한 예측 결과를 동등하게 가중치를 둠
-> 모든 셈플에 대해서 큰 loss를 발생시켜 드문 class의 loss를 압도하는 경우가 발생
- Balanced Cross Entropy
이 문제를 해결하기 위해 가중치 파라미터인 a를 곱해준 손실 함수를 제안
CE(p) = -alog(p)
y=1 일때 a를 곱해주고 y= -1일때 1-a를 곱해주는 방식
위 방식은 positive/negative sample 사이의 균형을 잡아주지만
easy/hard sample에 대해서는 균형을 잡지 못함
- Focal loss
focal loss 는 easy example을 down-weight하여 hard negative sample에 집중하여 학습하는 loss function
위 그림에서 파란색 선은 CE 이고, 경사가 완만하여 Pt가 가장 높은 부분과 낮은 부분의 경사 차이가 상대적으로 크지 않음
- Pt
example이 잘못 분류되고 Pt가 작으면 modulation factor는 1과 가까워지며 loss는 거의 영향을 받지 않음
pt가 높으면 modulation factor는 0에 가까워지고, 잘 분류된 loss는 down-weight됨
- r
r는 easy example을 down-weight하는 정도를 부드럽게 조정 r=0인경우 CE와 같으며 R이 상승할 수록 modulatino factor의 영향력이 커짐 (논문에서는 r=2가 가장 좋은값)
rest api
- 기본 설정
from flask import Flask # 서버 구현을 위한 Flask 객체 import
from flask_restx import Api, Resource # Api 구현을 위한 Api 객체 import
app = Flask(__name__) # Flask 객체 선언, 파라미터로 어플리케이션 패키지의 이름을 넣어줌.
api = Api(app) # Flask 객체에 Api 객체 등록
@api.route('/hello') # 데코레이터 이용, '/hello' 경로에 클래스 등록
class HelloWorld(Resource):
def get(self, name): # GET 요청시 리턴 값에 해당 하는 dict를 JSON 형태로 반환
return {"message" : "Welcome, %s!" % name}
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=80)
hello 라는 url 로 요청이 온 경우
-> get 요청이 온경우 get 함수로 요청 내용이 넘어 옴
- get post put delete
from flask import Flask, request
from flask_restx import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
count = 1
@api.route('/todos')
class TodoPost(Resource):
def post(self):
global count
global todos
idx = count
count += 1
todos[idx] = request.json.get('data')
return {
'todo_id': idx,
'data': todos[idx]
}
@api.route('/todos/<int:todo_id>')
class TodoSimple(Resource):
def get(self, todo_id):
return {
'todo_id': todo_id,
'data': todos[todo_id]
}
def put(self, todo_id):
todos[todo_id] = request.json.get('data')
return {
'todo_id': todo_id,
'data': todos[todo_id]
}
def delete(self, todo_id):
del todos[todo_id]
return {
"delete" : "success"
}
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=80)
- 자세한 내용은 아래 url 의 rest api 블로그 보기
참고 사이트
- lgbm 설명
https://en.wikipedia.org/wiki/LightGBM
https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html
https://ek-koh.github.io/data%20analysis/lgbm/
http://machinelearningkorea.com/2019/09/29/lightgbm-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0/
http://machinelearningkorea.com/2019/09/25/lightgbm%EC%9D%98-%ED%95%B5%EC%8B%AC%EC%9D%B4%ED%95%B4/
- flocal loss
https://herbwood.tistory.com/19
https://en.wikipedia.org/wiki/Cross_entropy
- rest api
https://justkode.kr/python/flask-restapi-1