728x90
반응형

OpenCV ML

import cv2
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

data = load_iris()

X_train, X_test, y_train, y_test = train_test_split(data.data ,data.target)

# 편미분을 위한 데이터 타입 변환 
X_train = X_train.astype('float32')
y_train = y_train.astype('float32')
X_test = X_test.astype('float32')
y_test = y_test.astype('float32')

X_train.shape
# (112, 4)

knn = cv2.ml.KNearest_create()
knn.train(X_train,cv2.ml.ROW_SAMPLE, y_train) # transpose되어 있는 데이터를 transpose하면 연산에 비효율적이기 때문에 내부적으로 최적화 계산을 해준다 
# True

cv2.ml.ROW_SAMPLE
# 0

y_test.shape
# (38,)

knn.predict(X_test)[1].reshape(38) == y_test
# array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
#        True,  True,  True, False,  True,  True,  True,  True,  True,
#        True, False,  True,  True,  True,  True,  True,  True,  True,
#        True,  True,  True,  True,  True,  True,  True,  True,  True,
#        True,  True])

Assumption

가정이 많아지면 많아질 수록 가정을 만족하는 데이터에 대해서는 성능이 좋아지지만, 일반성은 떨어진다

즉, 잘 정제된 데이터를 학습해서 좋은 데이터에서는 성능이 좋지만, 정제되지 않은 현실 데이터에 적용하기에는 좋지 않은 모델이 만들어질 수 있다

 

import tensorflow as tf 
import matplotlib.pyplot as plt

(X_train,y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()

plt.imshow(X_train[0], cmap='gray') # 패턴이 뚜렷하게, 크기를 일치하는 가정을 둔 사례

대체적으로 성능 좋은 알고리즘 (대세)

1980 - 1990 ANN

1990 - 2000 SVM

2000 - 2010 Ensemble (Random Forest)

               - Structured data => Boosting

               - XGBoosting, LightGBM

               - ETC (Deep Learning)

데이터가 작을 때에는 SVM부터 사용하는 것이 좋다

왜냐하면 Ensemble, Boosting, Deep Learning은 데이터가 많을 때라는 가정이 있어야 성능이 좋기 때문이다

Neural Network

Neural network는 뉴런에서 영감을 얻어 데이터를 통해 스스로 학습이 가능하도록 설계된 알고리즘, 네트워크 또는 모델이라고 한다

모델의 구조를 먼저 정하고

그 구조에 있는 파라미터를 찾는 모델 방식을 가진다

 

구조도 학습을 통해서 알아낼 수 있다 (NAS/Neural Architecture Search)

Hypothesis

가설은 어떤 현상을 해결하기 위한 함수이고 사실과 비슷하다고 믿는 함수이다

Model

머신러닝에서는 가설 = 모델이다

정의 자체에서 모델은 항상 틀릴 수 있다

모델은 시스템 관점에서 머신러닝 알고리즘을 사용해서 데이터로 학습시킨 것을 머신러닝 모델이라고 한다

※ scikit-learn에서 학습 안된 알고리즘을 estimator라고 한다

모델의 4가지 관점

1. 수학적으로 표현할 수 있어야 한다

2. 그림 또는 그래프로 표현할 수 있어야 한다

3. 통계치를 통해서 표현할 수 있어햐 한다

4. 코드를 통해서 표현할 수 있어야 한다

모델 분류 기준들

1. Linear vs Nonlinear

- Linear는 aX+b에서 a와 b를 찾는데 집중한다

- Nonlinear는 회귀식이 비선형 함수로 나타내는 경우를 말한다

2. Generative vs Discriminative

- Generative는 입력값과 결과값이 주어질때, 일정한 분포 규칙속에 존재한다는 가정을 하는 모델

- Discriminative는 입력 데이터가 있을 때 label data를 구별해내는 모델

3. Black box vs Descriptive

- Black box는 설명 불가능

- Descriptive는 설명 가능

4. First-principle vs Data-driven

- First-principle은 원리, 규칙에 기반한 모델인가

- Data-driven은 데이터에 기반한 모델인가

5. Stochastic vs Deterministic

- Stochastic는 확률론적인 방법

- Deterministic 결정론적인 방법

6. Flat vs Hierarchical

7. Parametric vs Non-parametric

- Parametric는 고정된 개수의 파라미터들을 학습하여 튜닝하는 것

- Non-parametric는 학습해서 튜닝할 파라미터가 명시적으로 존재하지 않거나 정확히 셀 수 없는 경우

Data modeling vs Algorithmic Modeling

Data modeling

- 데이터를 바탕으로 파라미터를 찾는 것에 집중하는 모델

- 데이터를 해당 모델에 얼마나 잘 적합시키는 가에 초점이 있다

- 모델 자체를 가정하기 때문에 모델이 잘 못될 경우 잘 못된 결과를 도출 할 수 있다

 

Algorithmic modeling

- 알고리즘을 모르는 상태에서 데이터를 통해 모델을 새로 만드는 방법

Perceptron

뉴런을 모방한 알고리즘 또는 모델

Perceptron과 linear model의 차이점은 선형 함수의 기울기와 bias를 찾는 방법이 다르다

perceptron은 delta rule에 의해서 학습을 한다

delta rule은 기대값과 실제값의 차이를 줄여 나가는 방식으로 싱글 레이어 퍼셉트론에서 인공 뉴런들의 연결 강도를 갱신하는데 쓰인다

 

from sklearn.linear_model import Perceptron
per = Perceptron() # linear model 
per.fit(X_train, y_train)
# Perceptron(alpha=0.0001, class_weight=None, early_stopping=False, eta0=1.0,
#           fit_intercept=True, max_iter=1000, n_iter_no_change=5, n_jobs=None,
#           penalty=None, random_state=0, shuffle=True, tol=0.001,
#           validation_fraction=0.1, verbose=0, warm_start=False)

per.score(X_test, y_test)
# 0.8947368421052632

MLP(Multi Layer Perceptron)

MLP는 perceptron를 쌓기 위해서 Layer 개념을 도입하고 여러 layer를 연결한 형태를 말한다

neural network는 기본적으로 fully connected여야 한다

Memorization Capacity

Layer가 많으면 많을 수록 성능이 좋아진다

그러나 ML에서 feature처럼 layer가 많으면 많을 수록 데이터가 많이 필요하다

 

전통적인 머신러닝 알고리즘에서는 데이터가 아무리 많아도 더 이상 성능이 올라가지 않는 plateau라는 현상이 생긴다

Universal Approximation Theorem

이론적으로 activation 함수가 비선형 일때 레이어가 많으면 어떠한 형태의 함수도 만들어 낼 수 있다

따라서 어떠한 데이터 셋도 분류 할 수 있다

 

단, activation function을 sigmoid나 tanh같은 함수를 사용하면 gradient vanishing현상이 생긴다

layer를 함수라고 본다면 neural network는 composition function이다

Feature cross

두 개 이상의 feature를 연산해서 새로운 feature형태로 만들어 주는 기법

Gradient vanishing

Gradient vanishing은 Back-propagation(편미분 연산)을 할 때마다 gradient가 전달이 되야하는데

sigmoid나 tanh와 같은 activation을 사용하는 네트워크에서 깊이가 깊어지면 값이 0이 되어 학습이 안되는 현상을 말한다

 

Dying Relu

Dying relu는 모든 0이하의 입력에 대해서 미분 값이 0이 되어 가중치에 곱해지면서 해당 노드가 통째로 죽어버리는 현상을 말한다

Optimization

실제값 - 예측값을 함수로 일반화 시키고 가능한 (실제값 - 예측값)을 가장 작게 만드는 과정을 최적화한다

최소값 찾는 문제는 미분하는 방법과 미분을 쓰지 않는 방법 두 가지로 나뉘어 해결 할 수 있다

Fully connected된 layer는 array연산으로 바꿀 수 있다

따라서 Neural Network는 vectorization이 최적화된 연산을 지원한다

Back propagation

수치 미분을 통해 최적화 하는 과정

foward propagation이 결과를 prediction하는 과정이라면

back propagation은 반대로 prediction된 결과와 실제 값의 오차를 계산하여 가중치를 업데이트하는 것을 말한다

Epoch

Back-propagation을 하는 과정에서 가중치가 업데이트 되었기 때문에 앞서 학습에 사용되었던 데이터는 가중치 업데이트에 영향을 거의 미치지 않게 되어 의미를 잃어버린다

따라서 전에 학습했던 데이터를 재활용 함으로써 전체 데이터가 가중치를 업데이트하는데에 기여를 할 수 있도록 여러번 학습 시킨다

단, Epoch을 많이 하면 할 수록 overfitting이 발생할 수 있다

ex) 2 Epoch => 전체 데이터를 두 번 학습 시킨다

