이번 미니 프로젝트는 3일간 진행되었습니다.
프로젝트 개요
주제 | 스마트폰 센서 기반 데이터를 활용한 HAR( human activity recognition, 인간 행동 인식) |
사전학습 과목 | 데이터 처리, 데이터 분석, DL 모델링 |
데이터 출처 | UCL Machine learning Repository |
데이터 구분 | Tabular |
문제유형 | Classification |
스마트폰 기반의 센서 데이터를 활용해 동작을 분류하는 모델을 완성하고 일반인 대상으로 제공할 수 있는 연계 서비스를 구상하는 것이 이 프로젝트의 목표입니다!
데이터 수집 절차
1. 측정
- 30명의 참가자가 galaxy S2를 착용한 후 6가지의 행동을 진행
- 가속도 센서, 자이로스코프 센서 활용
2. 특징 추출
- 수집 : 2.56초 번위(window), 1.28초 간격으로 이동하며 데이터 샘플링 (하나의 행)
- 집계 : 하나의 window에서 수집된 데이터를 신호 별로 분리 후 집계
데이터 구조
제공받은 csv 파일은 총 4개로
train data, test data, 데이터에 대한 설명 파일이다.
561개의 featrue는 sensor + aggregation + axis 구조로 구성되어 있다.
[1일차] 데이터 탐색 및 분석
1일차엔 데이터를 탐색하고 분석하는 과정을 거쳤고
3시 30분부터 조별 줌으로 들어가 개별로 분석한 내용을 공유하고 jupyter 통합본을 완성했다.
단변량 분석을 통해 데이터를 탐색해보고 두가지로 방법으로 데이터 분석을 진행했다.
데이터 탐색
1. 불러온 데이터의 형태, 기초통계량, 정보 등을 확인
2. target인 'Activity'에 대해 단변량 분석을 수행
타겟 데이터의 불균형이 심하지 않다.
walking_upstairs와 waliking_downstairs 가 데이터 수가 조금 부족하므로 oversampling 을 해야할 수도 있다.
데이터 분석 방법1 : Activity - 다중분류
1) 기본 모델을 생성한 후 변수 중요도를 구합니다. (random forest 알고리즘 사용) 2) 중요한 feature와 중요하지 않은 feature 상위 N개를 선정하고, 이들을 대상으로 EDA 수행 |
변수 중요도를 시각화하면
상위 5개가 중력 가속도 측정과 관련이 있다는 것을 알 수 있다.
선정된 변수(feature)와 target 간의 관계를 kdeplot으로 그리면
밀도 함수가 겹친 상황에서는 해당 feature가 'Activity' 들을 잘 구분할 수 없다는 의미이다.
상위 변수 5개가 'laying'을 제외한 나머지 class들은 잘 구별하지 못한다.
하위 변수를 보면 'Activity'에 대한 분류를 잘 해내지 못한다.
하지만, 2개 class 그룹(정적행동, 동적행동)은 잘 구분해낼 수 있을 것 같다.
데이터 분석 방법2 : is_dynamic - 이진분류
1) Target을 정적/동적 행동으로 구분 2) 어떤 feature(혹은 feature 그룹)이 2개 class 그룹(정적행동, 동적행동)를 구분하는데 중요한지를 찾아보고 탐색 |
Target인 Activity를 is_dynamic 변수로 변경했다.
- 값 0 : STANDING, SITTING, LAYING
- 값 1 : WALKING, WALKING_UPSTAIRS, WALKING_DOWNSTAIRS
변수 중요도를 시각화하면
상위 5개가 중력 가속도 측정과 관련이 있다는 것을 알 수 있다.
선정된 변수(feature)와 target 간의 관계를 kdeplot으로 그리면
동적 활동일 때(is_dynamic=1) 데이터는 약 1 부근에 집중되어 있다.
정적 활동일 때(is_dynamic=0) -1 부근과 0 사이의 넓은 영역에 분포해 있다.
앉아 있거나 누워 있을 때 특정 축에 대해 중력이 음수 방향으로 작용할 수 있고, 이로 인해 -1 부근에 분포가 생길 수 있다.
변수 분포가 명확하게 구분되는 경우가 많으며, 특히 X축의 중력가속도 변수들이 동적/정적 활동을 구별하는 데 중요한 역할을 할것이다.
[2일차] 모델 학습 및 성능 비교
2일차엔 다양한 딥러닝 구조로 모델을 생성하고 각 모델 별 5번 반복수행하고 얻은 성능의 평균을 계산하여 비교했다.
3시 30분부터 조별 줌으로 들어가 개별로 분석한 내용을 공유하고 jupyter 통합본을 완성했다.
위와 같이 모델구조를 설정했다.
def make_lst(input, hl, output):
lst = list()
lst.append(input)
for l in hl:
lst.append(l)
lst.append(output)
return lst
모델 1 : base model
model1 = Sequential([Input(shape = (nfeatures,)),
Dense(6, activation = 'softmax')])
model1.summary()
베이스 모델 성능이 워낙 좋아서 더 높힐 수 있을까 고민을 많이 했다.
모델 2 : hl 조정
def make_sequential_model(lst, learning_rate=0.01, epochs=5, x_train=x_train, y_train=y_train, see_history_plot=True):
clear_session()
model = Sequential(lst)
print(model.summary())
model.compile(optimizer=Adam(learning_rate), loss='sparse_categorical_crossentropy')
history = model.fit(x_train, y_train, epochs=epochs, validation_split=0.2, verbose=0).history
if see_history_plot:
dl_history_plot(history)
return model
lst = make_lst(Input(shape=(nfeatures, )), [], Dense(target_features, activation='softmax'))
tmp = list()
for i in range(5):
model = make_sequential_model(learning_rate=0.001, epochs=10, lst=lst)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
tmp.append(accuracy_score(y_val, pred_arg))
hidden layer가 6일때 가장 높게 나온다는 것을 알 수 있다.
모델 3 : rl 조정
def get_lr_res(lr, nfeatures=nfeatures, target_featrues=target_features, x_val=x_val, y_val=y_val):
res = list()
input = Input(shape=(nfeatures, ))
output = Dense(target_features, activation='softmax')
lst = make_lst(input, [], output)
for i in lr:
model = make_sequential_model(lst=lst, learning_rate=i, see_history_plot=False)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
res.append(accuracy_score(y_val, pred_arg))
return res
learning_rate는 0에서 0.02 사이의 값이 적합하다는 것을 알 수 있다.
모델 4: epoch 조정
EP 점진적으로 늘리기(범위 : 5 ~ 200), HL : 없음, learning_rate=0.01
def get_ep_res(ep, nfeatures=nfeatures, target_featrues=target_features, x_val=x_val, y_val=y_val):
res = list()
input = Input(shape=(nfeatures, ))
output = Dense(target_features, activation='softmax')
lst = make_lst(input, [], output)
for i in ep:
model = make_sequential_model(lst=lst, epochs=i, see_history_plot=False)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
res.append(accuracy_score(y_val, pred_arg))
return res
epoch는 15와 200이 가장 적합하다는 것을 알 수 있다.
모델 5: dropout 조정
dp 비율 점진적으로 늘리기 learning_rate: 0.003, epochs: 20, HL : 5개(333)
def get_dp_res(ratio, layer, nfeatures=nfeatures, target_featrues=target_features, x_val=x_val, y_val=y_val):
res = list()
input = Input(shape=(nfeatures, ))
output = Dense(target_features, activation='softmax')
for r in ratio:
clear_session()
hl = list()
for i in range(layer):
layer_name = f'dense_{i}'
hl.append(Dense(333, activation='relu', name=layer_name))
hl.append(Dropout(r))
lst = make_lst(input, hl, output)
model = make_sequential_model(lst=lst, learning_rate=0.003, see_history_plot=False)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
res.append(accuracy_score(y_val, pred_arg))
return res
dropout는 0.1이나 0.45가 적합하다는 것을 알 수 있다.
모델 6: Regularizers 조정
from keras.regularizers import l1, l2
tmp = list()
for i in range(5):
clear_session()
model = Sequential([Input(shape = (nfeatures,)),
Dense(128, activation = 'relu', kernel_regularizer=l2(0.01)),
Dense(64, activation = 'relu', kernel_regularizer=l2(0.01)),
Dense(32, activation = 'relu', kernel_regularizer=l2(0.01)),
Dense(16, activation = 'relu', kernel_regularizer=l2(0.01)),
Dense(8, activation = 'relu', kernel_regularizer=l2(0.01)),
Dense(6, activation = 'softmax')])
model.summary()
model.compile(optimizer=Adam(learning_rate=0.003), loss='sparse_categorical_crossentropy')
history = model.fit(x_train, y_train, epochs=20, validation_split=0.2, verbose=0).history
dl_history_plot(history)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
tmp.append(accuracy_score(y_val, pred_arg))
모델을 5번 반복 학습했을 때의 평균 검증 정확도를 확인했다.
모델7: early stopping 조정
early stopping 조정, hl 5
tmp = list()
for i in range(5):
clear_session()
model = Sequential([Input(shape = (nfeatures,)),
Dense(128, activation = 'relu'),
Dense(64, activation = 'relu'),
Dense(32, activation = 'relu'),
Dense(16, activation = 'relu'),
Dense(8, activation = 'relu'),
Dense(6, activation = 'softmax')])
callback = EarlyStopping(monitor='loss', min_delta=0.03, patience=3)
model.summary()
model.compile(optimizer=Adam(learning_rate=0.003), loss='sparse_categorical_crossentropy')
history = model.fit(x_train, y_train, epochs=20, validation_split=0.2, verbose=0, callbacks=[callback]).history
dl_history_plot(history)
pred = model.predict(x_val)
pred_arg = pred.argmax(axis=1)
tmp.append(accuracy_score(y_val, pred_arg))
모델을 5번 반복 학습했을 때의 평균 검증 정확도를 확인했다.
모델8 : functional 이용해서 features 6등분
가장 높은 feature_importances_ 순으로 6등분하여 멀티 input 구성 HL : , learning_rate : 0.003, epochs : 20
from sklearn.ensemble import RandomForestClassifier
def get_feature_importances(x, y, target=target, target_features=target_features):
data = dict()
model = RandomForestClassifier()
model.fit(x, y)
col = x.columns
val = model.feature_importances_
data = {'feature_name': col, 'feature_importances': val}
df_tmp = pd.DataFrame(data)
df_tmp.sort_values(by=['feature_importances'], ascending=False, inplace=True)
df_tmp.reset_index(drop=True, inplace=True)
return df_tmp
모델을 5번 반복 학습했을 때의 평균 검증 정확도를 확인했다.
모델9 : functional 이용해서 상위 features 만
모델을 5번 반복 학습했을 때의 평균 검증 정확도를 확인했다.
성능 비교
모델 8인 functop 이 가장 성능이 높고
모델 9인 top30이 가장 성능이 낮은 것을 알 수 있다.
따라서 functional 이용해서 중요도 features 6등분하여 학습한 모델이 가장 성능이 뛰어남을 알 수 있다.
최종 모델 선정
그럼 여기서 상위 features 그룹의 개수를 늘리면 더 좋은 성능이 나올 수 있지 않을까 해서 여러가지 등분으로 나눠 돌려봤다.
h=561
rfc = plot_feature_importance(rfc_model.feature_importances_, list(x2_train), result_only=True).head(h)
top=[]
rfc_accuracies = []
for i in range(1,h) :
feature_name_top = rfc.feature_name.iloc[i]
top.append(feature_name_top)
rfc_x = data_train.loc[:, top]
rfc_y = data_train.loc[:, target]
scaler = MinMaxScaler()
rfc_x = scaler.fit_transform(rfc_x)
le = LabelEncoder()
rfc_y = le.fit_transform(rfc_y)
rfc_x_train, rfc_x_val, rfc_y_train, rfc_y_val = train_test_split(rfc_x, rfc_y, test_size=0.3, random_state=1)
clear_session()
rfc_model2 = Sequential([Input(shape=(i, )),
Dense(128, activation="relu"),
Dense(64, activation="relu"),
Dense(32, activation="relu"),
Dense(16, activation="relu"),
Dense(6, activation="softmax")])
rfc_model2.compile(optimizer=Adam(learning_rate=0.01), loss = "sparse_categorical_crossentropy")
rfc_model2.fit(rfc_x_train, rfc_y_train, epochs=50, validation_split=0.2, verbose = 0)
rfc_pred2 = rfc_model2.predict(rfc_x_val)
rfc_pred2_1 = rfc_pred2.argmax(axis=1)
rfc_accuracy = accuracy_score(rfc_y_val, rfc_pred2_1)
rfc_accuracies.append({"shape" : i, "model" : "model3", "rfc_accuracy_mean" : rfc_accuracy})
rfc_accuracies
features importance 상위 333개 넣었을 떄 가장 뛰어난 성능이 나오는 것을 확인했다.
따라서, 해당 모델을 최종 선정했다.
[3일차] 모델링 및 파이프 라인 구성
3일차엔 대면으로 분당교육장에서 조원들을 만나 최종 결과물과 발표 ppt를 정리했다.
두단계로 모델 구조를 설계하고 그 모델을 통합하고 파이프라인을 구축했다.
마지막으로 결과물에 대한 비즈니스 인사이트를 제시했다.
단계1 : 정적(0), 동적(1) 행동 분류 모델 생성
정적 모델링 : 상위 333개 사용
동적 모델링 : baseline 사용
아무리 여러 모델링을 돌려봐도 베이스 모델만한 성능이 없어서 최종 모델로 베이스 라인을 선택했다.
단계2 : 모델 통합 및 결과 예측
- 두 단계 모델을 통합하고, 새로운 데이터(test)에 대해서 최종 예측결과와 성능평가가 나오도록 함수로 만들기
- 데이터 파이프라인 구축 : test데이터가 로딩되어 전처리 과정을 거치고, 예측 및 성능 평가 수행
최종예측 결과는 위와 같다.
0.98로 성능이 뛰어남을 알 수 있다.
비즈니스 인사이트 및 서비스 제안
사용자가 침대에 누우면 스마트폰의 센서로 인식하고 사용자의 자세를 예측한다.
그 예측값으로 사용자가 누웠다고 인식이 되면 유튜브 알고리즘과 연동이되어 수명 개선을 위한 동영상을 제공한다.
'대외활동 > 에이블스쿨' 카테고리의 다른 글
[에이블 스쿨] 5차 미니프로젝트 | ASSO 대비 (1) | 2024.11.26 |
---|---|
[에이블 스쿨] 4차 미니프로젝트 | 이미지데이터모델링-얼굴인식(Face Recognition) (2) | 2024.11.25 |
[에이블 스쿨] KES 2024, 한국 전자전 후기 | 스터디 활동 (2) | 2024.10.29 |
[에이블 스쿨] 1차 코딩마스터스 | 기록 방법, 꿀팁 (2) | 2024.10.11 |
[에이블스쿨] 2차 미니프로젝트 | 분당교육장 방문 후기 (3) | 2024.10.11 |