우선 핸드폰 카메라를 사용하여 비전 인식을 하였습니다. 카메라를 통해 들어온 데이터를 컴퓨터를 통해 제어기인 opencr로 전달하였습니다. 그리고 opencr을 이용해 그리퍼에 사용된 모터들을 각 모드에 맞게 구동하였습니다. 이 상태에 대해 피드백을 지속적으로 진행하여 카메라에 잡힌 물체가 바뀌면 그 형상에 맞게 그리퍼의 모션을 바뀌게 하였습니다.
오브젝트
1) Data Augmentation
원본 데이터 약 600장 -> 약 1550장
Augmentations
90° Rotate: Clockwise, Counter-Clockwise, Upside Down
Crop: 0% Minimum Zoom, 17% Maximum Zoom
Rotation: Between -45° and +45°
Brightness: Between -25% and +25%
Exposure: Between -25% and +25%
영상인식으로 3가지 형상 구체, 원기둥, 직사각형 오브젝트를 분류하기 위하여 데이터를 수집하였습니다. 사진 혹은 영상촬영을 통해 각 오브젝트에 대한 이미지 데이터 약 600장을 수집하였습니다. 3개의 오브젝트마다 균형있게200장씩을 수집하였고, 각 클래스를 직사각형 모양으로 라벨링하였습니다. 모델이 과적합을 피하고 좀 더 학습을 잘 하기 위하여 원본 데이터를 어그멘테이션을 하였고, 회전, 크랍, 밝기, 노출에 각각 랜덤한 값을 넣어줍니다.
2) Yolo V5 custom training
사람은 이미지를 보면 어디에 무엇이 있는지를 한 번에 파악할 수 있습니다. 그래서 운전을 하면서도 빠르게 지나가는 바깥 환경을 빠르고 정확하게 인식할 수 있습니다. Yolo는 는 You only look Once의 약자로 현재까지 사람의 시각 체계와 가장 가까운 객체 탐지 모델입니다. Yolo V5는 단일 신경망 구조이기 때문에 계산 속도가 무척 빨라 실시간으로 사용할 수 있습니다. Yolo 모델을 앞서 전처리한 이미지데이터로 전이학습 시킵니다. 전이학습이란,이미 훈련된 딥러닝 모델에 파인 튜닝을 적용하여 적은 데이터로도 좋은 결과값을 얻을 수 있도록 하는 기술입니다.
3) YOLO 학습 결과
Yolo 모델이 잘 학습했는지를 나타내주는 지표인 정확도와 재현율은 0.95, 1로 우수한 성능을 갖추었습니다. 정확도란, 모델이 객체라고 예측했던 모든 bounding box들 중에 실제 정답이 있는 확률이고, 재현율이란, 실제 정답 중 모델이 정답을 맞춘 확률입니다. 즉, 두 개의 지표가 모두 우수해야 훌륭한 모델이라 할 수 있습니다.Yolo 모델에 영상을 실시간으로 넣게 되면 출력값으로 객체의 위치를 예측하는 bounding box가 생성됩니다. 프레임 내에 cube, circle, 혹은 cylinder 객체를 예측하게 된다면 분류된 값을 시리얼 통신을 통해 OPENCR 제어기에 송신합니다.
# 데이터 처리 라이브러리
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
%matplotlib inline # notebook을 실행한 브라우저에서 바로 그림을 볼 수 있게 해줌.
plt.style.use('seaborn') # 'seaborn' 폰트로 변경
sns.set(font_scale=2.5) # 폰트 크기 설정
# 경고 창 생략
import warnings
warnings.filterwarnings('ignore')
seaborn은 matplotlib을 기반으로 다양한 색상 테마와 통계용 차트 등의 기능을 추가한 시각화 패키지입니다.
데이터를 불러올 때 pandas를 사용합니다. pandas는 데이터를 처리하는 강력한 도구입니다. csv 파일의 가장 위에 있는 인덱스를 columns로 지정합니다.
head
df_train.head(5)
head 함수는 pandas로 불러온 데이터를 위에서부터 숫자만큼 순서대로 불러옵니다.
describe
df_train.describe()
describe 함수는 데이터 통계 분석 도구입니다. 개수, 평균, 표준편차, 최소값 등을 표로 멋지게 표현해줍니다.
3. 데이터 대략적 분석하기
①결측값 파악하기
df_train
for col in df_train.columns:
print('{:>10}\t Percentage of NaN value: {:.2f}'.format(col, 100*(df_train[col].isnull().sum() / len(df_train[col].shape[0]))))
df_train에는 12개의 columns가 들어있습니다. 이 중 Age, Cabin, Embarked 3가지엔 결측값이 존재하므로 이를 다른 값으로 채워주거나, feature를 사용하지 않는 방법 중 하나를 택해야 합니다. 이 때, Cabin은 결측값의 비율이 77프로에 육박하므로 사용하지 않는 편이 낫겠습니다.
df_test
for col in df_test.columns:
print('{:>10}\t Percentage of NaN value: {.2f}'.format(col, df_test[col].isnull().sum() / len(df_test[col].shape[0])))
df_test는 Age, Fare, Cabin 3가지에 관하여 결측값이 존재하고 df_train과 달리 Fare에 결측값이 존재합니다. 마찬가지로 Cabin의 결측값 비율은 높으므로 사용하지 않습니다.
생존률을 구한 다음 생존률이 높은 순(ascending=False)대로 히스토그램을 그렸습니다. 티켓 등급이 높을수록 생존률이 높습니다. 돈이 많은 사람이 생존할 확률이 높다는 것을 알 수 있습니다. 역시.. 재력이..
y_position = 1.02
f, ax = plt.subplots(1,2,figsize=(18,8))
df_train['Pclass'].value_counts().plot.bar(color=['#CD7F32','#FFDF00','#D3D3D3'],ax=ax[0]])
ax[0].set_title('Number of passengers By Pclass', y = y_position)
ax[0].set_title('Count')
sns.countplot('Pclass', hue='Survived',data=df_train, ax=ax[1])
ax[1].set_title('Pclass: Survived vs Dead', y = y_position)
plt.show()
matplotlib.pyplot의 subplots 함수는 그래프를 그릴 개수와 그래프의 크기를 설정합니다. 첫번째 ax[0] 위치에는 티켓 등급별로 인원수를 히스토그램으로 나타내고, 두번째 ax[1] 위치에는 seaborn의 countplot 함수를 사용하여 티켓 등급별로 사망자와 생존자를 나타내도록 했습니다. 그래프의 set_title 함수를 사용하여 각 그래프의 제목을 나타내줍니다.
② Sex
f, ax = plt.subplots(1,2,figsize=(18,8))
df_train[['Sex','Survived']].groupby(['Sex'],as_index=True).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot('Sex', hue='Survived', data=df_train,ax=ax[1])
ax[1].set_title('Sex: Survived vs Dead')
plt.show()
factorplot은 x, y 축에 두가지의 값을 받고, hue에 있는 데이터를 분류하여 그래프로 표현합니다.
③ Age
연령 분석
print('제일 나이 많은 탑승객: {:.1f}'.format(df_train['Age'].max())
print('제일 나이 어린 탑승객: {:.1f}'.format(df_train['Age'].min())
print('탑승객 평균 나이 : {.1f}'.format(df_train['Age'].mean())
seaborn의 kdeplot은 커널밀도함수로 데이터에 맞게 그래프를 fitting 해주는 함수입니다. Age가 0 이하로는 실제 데이터가 없지만 그래프를 fitting 한 결과로 저렇게 그려집니다. 히스토그램으로 그릴 경우 비교할 대상이 겹치면 보이지 않는 현상이 나타나지만, kdeplot은 여러개를 비교할 수 있습니다.
plt.subplots(1,1,figsize=(8,6))
df_train[df_train['Pclass']==1]['Age'].plot(kind='kde')
df_train[df_train['Pclass']==2]['Age'].plot(kind='kde')
df_train[df_train['Pclass']==3]['Age'].plot(kind='kde')
plt.legend(['1st Class','2nd Class','3rd Class'])
plt.title('Age Distribution within classes')
plt.xlabel('Age')
plt.show()
plt.figure(figsize=(8,6))
aging_survived_ratio=[]
for i in range(80):
aging_survived_ratio.append(df_train[(df_train['Age'] <= i)]['Survived'].sum() / len(df_train[df_train['Age']<=i]['Survived'])
plt.plot(aging_survived_ratio)
plt.title('Survival ratio change depending on range of Age')
plt.xlabel('Age 0~x')
plt.show()
해당 나이까지의 생존률을 나타낸 그래프를 보면 나이가 영유아는 생존률이 높은 것을 알 수 있습니다. 나이가 들수록 생존률이 줄어듭니다.
Pclass, Sex, Age
f, ax = plt.subplots(1,2,figsize=(18,8))
sns.violinplot('Pclass','Age',hue='Survived', data=df_train, scale='count', split=True, ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))
sns.violinplot('Sex', 'Age', hue='Survived',data=df_train,scale='count',split=True, ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.show()
violinplot은 그래프의 형태가 바이올린을 닮았다고 해서 붙여진 이름입니다. violinplot을 통해 티켓등급이 높고 나이가 어리며, 여성이라면 살아남을 확률이 더 높은 것을 한 눈에 확인할 수 있습니다.
가족 인원수가 생존률에 미치는 영향을 나타낸 그래프입니다. 이 때, set_title 함수의 y는 title의 위치를 지정해줍니다. default는 1입니다.
⑥ Fare
fig, ax = plt.subplots(1,1,figsize=(8,8))
g = sns.distplot(df_train['Fare'], color='b', label='skewness: {:.2f}'.format(df_train['Fare'].skew()),ax=ax)
g = g.legend(loc='best')
fare 은 데이터가 한쪽으로 치우쳐진 모습을 볼 수 있습니다. 이를 객관적으로 나타내는 지표가 skewness, 왜도입니다. 왜도는 실수 값 확률 변수의 확률 분포 비대칭성을 나타내는 지표입니다. 왜도 값이 클수록 데이터가 치우쳐 있는 것을 확인할 수 있습니다. 이를 고르게 퍼뜨리기 위해서 log 함수를 취합니다.
df_train['Fare'] = df_train['Fare'].map(lambda i: np.log(i) if i>0 else 0)
df_test['Fare'] = df_test['Fare'].map(lambda i: np.log(i) if i>0 else 0)
fig, ax = plt.subplots(1,1,figsize=(8,8))
g = sns.distplot(df_train['Fare'], color ='b', label='Skewness: {:.2f}'.format(df_train['Fare'].skew()),ax=ax)
g = g.legend(loc='best')
아까와 다르게 skewness 가 0에 가까워졌고, 데이터가 조금 더 고르게 퍼져 있는 모습을 볼 수 있습니다.
⑦ Ticket
티켓 이름은 데이터로 처리하기 까다롭고, 티켓 이름 간에 그렇게 큰 연관성이 보이지 않기 때문에 모델이 학습할 데이터에서 제외하도록 하겠습니다.
정규 표현식을 사용하여 이름에서 영어 호칭만을 추출해냅니다. [A-Za-z]는 모든 알파벳을 의미하고, '+'는 앞에 있는 것이 1번 이상 반복되는 것을 의미합니다. 따라서, '.'으로 끝나는 알파벳 단어를 추출해내면 우리가 원하는 영어 호칭만을 추출할 수 있습니다. 이를 새로운 column인 Initial을 만들어 저장합니다.
영어 호칭과 도착할 항구는 숫자 값으로 맵핑할 때 연속된 수의 개념보다는 분류의 개념이 더 크기 때문에 원핫 인코딩 기법을 사용하여 데이터를 표현해줍니다. 그리고 필요없는 데이터 column은 삭제하여줍니다. 이로써 데이터 전처리가 완료되었습니다. 간단히 모델을 설계하여 생존자를 예측해보도록 합니다.
7. 모델 설계하기
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics
from sklearn.model_selection import train_test_split
X_train = df_train.drop(['Survived'],axis=1)
target_label = df_train['Survived'].values
X_test = df_test.values
x_tr, x_vld, y_tr, y_vld = train_test_split(X_train, target_label, test_size=0.3, random_state=2018)
model = RandomForestClassifier()
model.fit(X_tr, y_tr)