Regularization

모델에 제약(penalty)을 줌으로써 overfitting을 방지하고 일반화 시키는 방법

from sklearn.linear_model import Ridge, Lasso, ElasticNet, Perceptron

Lasso => L1을 추가한다

Ridge => L2를 추가한다

ElasticNeet => L1, L2를 추가한다

Learning Rate

Gradient decent를 할 때 어느 정도의 보폭으로 최소값에 도달할 것인가를 지정하는 파라미터 => 학습률

학습률이 클때는 속도가 빠른 대신 local minimum에 영원히 도달하지 못할 가능성이 있는 반면

학습률이 작을때는 local minimum에는 도달할 수 있겠지만 속도가 매우느린 단점을 갖는다

따라서 적당한 학습률을 선택하는 것이 중요하다

 

 

 

 

반응형
728x90
반응형

Image data

이미지 데이터를 다룰 때는 주의 해야 것들이 있다

1. 이미지 데이터의 크기가 재각각이다

2. 이미지 데이터를 머신러닝 데이터로 사용하기 위해서는 array data로 바꿔야한다

3. 이미지 데이터를 파일로 갖고 있을 경우 tensorflow에서는 tf.io.read_file('') 불러온다

4. 불러온 이미지 파일 type 따라서 decoder를 달리해야 한다

5. png 파일은 투명도를 지원한다. 따라서 같은 크기더라도 채널 정보가 4차원이 된다

이미지가 크기가 다를때 세 가지 해결 방식

1. resize

- resize를 통해 크기를 통일시킨다

- , resize를 하게 되면 데이터의 의미가 유지되지 않는다(이미지 왜곡이 발생한다)

2. crop

- 내가 생각한 이미지가 생각보다 사용한다

- 데이터를 일일이 crop 해야하는 단점이 있다

3. padding

- 내가 생각한 이미지가 생각보다 작을 사용한다

# sppnet, r-cnn에서 resize관련 이슈를 해결한 방식을 배울 것이다

이미지 데이터의 크기가 크면 클수록 좋을까?

# 가정: cpu, gpu의 성능은 최고라고 가정한다 => 데이터가 많으면 많을 수록 좋다

데이터가 많다는 것은 2차원 데이터에서 row가 늘어나는 것이다

row가 많으면 처리할 연산량이 많아지기 때문에 처리속도가 떨어진다

하지만 하드웨어 성능관점에서 벗어나면 데이터의 row가 많으면 많을 수록 좋다

 

그렇다면 column(feature/dimension)은 크면 클 수록 좋을까? => column은 i.i.d 가정을 갖고 있다

예를 들어 꽃을 설명 할 때 꽃 잎 정보만 주어 졌을 때 정확하게 학습할까 아니면 꽃 잎 정보, 꽃 줄기 정보, 꽃의 씨앗 정보가 주어졌을 때 더 정확하게 학습할까?

당연 더 많은 종류의 정보가 주어졌을 때 학습을 잘 할 수 있다 => 더 많은 nuance를 갖기 때문에 feature가 많은 것은 유리할 수 있다

하지만, 차원이 증가하면 증가할 수록 차원의 저주가 발생한다

즉, 차원이 증가함에 따라 필요한 데이터는 기하 급수적으로 늘어난다

 

데이터에 따라, 모델에 따라, feature 갯수에 따라 데이터가 작으면 overfitting이 발생할 수 있다

예를 들어 사람을 인식하는 모델이 있다고 가정했을 때 눈, 코, 입 정보만 주어진 데이터로 학습을 할 경우

사람의 눈, 코, 입이 포함되어 있는 데이터의 경우는 정확하게 인식할 수 있지만

눈, 코, 입과 더불어 사람의 몸 전체가 주어진 데이터에 대해서는 사람이라고 인식을 하지 못하게 될 수도 있다.

뿐만 아니라 사람을 인식하는 모델을 학습할 때 사람 몸 전체에 대한 정보가 주어진 데이터를 학습하는데

데이터에 대한 feature갯수 보다 데이터의 갯수가 적을 경우 학습된 사람 데이터에 대해서만

정확하게 인식하고 조금이라도 다르게 생긴 사람 데이터 정보가 들어 왔을 때 정확히 인식하지 못할 가능성이 발생 할 수 있다

Feature selection

유의미한 feature만 추려서 사용한다

1. Filter (Statistics)

- 통계 값을 활용하여 클래스와 가장 밀접한 feature를 택한다

- 상관성 분석을 통해 구분한다

2. Wrapper

- Algorithm + feature를 활용하여 최적의 feature를 택한다

3. Embeded

- Algorithm으로 자체만으로 feature의 중요도를 알려준다

- Feature 기반의 분류를 있는 것에만 사용할 있다

 

Feature selection은 한계가 있다

이미지 데이터는 i.i.d가 아니기 때문에 feature간의 독립성이 약해서 feature selection을 사용할 없다

 

import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url, 
                                   fname='flower_photos', 
                                   untar=True)

data_dir = pathlib.Path(data_dir)

image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)

Filter

import seaborn as sns
from sklearn.feature_selection import SelectKBest, chi2 # 카이제곱 검정: 관찰된 빈도가 기대되는 빈도와 의미있게 다른지의 여부를 검정하기 위해 사용되는 검정방법이다
iris = sns.load_dataset('iris')
skb = SelectKBest(chi2, k=3) # 클래스와 연관성이 가장 큰 3가지 feature를 고른다 
skb.fit_transform(iris.iloc[:,:-1], iris.species)
skb.fit_transform(iris.iloc[:,:-1], iris.species)[:5]
array([[5.1, 1.4, 0.2],
       [4.9, 1.4, 0.2],
       [4.7, 1.3, 0.2],
       [4.6, 1.5, 0.2],
       [5. , 1.4, 0.2]])
iris.iloc[:5] # sepal_length, petal_length, petal_width 3가지 feature가 선택되었다 

sepal_length	sepal_width	petal_length	petal_width	species
0	5.1	3.5	1.4	0.2	setosa
1	4.9	3.0	1.4	0.2	setosa
2	4.7	3.2	1.3	0.2	setosa
3	4.6	3.1	1.5	0.2	setosa
4	5.0	3.6	1.4	0.2	setosa
vars(skb)
{'k': 3,
 'pvalues_': array([4.47651499e-03, 1.56395980e-01, 5.53397228e-26, 2.75824965e-15]),
 'score_func': <function sklearn.feature_selection._univariate_selection.chi2>,
 'scores_': array([ 10.81782088,   3.7107283 , 116.31261309,  67.0483602 ])}
skb.get_params()
#
{'k': 3,
 'score_func': <function sklearn.feature_selection._univariate_selection.chi2>}
iris.corr() # petal_length, petal_width 두 가지 feature가 서로 연관되어 있기 때문에 둘 중 하나를 택한다 
	sepal_length	sepal_width	petal_length	petal_width
sepal_length	1.000000	-0.117570	0.871754	0.817941
sepal_width	-0.117570	1.000000	-0.428440	-0.366126
petal_length	0.871754	-0.428440	1.000000	0.962865
petal_width	0.817941	-0.366126	0.962865	1.000000

Wrapper

알고리즘과 데이터의 feature에 따른 경우의 수를 고려하여 계산하는 방식

from sklearn.feature_selection import RFE # Recursive feature extraction 
from sklearn.linear_model import LogisticRegression

rfe = RFE(LogisticRegression(), n_features_to_select=2) # 4개 중에 2개 선택 (iris feature가 4개 이기 때문에)
rfe.fit_transform(iris.iloc[:,:-1], iris.species) # fit_transform
vars(rfe)
#
{'estimator': LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                    intercept_scaling=1, l1_ratio=None, max_iter=100,
                    multi_class='auto', n_jobs=None, penalty='l2',
                    random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                    warm_start=False),
 'estimator_': LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                    intercept_scaling=1, l1_ratio=None, max_iter=100,
                    multi_class='auto', n_jobs=None, penalty='l2',
                    random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                    warm_start=False),
 'n_features_': 2,
 'n_features_to_select': 2,
 'ranking_': array([3, 2, 1, 1]),
 'step': 1,
 'support_': array([False, False,  True,  True]),
 'verbose': 0}
iris.columns[:-1][rfe.support_] 

# Index(['petal_length', 'petal_width'], dtype='object')

Embeded

from sklearn.tree import DecisionTreeClassifier # 분기를 시켜 feature의 중요도를 나타낸다 
from sklearn.ensemble import RandomForestClassifier

dt = DecisionTreeClassifier()
dt.fit(iris.iloc[:,:-1], iris.species)

dt.feature_importances_ # feature의 중요도를 알려준다 
# array([0.01333333, 0.        , 0.56405596, 0.42261071])
iris.iloc[:,:-1].columns
# Index(['sepal_length', 'sepal_width', 'petal_length', 'petal_width'], dtype='object')
rf = RandomForestClassifier()
rf.fit(iris.iloc[:,:-1], iris.species)

rf.feature_importances_
# array([0.10738656, 0.02592046, 0.41244991, 0.45424308])

Dimension Reduction

차원 축소

nuance 손실도 발생하고 원본 데이터를 손상시킨다는 단점이 있다

 

from sklearn.decomposition import PCA
pca = PCA(2) # 2차원으로 줄인다 
pca.fit_transform(iris.iloc[:,:-1], iris.species) # 4차원 -> 2차원 / 공간이 왜곡 되었다 
# array([[-2.68412563,  0.31939725],
       [-2.71414169, -0.17700123],
       [-2.88899057, -0.14494943],
       [-2.74534286, -0.31829898],

Feature selection vs Dimension reduction

Feature selection은 데이터 값을 그대로 유지하면서 feature를 축소 했지만,

Dimension reduction은 데이터 값을 변형하면서 차원을 축소 한다 => 공간을 왜곡시킨다

!pip install mglearn
import mglearn
mglearn.plot_pca.plot_pca_illustration() # 차원이 축소 되어도 의미를 잃지 않았다 / 고차원의 특성이 저차원에서도 유지가 되었다 / manifold

Manifold

고차원의 데이터를 공간상에 표현하면 각 데이터들은 점의 형태로 찍혀지는데,

이러한 점들을 잘 아우르는 subspace를 manifold라고 한다

 

Path

import cv2
import os # 운영체제별로 결과가 상이할 수 있다 
from pathlib import Path # 운영체제 별로 상이하지 않게 범용적으로 사용 가능 

os.listdir('flower_photos/daisy')[:10]
['7410356270_9dff4d0e2e_n.jpg',
 '7568630428_8cf0fc16ff_n.jpg',
 '10770585085_4742b9dac3_n.jpg',
 '4286053334_a75541f20b_m.jpg',
 '8759177308_951790e00d_m.jpg',
 '4131565290_0585c4dd5a_n.jpg',
 '8710109684_e2c5ef6aeb_n.jpg',
 '3504430338_77d6a7fab4_n.jpg',
 '2612704455_efce1c2144_m.jpg',
 '8021540573_c56cf9070d_n.jpg']
path = 'flower_photos/daisy'
images = [cv2.imread(os.path.join(path,i)) for i in os.listdir(path)] # os.listdir : 특정 디렉토리를 리스트로 만들어 준다 

!pwd
# /content/drive/My Drive/Colab Notebooks/고급시각반 정리/flower_photos
path = Path('flower_photos/daisy') # path 객체로 불러온다 
images = [cv2.imread(str(i)) for i in path.iterdir()]

len(images)
# 633

Pattern

path 객체는 pattern을 사용할 수 있다

import glob # 패턴을 활용할 수 있는 패키지 
image = [cv2.imread(i) for i in glob.glob('flower_photos/daisy/*.jpg')] # glob 모듈의 glob 함수는 사용자가 제시한 조건에 맞는 파일명을 리스트 형식으로 반환한다.
len(image)
# 633
import imageio
imageio.volread(path) # s mode를 알아야 한다?

path = 'flower_photos/daisy'
imageio.mimread(path, format='jpg') # multiple image를 불러들일 수 있다. 단, jpeg는 multi-image 불러들일 수 없다 
# RuntimeError: Format JPEG-PIL cannot read in mode 'I'
from skimage.io import imread_collection
imc = imread_collection('flower_photos/daisy/*.jpg')  # 패턴을 정확히 이해해야 한다 

imc.files[:10]
['flower_photos/daisy/5547758_eea9edfd54_n.jpg',
 'flower_photos/daisy/5673551_01d1ea993e_n.jpg',
 'flower_photos/daisy/5673728_71b8cb57eb.jpg',
 'flower_photos/daisy/5794835_d15905c7c8_n.jpg',
 'flower_photos/daisy/5794839_200acd910c_n.jpg',
 'flower_photos/daisy/11642632_1e7627a2cc.jpg',
 'flower_photos/daisy/15207766_fc2f1d692c_n.jpg',
 'flower_photos/daisy/21652746_cc379e0eea_m.jpg',
 'flower_photos/daisy/25360380_1a881a5648.jpg',
 'flower_photos/daisy/43474673_7bb4465a86.jpg']
w = os.walk('flower_photos/daisy')
for _, _, files in os.walk('flower_photos/daisy'):
  for i in range(10):
    print(files[i])
    
7410356270_9dff4d0e2e_n.jpg
7568630428_8cf0fc16ff_n.jpg
10770585085_4742b9dac3_n.jpg
4286053334_a75541f20b_m.jpg
8759177308_951790e00d_m.jpg
4131565290_0585c4dd5a_n.jpg
8710109684_e2c5ef6aeb_n.jpg
3504430338_77d6a7fab4_n.jpg
2612704455_efce1c2144_m.jpg
8021540573_c56cf9070d_n.jpg
import tensorflow as tf 
img = tf.keras.preprocessing.image_dataset_from_directory('flower_photos/')
# Found 3670 files belonging to 5 classes.

type(img)
# tensorflow.python.data.ops.dataset_ops.BatchDataset

for i in img:
  print(i[0].numpy()) # float형태로 한꺼번에 불러온다 단, 범용적으로 사용하지 못하는 단점이 있다

전처리의 중요성

전처리는 정답이 없다

import tensorflow as tf 
import matplotlib.pyplot as plt

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
# (X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()

정 중앙에 있는 숫자 + 비틀림이 없는 숫자 + 크기가 일정

- 이러한 가정이 있기 때문에 성능이 좋았다, 가정을 한 데이터에 대해서는 대표성을 잘 지닌다

- 그러다 다양한 상황의 일반적인 데이터에는 성능이 좋지 못할 수도 있다

ex) A라는 사람의 필체를 학습한 a모델이 있다고 했을 때 A라는 사람의 글씨는 정확히 인식할 수 있지만 다른 사람의 필체는 정확하게 인식하지 못할 가능성이 높다

plt.imshow(X_train[0]) # 정 중앙에 있는 숫자 + 비틀림이 없는 숫자 + 크기가 일정 (전처리를 통해서 새로운 데이터 분포를 만든 것) => 이러한 가정이 있기 때문에 성능이 좋았다, 가정을 한 데이터에 대해서는 대표성을 잘 지닌다

plt.imshow(X_train[0]) # 3차원 데이터 이기 때문에 전통적인 머신러닝에 사용할 수 없다

plt.imshow(X_train[0], cmap='gray')

X_train[0].shape
# (32, 32, 3)

X_train[0].flatten() # 1차원으로 변경, copy방식 => 원본하고 같이 바뀌고 싶지 않을 때
# array([ 59,  62,  63, ..., 123,  92,  72], dtype=uint8)

X_train[0].ravel()   # 1차원으로 변경, view방식 => 원본하고 같이 바뀌고 싶을 때 
# array([ 59,  62,  63, ..., 123,  92,  72], dtype=uint8)

color 이미지 일 때 (32, 32, 3) 이미지는 머신러닝 관점에서 차원은 3072(32X32X3)이다

따라서 차원의 저주 문제가 발생한다

 

gray로 바꿈으로써 차원을 축소할 수도 있다 => color를 gray로 바꿀 때 단순히 평균해서 바꾸기도 한다 => np.mean(X_train[0], axis=2)

from skimage.color import rgb2gray
X_train[0].size, rgb2gray(X_train[0]).size # nuance
(3072, 1024)
Raw data Featured Data
원본데이터 전처리된 데이터
의미 손실이 없는 대신 패턴을 찾기 어렵다 일부 의미가 손실되지만 패턴을 찾기 좋다
차원의 저주가 발생할 수 있다 차원의 축소가 된다
연산량이 많이 요구된다 연산량이 많이 줄어든다
저장 공간이 많이 요구된다 저장 공간이 많이 줄어든다

이미지 변화 적용(Filter)

Filter도 전처리 방법중 하나 이다 어떻게, 어떤 Filter를 적용하는 것이 맞는지 정확히 알 수 없다

Image augmentation

원본 이미지의 의미를 유지시키면서 변형 하고 새로운 데이터 셋으로 사용 한다

 

from sklearn.datasets import load_digits
data = load_digits()
data.images.shape
# (1797, 8, 8)

plt.imshow(data.images[2], cmap='gray')

data.data # 하나의 데이터는 1차원으로 변경되었다 
array([[ 0.,  0.,  5., ...,  0.,  0.,  0.],
       [ 0.,  0.,  0., ..., 10.,  0.,  0.],
       [ 0.,  0.,  0., ..., 16.,  9.,  0.],
       ...,
       [ 0.,  0.,  1., ...,  6.,  0.,  0.],
       [ 0.,  0.,  2., ..., 12.,  0.,  0.],
       [ 0.,  0., 10., ..., 12.,  1.,  0.]])

Model

이미지 데이터는 공통적으로 Non Linear다

Non Linear라는 것은 데이터 셋을 비선형적으로 구분해야 한다

머신러닝은 meta 프로그래밍이 가능하다

=> 메타 프로그래밍은 자기 자신 혹은 다른 컴퓨터 프로그램을 데이터로 취급하며 프로그램을 작성·수정하는 것을 말한다

특징들이 일반적이기 때문에 (abstract)

import cv2
import numpy as np
from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier() # 1단계 (Hyperparameter)

dt.fit(data.data, data.target)
# DecisionTreeClassifier(ccp_alpha=0.0, class_weight=None, criterion='gini',
#                       max_depth=None, max_features=None, max_leaf_nodes=None,
#                       min_impurity_decrease=0.0, min_impurity_split=None,
#                       min_samples_leaf=1, min_samples_split=2,
#                       min_weight_fraction_leaf=0.0, presort='deprecated',
#                       random_state=None, splitter='best')
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.neural_network import MLPClassifier, MLPRegressor
from sklearn.svm import SVC, SVR
from sklearn.neighbors import KNeighborsClassifier

t = cross_val_score(dt, data.data, data.target, cv = 10) 
t 
# array([0.79444444, 0.86666667, 0.85      , 0.8       , 0.78333333,
#       0.87222222, 0.90555556, 0.81005587, 0.81564246, 0.82681564])
t.mean() # 전처리가 잘 되어 있기 때문에 성능이 좋다 
# 0.8324736188702669
data.data = data.data.astype('float32')
knn1 = cv2.ml.KNearest_create()
knn1.train(data.data, cv2.ml.ROW_SAMPLE ,data.target) # 데이터가 연속이라는 가정을 두고 학습을 해야 하기 때문에 데이터 타입이 float이어야 한다 
# True
knn2 = KNeighborsClassifier()
knn2.fit(data.data, data.target)

# KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
#                     metric_params=None, n_jobs=None, n_neighbors=5, p=2,
#                     weights='uniform')
knn1.findNearest(data.data[3][np.newaxis], 3) # 2차원 데이터를 받는다 
#(3.0,
# array([[3.]], dtype=float32),
# array([[3., 3., 3.]], dtype=float32),
# array([[  0., 197., 232.]], dtype=float32))
knn2.predict(data.data[3][np.newaxis])
# array([3])

%timeit knn1.findNearest(data.data, 5) 
# 10 loops, best of 5: 148 ms per loop

%timeit knn2.predict(data.data) 
# 1 loop, best of 5: 417 ms per loop

 

 

 

 

 

 

반응형

'Computer_Science > Computer Vision Guide' 카테고리의 다른 글

3-9. openCV의 DNN으로 Object Detection 구현 개요  (0) 2021.09.27
3-8. RPN, Positive Anchor Box  (0) 2021.09.26
3-7. anchor box를 이용한 RPN  (0) 2021.09.24
3-6. Faster RCNN  (0) 2021.09.24
3-5. fast RCNN  (0) 2021.09.24
728x90
반응형

def rpn(base_layers, num_anchors) :
	x = Concolution2D(512, (3, 3), padding='same', activation='relu', kernel_initializer='normal', name='rpn_conv1')(base_layers)
    
    x_class = Concolution2D(num_anchors, (1, 1), activation='sigmoid', kernel_initializer='uniform', name='rpn_out_class')(x)
    x_regr = Concolution2D(num_anchors*4, (1, 1), activation='linear', kernel_initializer='zero', name='rpn_out_regress')(x)
    
    return [x_class, x_regr, base_layers]

 

w50 x h40 x d512 => 3x3 conv, 512 channel =>

1) 이진분류 : 1x1 conv 9(anchor 개수) output channel => sigmoid Binary ( FG / BG ) 

                      => w50 x h40 9anchor box => grid x box = 18000개

2) 영역추천 : 1x1 conv 4x9 output channel => bounding box regression (x1, y1, w, h)

                        (x1, y1, w, h) 9anchor box => 36

 

# RPN Bounding Box Regression

- RPN Bounding Box Regression은 Anchor Box를 Reference로 이용하여 Ground truth와 예측 Bbox의 중심좌표 x, y 그리고 w, h 의 차이가 Anchor box와 Ground Truth 간의 중심 좌표 x,y,w,h 차이와 최대한 동일하게 예측 될 수 있어야 함.

Anchor Box와 Predicted box, Ground Truth의 차이

1) PB, GTB 중심점 간의 거리

2) AB, GTB 중심점 간의 거리

두 차이가 동일하면 같게 예측 한 것이라는 가정

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

faster RCNN = RPN(Region Proposal Network) + Fast RCNN

- conv layer를 통과한 feature map은 두 경로로 흘러감

1) RPN 

2) feature map

 

Region Proposal Network 구현 이슈

- 피처는 pixel값, target은 Ground Truth bounding box인데 어떻게 selective search 수준의 region proposal을 할수있을까?

=> Anchor Box : object 유무 여부의 후보 box

anchor box는 후보군 값인데 GT box를 넣어주면 deep learning으로 가능

동일 grid point 기준, 구성은 9개, 서로 다른 크기 3개, 서로다른 ratio 3개 로 구성 => object 형태가 다르기 때문

다양하게 해야 겹치는 object, 다른 비율의 object를 찾을수있음

 

진행하다보면 각 grid point와 point별 anchor box가 또 겹침

다 겹치면 image boundary 형성

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

fast RCNN은 기존 RCNN에 spp layer사용해서 CNN LAYER 학습 횟수를 효과적으로 줄인 것과 마찬가지 원리이다.

spp layer이 아닌 ROI pooling Layer로 적용방법은 일부 다르다

- fast RCNN은 Roi pooling을 이용한다.

- 또한 SVM이라는 별도의 classification이 아닌 바로 softmax를 사용해서 deep learning network 으로 끌어들인다.

- multi task loss function으로 classification과 regression를 함께 최적화한다.

 

- faster RCNN은 selective search를 deep learning영역을 끌어들인 RPN을 사용한다.

 

# ROI pooling

- feature map 상의 임의의 ROI를 고정크기의 Pooling 영역으로 매핑

- 매핑 시 일반적으로 max pooling 적용 => 크기를 맞춰줌

- feature map의 depth와 roi pooling의 depth( channel )는 동일함, size만 고정

(spp는 depth없이 그냥 1차원 fixed length로 만들어버림)

 

- 후에 softmax 사용, ( vs svm

 

# 전과정을 deep learning으로 진행시킨 것의 의의

- softmax를 사용하는 등의 편리

- classification, regression을 multi task loss로 통합 최적화 가능

- 전과정을 back propagation을 통해 가중치 최적화 가능

 

multi-task loss
성능 비교

 

 

 

 

반응형
728x90
반응형

SPPNet : Spatial Pyramid pooling

RCNN의 문제점, 

Spatial Pyramid Matching

 

sppnet은 fast rcnn에서 개념을 차용해감

 

# RCNN의 주요 문제점

1) 너무 느린 Detection 시간

=> region을 너무 많이 proposal 하고 cnn입력됨. // region 영역 이미지가 crop과 warp까지 적용함

 

# RCNN 개선 방안

1) 원본이미지를 Selective search 하고, 다시 원본이미지를 feature extractor에 넣고 feature map을 생성함

=> 1개의 이미지만 extracted 하는 것이라 훨씬 간편함 vs 2000여개 region를 extracting

=> crop, warp의 이미지 훼손도 방지

 

=> 당시엔 feature map 이 3차원이라 dense layer, softmax,FC로 만들수가 없어서 1차원으로 만들게 됨

1D flattened fc input이 static해서 일정한 scale로 feature 고정이 안되면 안받아줌 -> 어쩔 수 없이 svm을 쓰게 되었다.

2) SPPNet

feature map 내의 중구난방 scale의 region을 별도로 mapping 할 수 있는 spp layer을 만듬

SPM을 적용해서 균일한 scale로 적용시킴

 

# spp(Spatial pyramid pooling)

CNN image classification에서 서로 다른 이미지의 크기를 고정된 크기로 변환하는 기법으로 소개

=> input image size를 고정하지 말자는 개념

대신 conv layer와 fc layer를 유연하게 연결시킬수있는 layer를 두면 classification layer를 적용하는데 문제없다.

기존 : image -> corp/warp -> conv layers -> fc layers -> output

spp : image -> conv layers -> spatial pyramid pooling -> fc layers -> output

# spatial pyramid pooling 

Bag of visual words => spatial pyramid matching

- 하나의 object를 조각조각 쪼개서(bag of visual words) histogram으로 확인하면 특징적인 부분이 드러난다.

- 원본의 정보를 새로운 mapping 정보로 변환함, 기준은 histogram

=> 비정형의 원본을 기준에 의한 정형적인 histogram화 시킨 것

 

단점은 언어면 문맥이 없고, visual object면 형상, 배치적 맥락이 없음, 그저 빈도수만 고려

=> spatial 위치 개념을 분면 상으로 넣어줌

 

# spatial pyramid matching 

image를 분면으로 쪼개면 좌표당 hitogram을 정보표현을 할 수 있다

이것으로 classification을 할 수 있다.

 

level 0는 전형 고려하지 않은 상태 => level2는 16분면으로 쪼개서 spatial 당 정보 생성 후 그 안에서 분류

 

- 분면 분할을 했기 때문에 histogram이 균일해진다.

- pooling => 원본 feature에서 일부분을 뽑아냄 => classify한 부분을 뽑아냄

나누는 분면에 따라서 feature vector가 달라짐

- 아니, 근데 원본 pooling을 했는데 또 spp를 해도 되는건가? 데이터 손실이 발생하지 않을까?

=> img size가 warp이 되면서 손실이 생각보다 적고, 성능이 높아졌다.

왜냐하면 feature map 분면분할 하면서 분면개수로 fixed length representation로 layer를 만들고 scale size가 어떻든 상관이 없어진다.

 

이상태에서 dense layer를 하면 된다.

 

# RCNN 과 SPP NET 비교

                    1개 image가 2000여번 CNN 통과                            1개 image가 1번만 CNN 통과

 

 

반응형
728x90
반응형

RCNN Training - classification

 

stage 1

annotation file에 groundTruth 좌표가 입력된 원본이미지에 selective search를 적용한다.

 

stage 2

1. imageNet으로 Feature Extractor pre-train시킴

 

2. Ground Truth와 ss predicted된 영역IOU가 0.5 이상인 경우만 해당 클래스로, 나머지는 Background로 fine-tuning함

 

3. gound Truth로만 학습하되, 0.3 IOU이하는 background로 설정, 0.3이상이지만 GT가 아닌 경우는 무시함

그 후 SVM으로 학습

 

# Bounding box Regression

모델의 목표는

1. SS proposal box의 중심점 좌표 (Px, Py)를 Ground Truth의 중심점의 거리 PwDx(p), PhDy(p)가 최소가 되게

2. width height의 값도 일치하도록

 

그걸 위해 모델은 Dx(p), Dy(p) 수정 예측값을 찾아야 한다.

 

Target 값은

G - P 좌표 간 거리 차이를 box Pw로 나눠준다,

 

# RCNN이 등장할 당시엔 기존 모델들에 비해 성능이 굉장히 높게 나왔다.

그러나 알고리즘이 매우 복잡함. 너무 detection시간이 느림, 학습시간도 오래 걸림

본질적으로 개별이미지 별로 2000여개씩 생성된 region 이미지를 CNN feature map 생성한다.

각기 따로노는 구성요소들 : selective search, CNN Feature Extractor, SVM, bounding box regressor로 구성된 복잡한 프로세스를 거침

 

향후 영향

- deep learning based object detection 성능 입증

- region proposal 기반 성능 입증

- detection 수행시간 줄이고 복잡하게 분리된 개별 아키텍처를 통합할 수 있는 방안 연구 매진

 

 

반응형
728x90
반응형

Regions - CNN

 

Object Localization이나 Detection 등의 핵심은 object의 위치를 찾는 것이다.

image classification과 동일한 architect(Feature Extrator-Feature Map-FC layer - Softmax class score / Annotation - bounding box regression)를 지닌다.

 

그런데 object detection은 여러개의 object가 있는 경우 중간지점을 예측하는 등 제대로 성능이 나오지 않음

그래서 있을만한 위치를 먼저 예측을 한다 -> region proposal 방식을 채택함

 

# stage 1

selective search 를 통해 2000여개의 region을 예측하고 proposal

예측이된 object는 cnn모델에 넣게됨

 

- object 내 또 각기 다른 object가 있을텐데 사이즈를 동일하게 맞춤

=> 사이즈를 맞추는 이유는 1D flattened Fully Connected input에서 각 사이즈가 명시가 되어있어야하기 때문이다

- 그런데 예측할때 각기 다른 scale로 예측되기 때문에 모양이 다르다.

- 모양을 맞추기 위해 image crop을 하면 모양이 망가진다. 늘어나거나 작아지거나....

warp로 감싼다

 

# stage 2

CNN detection을 통해 학습

Feature Extrator - Feature Map-FC layer - Softmax class score 

- extracted region을 classify 하고 각각 region을 cnn 하고 Bbox reg, SVM을 구동 => 속도가 매우 느릴 수 밖에

 

- 3차원의 feature map이 예를 들어(512, 7, 7)이 있으면 압축을 해서 1차원 Feature vector 로 만듬 => 1D flattened Fully Connected input

deep learning이 끝나고 보통은 softmax를 돌려야 하는데

classification은 svm같은 모델을 별도로 운용한다.

왜냐면 압축된 feature vector는 어차피 1차원이니깐, 그랬더니 성능이 좋았다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

- Feature Extractor Network

VGG, RESNET, INCEPTION 등

보통 imageNet dataset 기반으로 pretrained 됨

img classification model 은 원본 img보다는 size가 적지만 상대적으로는 큰 feature map이 만들어지고,

size는 점점 줄어들지만 channel(depth)의 수는 늘어남, feature map이 작아질수록 핵심적인 feature로만 추상화됨

 

- object detection network

pascal VOC / MS-COCO

Dataset 기반으로 pretrained 됨

별도의 network로 구성됨

scale 맞누는 것이나 bounding box 맞추는 것이나, classification을 하는 것

그래서 fully connected 여부나 bounding box regression를 어떻게 할건지를 조절

multiscale, feature pyramid 등 고려

 

# image Resolution, FPS, Detection 성능 상관 관계

높은 image Resolution => 높은 detection 성능 => 낮은 FPS

배열이 크기 때문에 제한된 성능으로 오랜기간 탐색

mAP <> 1/ FPS

FPS가 빨라야 하는 요구사항 => 낮은 Detection 성능

 

=> 상황에 맞게 조절해야 한다.

빠른 속도를 요구하면 precision과 fps로

 

맞추는게 중요하면 recall과 성능으로

반응형

'Computer_Science > Computer Vision Guide' 카테고리의 다른 글

3-2. RCNN Training과 Loss  (0) 2021.09.24
3-1. RCNN - region proposal 기반 OD  (0) 2021.09.24
2-6. OpenCV 영상처리  (0) 2021.09.23
2-4~5. OpenCV 개요  (0) 2021.09.21
2-3. MS-COCO DATASETS  (0) 2021.09.21
728x90
반응형

OpenCV VideoCapture클래스는 동영상을 개별 Frame으로 하나씩 read하는 기능을 제공

VideoWriter는 VideoCapture로 읽어들인 개별 Frame을 동영상 파일로 write 수행

 

Video Capture 개요

# Video Capture 객체는 생성인자로 입력 video 파일 위치를 받아 생성

cap = cv2.VideoCapture(video_input_path)

# Video Capture 객체는 입력 video 파일의 다양한 속성을 가져올수있음

cap.get(cv2.CAP_PROP_FRAME_WIDTH) # 영상 Frame 너비
cap.get(cv2.CAP_PROP_FRAME_HEIGTH) # 영상 Frame 높이
cap.get(cv2.CAP_PROP_FPS) # 영상 FPS

# Video Capture 객체의 read()는 마지막 Frame까지 차례로 Frame 읽음

while True :
	hasFrame, img_frame = cap.read()
    if not hasFrame :
    	print('더 이상 처리할 frame이 없습니다')
        break

 

VideoWriter 개요

- VideoWriter객체는 write할 동영상 파일 위치, encoding 코덱 유형, write fps수치, frame 크기를 생성자로 입력받아 이들값에 따른 도영상 write 수행

VideoWriter는 write시 특정 포맷으로 동영상을 Encoding 할수있음(DIVX, XVID, MJPG, X264, WMV1, WMV2)

# file read
cap = cv2.VideoCapture(video_input_path)
# 해당 format으로 write
codec = cv2.VideoWriter_fourcc(*'XVID')

vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
vid_fps = cap.get(cv2.CAP_PROP_FPS)

# target으로 write
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size)

 

colab 에서 영상 다운로드

!mkdir ./data
!wget -O /content/data/Night_Day_Chase.mp4 https://github.com/chulminkw/DLCV/blob/master/data/video/Night_Day_Chase.mp4?raw=true

데이터 로드 및 확인

# 코랩 버전에서 위의 sample은 John wick이지만 실제 Video 처리는 강의와 동일하게 Night and Day로 수행. 

import cv2

video_input_path = '/content/data/Night_Day_Chase.mp4'
# linux에서 video output의 확장자는 반드시 avi 로 설정 필요. 
video_output_path = '/content/data/Night_Day_Chase_out.mp4'

cap = cv2.VideoCapture(video_input_path)
# Codec은 *'XVID'로 설정. 
codec = cv2.VideoWriter_fourcc(*'XVID')

vid_size = (round(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) #(200, 400)
vid_fps = cap.get(cv2.CAP_PROP_FPS )
    
vid_writer = cv2.VideoWriter(video_output_path, codec, vid_fps, vid_size) 

frame_cnt = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print('총 Frame 갯수:', frame_cnt, 'FPS:', round(vid_fps), 'Frame 크기:', vid_size)
# 총 Frame 갯수: 1383 FPS: 28 Frame 크기: (1216, 516) # w h

frame 총 갯수에서 FPS(frame per second)를 나누면 시간을 구할수있음

1383 / 28 = 약 49초의 영상길이

import time

green_color=(0, 255, 0)
red_color=(0, 0, 255)

start = time.time()
index=0
while True:
    hasFrame, img_frame = cap.read()
    if not hasFrame: # false 방지
        print('더 이상 처리할 frame이 없습니다.')
        break
        
    index += 1
    print('frame :', index, '처리 완료')
    
    # 이 frame으로 detection code가 들어감
    
    # bounding box의 예시
    #              처리할 frame   위치               색깔    
    cv2.rectangle(img_frame, (300, 100, 800, 400), color=green_color, thickness=2)

	# frame이 변할 때마다 적용 
 	caption = "frame:{}".format(index)
    cv2.putText(img_frame, caption, (300, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.7, red_color, 1)
    
    vid_writer.write(img_frame)

print('write 완료 시간:', round(time.time()-start,4))
vid_writer.release()
cap.release()   

# frame : 1 처리 완료
# frame : 2 처리 완료
# frame : 3 처리 완료
# frame : 4 처리 완료
...
# frame : 1382 처리 완료
# frame : 1383 처리 완료
# 더 이상 처리할 frame이 없습니다.
# write 완료 시간: 15.5749

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts