728x90
반응형

Upsampling

1. Nearest Neighbor

- N배 만큼 이미지를 키운다고 했을 Input 이미지에서 값에서 늘어난 부분에 가장 가까운 값을 채워 넣는다

2. Bed of Nails

- N배 만큼 이미지를 키운다고 했을 Input 이미지에서 늘어난 부분에 0값을 채워 넣는다

- ZFNet의 unpooling은 bed of nails의 일종이다

x = tf.reshape(tf.range(24), (1,2,3,4))
x
# <tf.Tensor: shape=(1, 2, 3, 4), dtype=int32, numpy=
# array([[[[ 0,  1,  2,  3],
#          [ 4,  5,  6,  7],
#          [ 8,  9, 10, 11]],
# 
#         [[12, 13, 14, 15],
#          [16, 17, 18, 19],
#          [20, 21, 22, 23]]]], dtype=int32)>
tf.keras.layers.UpSampling2D((1,2))(x)

# <tf.Tensor: shape=(1, 2, 6, 4), dtype=int32, numpy=
# array([[[[ 0,  1,  2,  3],
#          [ 0,  1,  2,  3],
#          [ 4,  5,  6,  7],
#          [ 4,  5,  6,  7],
#          [ 8,  9, 10, 11],
#          [ 8,  9, 10, 11]],
# 
#         [[12, 13, 14, 15],
#          [12, 13, 14, 15],
#          [16, 17, 18, 19],
#          [16, 17, 18, 19],
#          [20, 21, 22, 23],
 #         [20, 21, 22, 23]]]], dtype=int32)>
from scipy import ndimage, signal
x = tf.reshape(tf.range(9), (3,3))
f = tf.ones((2,2))
ndimage.convolve(x,f,mode='nearest') # 마지막 픽셀의 값을 복사하여 채워 넣고 연산한다 
# array([[ 8, 12, 14],
#        [20, 24, 26],
#        [26, 30, 32]], dtype=int32)

Convolution vs Transpose convolution vs Deconvolution

1. Convolution

- 이미지에서 특징을 추출하기 위한 연산 방법

- 보통 이미지에서 중요한 특징을 추출하고 연산량을 줄이기 위해 downsampling이 된다

- 데이터를 상하, 좌우 반전후 correlation연산을 하는 방법

2. Convolution transpose

- Learnable upsampling (보간법을 활용하여 값을 채우는 것과 비슷하다)

- convolution 연산과 전혀 다르지만 연산 결과가 같을 있다

- 보간법과 다르게 학습할 있는 파라미터가 있는 방법이다

3. Deconvolution

- convolution의 역연산

Transpose convolution

import tensorflow as tf 
import numpy as np
a = np.array([1,2,3])
b = np.array([-1,1])

signal.convolve(a,b) # convolution transpose 연산결과가 같다 

# array([-1, -1, -1,  3])

convolution transpose

1          -1           -1

2 -1 => -2 + 1 => -1

3 1       -3 + 2      -1

                  3       3

Variational AutoEncoder

내가 아는 확률 분포(정규분포)와 찾기 힘든분포를 가능한 근사적으로 하여 확률 분포를 찾아내는 방법

(사후확률 분포를 보다 단순한 확률분포(정규분포)로 근사하는 방법)

VAE 순서

1. 잠재변수는 다루기 쉬운 확률분포(다차원의 정규분포 등)로 가정한다

2. Encoder 함수를 통해서 평균과 표준편차를 추정한다

3. latent variable에서 sample된 z라는 value(decoder input)를 만든다 (Reparameterization trick)

4. z로부터 sampling을 하여 generator를 생성한다

Decoder network

ELBO(Evidence LowerBOund)

ELBO term을 Φ에 대해 maximize 하면 이상적인 sampling함수를 찾는 것이다
ELBO term을 𝜃에 대해 maximize 하면 MLE 관점에서 Network의 파라미터를 찾는 것이다
출처: https://deepinsight.tistory.com/127 [Steve-Lee's Deep Insight]

AutoEncoder vs Variational AutoEncoder

AutoEncoder와 Variational AutoEncoder 구조가 매우 유사한데

왜 AutoEncoder는 생성모델이 아니고 VAE는 생성 모델일까?

 

AutoEncoder는 사전 지식에 대한 조건이 없기 때문에 의미 있는 z vector의 latent space가 계속해서 바뀐다

즉 새로운 이미지를 생성할 때 z값이 계속해서 바뀐다

반면 VAE는 사전지식에 대한 조건을 부여 했기 때문에 z vector가 사전지식(내가 아는 분포)를 따른다

따라서 같은 분포에서 sampling을 하기 때문에 생성모델로 볼수 있다

 

 

 

반응형
728x90
반응형

AutoEncoder

import tensorflow as tf
(X_train, _), (X_test,_) = tf.keras.datasets.fashion_mnist.load_data()

X_train = X_train.reshape(60000, 28*28)
X_test = X_test.reshape(10000, 28*28)

X_train = X_train/255
X_test = X_test/255
class MyModel(tf.keras.models.Model):
  def __init__(self, dim):
    super(MyModel, self).__init__() # MyModel의 부모 객체를 불러와 init를 실행한다 
    self.dim = dim 
    self.encoder = tf.keras.layers.Dense(dim)
    self.decoder = tf.keras.layers.Dense(28*28, activation='sigmoid')
    # self.encoder = tf.keras.models.Sequential([ # 모델 안에 모델 넣는 방법 
    #     tf.keras.layers.Flatten(), # encoder 안에서 flatten 
    #     tf.keras.layers.Dense(dim, activation='relu')
    # ])
    # self.decoder = tf.keras.models.Sequential([
    #     tf.keras.layers.Dense(28*28, activation='sigmoid'),
    #     tf.keras.layers.Reshape(28,28)
    # ])

  def call(self, input_):
    x = self.encoder(input_)
    x = self.decoder(x)
    return x
autoencoder = MyModel(32)
autoencoder.compile(loss=tf.keras.losses.MeanSquaredError())
autoencoder.fit(X_train, X_train, epochs=20)
Epoch 1/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0282
Epoch 2/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0157
Epoch 3/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0140
Epoch 4/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0134
Epoch 5/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0131
Epoch 6/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0129
Epoch 7/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0128
Epoch 8/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0128
Epoch 9/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0127
Epoch 10/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0127
Epoch 11/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0126
Epoch 12/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0126
Epoch 13/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0126
Epoch 14/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0126
Epoch 15/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0126
Epoch 16/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0125
Epoch 17/20
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0125
Epoch 18/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0125
Epoch 19/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0125
Epoch 20/20
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0125
<keras.callbacks.History at 0x7fdfc80aab50>
autoencoder.encoder, autoencoder.decoder # 상속을 통해서 만들면 더 유연한 모델을 만들 수 있다 

# (<keras.engine.sequential.Sequential at 0x7fdfc49ca910>,
#  <keras.engine.sequential.Sequential at 0x7fdfc7feec90>)

Convolutional autoencoder

(X_train, _), (X_test,_) = tf.keras.datasets.fashion_mnist.load_data()

X_train[..., tf.newaxis].shape
# (60000, 28, 28, 1)
tf.expand_dims(X_train, axis=-1)
X_train = X_train.reshape(60000, 28,28,1)

X_test = X_test.reshape(10000,28,28,1)

input_ = tf.keras.Input((28,28,1))
x = tf.keras.layers.Conv2D(16,3, padding='same', activation='relu')(input_)
x = tf.keras.layers.MaxPooling2D(2,2, padding='same')(x)
x = tf.keras.layers.Conv2D(8,3, padding='same', activation='relu')(x)
x = tf.keras.layers.MaxPooling2D(2,2, padding='same')(x)
x = tf.keras.layers.Conv2D(8,3, padding='same', activation='relu')(x)
x = tf.keras.layers.MaxPooling2D(2,2, padding='same')(x)

x = tf.keras.layers.Conv2D(8,3, padding='same', activation='relu')(x)
x = tf.keras.layers.UpSampling2D((2,2))(x)
x = tf.keras.layers.Conv2D(8,3, padding='same', activation='relu')(x)
x = tf.keras.layers.UpSampling2D((2,2))(x)
x = tf.keras.layers.Conv2D(16,3, activation='relu')(x)
x = tf.keras.layers.UpSampling2D((2,2))(x)
# x = tf.keras.layers.Conv2D(16,3, padding='same', activation='relu')(x)
model = tf.keras.models.Model(input_,x)

model.summary() 
# 중간에 복원하는 과정이 맞지 않아도 학습을 통해서 최종결과에서 틀린 것을 보완된다 / Conv2DTranspose(deconvolution)을 사용하면 완전히 복원 가능하긴 하다 
Model: "model_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d_37 (Conv2D)           (None, 28, 28, 16)        160       
_________________________________________________________________
max_pooling2d_18 (MaxPooling (None, 14, 14, 16)        0         
_________________________________________________________________
conv2d_38 (Conv2D)           (None, 14, 14, 8)         1160      
_________________________________________________________________
max_pooling2d_19 (MaxPooling (None, 7, 7, 8)           0         
_________________________________________________________________
conv2d_39 (Conv2D)           (None, 7, 7, 8)           584       
_________________________________________________________________
max_pooling2d_20 (MaxPooling (None, 4, 4, 8)           0         
_________________________________________________________________
conv2d_40 (Conv2D)           (None, 4, 4, 8)           584       
_________________________________________________________________
up_sampling2d_16 (UpSampling (None, 8, 8, 8)           0         
_________________________________________________________________
conv2d_41 (Conv2D)           (None, 8, 8, 8)           584       
_________________________________________________________________
up_sampling2d_17 (UpSampling (None, 16, 16, 8)         0         
_________________________________________________________________
conv2d_42 (Conv2D)           (None, 14, 14, 16)        1168      
_________________________________________________________________
up_sampling2d_18 (UpSampling (None, 28, 28, 16)        0         
=================================================================
Total params: 4,240
Trainable params: 4,240
Non-trainable params: 0
_________________________________________________________________

Type Markdown and LaTeX: 𝛼2

Variational AutoEncoder

숨어 있는 확률 분포가 복잡할 경우
데이터의 분포를 정규분포와 가능한 오차가 적은 방향으로 분포를 구한다

Likelihood

어떤 모델에서 해당 데이터(관측값)이 나올 확률

Maximum Likelihood

현재 가지고 있는 데이터셋이 나올 확률을 최대화하는 방향으로 확률 분포를 구하는 방법

데이터가 1, 4, 5, 6, 9가 있다고 가정했을 때

주황색 확률분포로 부터 데이터들을 얻었을 가능성이 더 클 것이다

왜냐하면 획득한 데이터들의 분포가 주황색 확률분포의 중심에 더 일치하는 것 처럼 보이기 때문이다

단, 주어진 데이터 샘플이 편향된 경우 추정된 확률 분포가 실제 상황을 표현하기에 부적합한 확률 분포가 될 수 있다

Maximum A Posterior

사전 지식에 근거하여(과거의 경험) 실제 데이터의 분포가 어떠 할 것이다 라고 예측하는 방법

동전 던지기를 예로 들면

동전을 10번 던져서 모두 앞면이 나온다고 하더라도,

동전의 앞면과 뒷면이 나올 확률이 0.5로 동일할거라는 사전지식이 동시에 작용하기 때문에

동전의 뒷면이 나올 확률이 0%가 되지 않도록 확률 분포를 구하는데 영향을 끼친다

따라서 올바른 사전지식을 가지는 것이 중요하며 올바른 사전지식을 활용하는 경우 MLE보다 더 나은 모수(평균, 표준편차등) 파라미터를 추정할 수 있다

생성 모델

숨어 있는 분포를 알 수 있으면 데이터를 생성할 수 있다

예를 들어 숫자의 잠재적인 의미 즉 필체를 나타내는 잠재변수인 각도, aspect ratio등으로 부터 숫자를 만들어 낼 수 있다

다차원의 아주 큰 분포를 더 작은 분포로 표현할 수 있는데

더 작은 분포를 찾으면 다차원의 데이터 분포를 가진 데이터를 생성 할 수 있다

작은 latent space를 통해 학습된 모델에서도 데이터를 잘 표현하는 데이터를 생성할 수 있다

※ 잠재 공간(latent space): 어떠한 관측 데이터 혹은 입력 데이터가 있을 때 그 데이터 들을 대표할 수 있는 함축된 데이터 공간 또는 집합을 잠재 공간이라고 한다

AutoEncoder의 생성 모델적 의미

Encoder를 이용해서 복잡한 분포로 부터 정규분포를 알아내고

정규 분포로부터 숨어 있는 작은 분포를 찾아낸다(latent space)

이렇게 알아낸 latent space로부터 decoder를 활용하여 원래의 데이터를 복원한다

왜도와 첨도

1. 왜도(skewness) - 분포의 비대칭성을 나타내는 척도

2. 첨도(kurtosis) - 분포의 뾰족한 정도를 나타내는 척도

왜도

첨도

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

iris = sns.load_dataset('iris')
data = iris.iloc[:,:-1]
f, axes = plt.subplots(2, 2, figsize=(7, 7), sharex=True)
sns.distplot(data.iloc[:,0], color="skyblue", ax=axes[0,0])
sns.distplot(data.iloc[:,1], color="olive", ax=axes[0,1])
sns.distplot(data.iloc[:,2], color="gold", ax=axes[1,0])
sns.distplot(data.iloc[:,3], color="teal", ax=axes[1,1])
for i, ax in enumerate(axes.reshape(-1)):
    ax.text(x=0.97, y=0.97, transform=ax.transAxes, s="Skewness: %f" % data.iloc[:,i].skew(),\
        fontweight='demibold', fontsize=10, verticalalignment='top', horizontalalignment='right',\
        backgroundcolor='white', color='xkcd:poo brown')
    ax.text(x=0.97, y=0.91, transform=ax.transAxes, s="Kurtosis: %f" % data.iloc[:,i].kurt(),\
        fontweight='demibold', fontsize=10, verticalalignment='top', horizontalalignment='right',\
        backgroundcolor='white', color='xkcd:dried blood')
plt.tight_layout()

 

 

 

 

반응형
728x90
반응형

YOLO (You Only Look Once)

import tensorflow as tf
vgg = tf.keras.applications.VGG16()

vgg.layers[2].get_config()

{'activation': 'relu',
 'activity_regularizer': None,
 'bias_constraint': None,
 'bias_initializer': {'class_name': 'Zeros', 'config': {}},
 'bias_regularizer': None,
 'data_format': 'channels_last',
 'dilation_rate': (1, 1),
 'dtype': 'float32',
 'filters': 64,
 'groups': 1,
 'kernel_constraint': None,
 'kernel_initializer': {'class_name': 'GlorotUniform',
  'config': {'seed': None}},
 'kernel_regularizer': None,
 'kernel_size': (3, 3),
 'name': 'block1_conv2',
 'padding': 'same',
 'strides': (1, 1),
 'trainable': True,
 'use_bias': True}
layer = tf.keras.layers.Dense(2)
layer.build((None,2))  

layer.weights
# [<tf.Variable 'kernel:0' shape=(2, 2) dtype=float32, numpy=
#  array([[-0.9223565 , -0.76073015],
#         [-0.94507563,  0.25733256]], dtype=float32)>,
#  <tf.Variable 'bias:0' shape=(2,) dtype=float32, numpy=array([0., 0.], dtype=float32)>]
layer2 = tf.keras.layers.Dense(2) # __call__는 build가 되어 있는지 확인하고 되어 있으면 call 연산  
layer2(tf.constant([[1,2,3],[4,5,6]])) # build가 되어 있지 않으면 build후 call 연산 

# <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
# array([[ 2.7301223, -2.2875605],
#        [ 5.7739477, -3.6619558]], dtype=float32)>
model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(2, input_shape(2,)) # (None,2) => 요소가 2개인 데이터 N개 
])
model(tf.constant([[1,2,3],[4,5,6]]))
# <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
# array([[ 5.3184466,  3.66491  ],
#        [12.929317 ,  7.4551005]], dtype=float32)>
model.input_shape # build 하지 않으면 input_shape을 알 수 없다 
# (2, 3)
model.weights
# [<tf.Variable 'dense_3/kernel:0' shape=(3, 2) dtype=float32, numpy=
#  array([[ 0.6508478 , -0.3525918 ],
#         [ 0.99072933,  0.830464  ],
#         [ 0.89538   ,  0.7855246 ]], dtype=float32)>,
#  <tf.Variable 'dense_3/bias:0' shape=(2,) dtype=float32, numpy=array([0., 0.], dtype=float32)>]

Build의 의미

ex) layer = tf.keras.layer.Dense(2)

1. layer를 만들때 내부적으로 __init__가 실행되며 unit을 인자로 받는다

2. 구조적으로 인자로 받은 unit수 만큼 perceptron을 생성한다

3. input의 인자 개수에 따라 자동적으로 weight metrix의 크기가 결정된다

4. unit수 만큼 output으로 나온다

 

build는 weight metrix의 크기를 정하고 만드는 작업을 의미한다 + 초기화

Custom layer (YOLO)

class YoloReshape(tf.keras.layers.Layer):
  def __init__(self, shape_):
    super().__init__()
    self.shape_ = tuple(shape_)

  def call(self, input_):
    S = [self.shape_[0], self.shape_[1]]
    C = 20 
    B = 2
    S[0]*S[1]*C
    ix = S[0]*S[1]*C
    ix2 = S[0]*S[1]*B

    boxs = tf.reshape(input_[:,:ix2], tuple(input_.shape[0],S[0],S[1],B*4))
    boxs = tf.nn.sigmoid(boxs) 

    confidence = tf.reshape(input_[:,ix2:ix1], tuple(input_.shape[0],S[0],S[1],B))
    confidence = tf.nn.sigmoid(confidence) 

    class_prob = tf.reshape(input_[:,ix1:], tuple(input_.shape[0],S[0],S[1],C)) # input_.shape[0] + tuple(S[0],S[1],C) / 10,20
    class_prob = tf.nn.softmax(class_prob) # 확률로 강제시킨다 

    return tf.concat([boxs, confidence, class_prob])

  def build(self):
    pass

  def get_config(self):
    config = super().get_config().copy()
    config.update({
        'target_shape':self.shape_
    })
    return config

Representation learning

- 어떤 task를 수행하기에 적절하게 데이터의 representation을 변형하는 방법을 학습하는 것

- 어떤 task를 더 쉽게 수행할 수 있는 다른 형태로 표현을 만드는 것 예) PCA

AutoEncoder

Unsupervised learning
Self-supervised learning
Manifold learning (N차원의 공간을 N보다 작은 저차원의 특성으로 표현하여 학습하는 방법)
Feature extraction

Autoencoder는 내 자신을 작은 차원으로 표현하는 encoder와 작은 차원을 그대로 복원하는 decoder로 구성되어 있는 하나의 모델

 

Autoencoder를 이상치 제거에서 활용한다고 했을 때

Encoder를 거쳐 차원이 줄어들면 핵심 특징을 제외한 것들은 자연스럽게 사라지게 되므로

noise가 포함된 데이터가 autoencoder를 통과하면 noise는 사라지게 될 것이다

 

비용절감 차원에서 좋은 모델

self-supervised: 자기 자신의 데이터가 target이 된다

AutoEncoder 구현

import tensorflow as tf
(X_train, _), (X_test, _) = tf.keras.datasets.mnist.load_data()
X_train = X_train.reshape(60000,28*28)
X_train = X_train/255
X_test = X_test.reshape(10000,28*28)
X_test = X_test/255
input_ = tf.keras.Input((784,)) # 28x28 image이기 때문에 
encoder = tf.keras.layers.Dense(32)(input_) # layer는 encoder와 decoder가 대칭이 되도록 설계 해야 한다 
encoder = tf.keras.layers.ReLU()(encoder)
decoder = tf.keras.layers.Dense(784, activation='sigmoid')(encoder) # Mnist 

autoencoder = tf.keras.models.Model(input_, decoder)
autoencoder.compile(loss=tf.keras.losses.BinaryCrossentropy(), optimizer='adam')
autoencoder.summary()
Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 784)]             0         
_________________________________________________________________
dense (Dense)                (None, 32)                25120     
_________________________________________________________________
re_lu (ReLU)                 (None, 32)                0         
_________________________________________________________________
dense_1 (Dense)              (None, 784)               25872     
=================================================================
Total params: 50,992
Trainable params: 50,992
Non-trainable params: 0
_________________________________________________________________
history = autoencoder.fit(X_train, X_train, epochs=50)

Epoch 1/50
1875/1875 [==============================] - 5s 2ms/step - loss: 0.1629
Epoch 2/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.1044
Epoch 3/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0966
Epoch 4/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0951
Epoch 5/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0946
Epoch 6/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0942
Epoch 7/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0940
Epoch 8/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0939
Epoch 9/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0938
Epoch 10/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0937
Epoch 11/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0936
Epoch 12/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0935
Epoch 13/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0935
Epoch 14/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0934
Epoch 15/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0934
Epoch 16/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0934
Epoch 17/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0933
Epoch 18/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0933
Epoch 19/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0932
Epoch 20/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0932
Epoch 21/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0932
Epoch 22/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0931
Epoch 23/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0931
Epoch 24/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0931
Epoch 25/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0931
Epoch 26/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0930
Epoch 27/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0930
Epoch 28/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0930
Epoch 29/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0930
Epoch 30/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0929
Epoch 31/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0929
Epoch 32/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0929
Epoch 33/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0929
Epoch 34/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0929
Epoch 35/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 36/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 37/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 38/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 39/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 40/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 41/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0928
Epoch 42/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 43/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 44/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 45/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 46/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0927
Epoch 47/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0926
Epoch 48/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0926
Epoch 49/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0926
Epoch 50/50
1875/1875 [==============================] - 4s 2ms/step - loss: 0.0926
import matplotlib.pyplot as plt

img = 7

fig, axs = plt.subplots(1,2)
axs[0].imshow(X_test[img].reshape(28,28))
axs[1].imshow(autoencoder(X_test)[img].numpy().reshape(28,28)) 
# 대표적인 특징만 표현된다 (섬세하게 재현되지는 않는다)

layer = tf.keras.layers.Dense(1)

layer.get_config() 
# activity_regularizer:  레이어 출력에 페널티를 적용하는 정규화 기법 / BN 때문에 더 이상 잘 사용하지 않는다
{'activation': 'linear',
 'activity_regularizer': None,
 'bias_constraint': None,
 'bias_initializer': {'class_name': 'Zeros', 'config': {}},
 'bias_regularizer': None,
 'dtype': 'float32',
 'kernel_constraint': None,
 'kernel_initializer': {'class_name': 'GlorotUniform',
  'config': {'seed': None}},
 'kernel_regularizer': None,
 'name': 'dense_2',
 'trainable': True,
 'units': 1,
 'use_bias': True}

Convolution 결과 복원

input_ = tf.keras.Input((28,28,1))
x = tf.keras.layers.Conv2D(16,3, padding='same')(input_)
x = tf.keras.layers.Conv2D(8,3, padding='same')(x)
x = tf.keras.layers.Conv2D(16,3, padding='same')(x)

model = tf.keras.models.Model(input_, x)

model.summary()
Model: "model_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_4 (InputLayer)         [(None, 28, 28, 1)]       0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 28, 28, 16)        160       
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 28, 28, 8)         1160      
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 28, 28, 16)        1168      
=================================================================
Total params: 2,488
Trainable params: 2,488
Non-trainable params: 0
_________________________________________________________________

Sparse Auto-Encoder

차원을 늘리는 모델

 

 

반응형
728x90
반응형

YOLO (You Only Look Once)

XML 파일 불러오기

Multiple object detection인 경우 정형데이터로 구성할 수 없기 때문에

xml이나 json과 같은 다양한 의미를 지닌 데이터 형식을 불러와야 할 때가 있다

import tensorflow as tf 
import xml.etree.ElementTree as ET # xml 형식의 파일을 parsing하는 파이썬 라이브러리 
import pathlib
import matplotlib.pyplot as plt
import matplotlib.patches as mpt
src = 'VOCdevkit/VOC2007/Annotations/000005.xml'

출처: http://host.robots.ox.ac.uk/pascal/VOC/voc2007/examples/index.html

 

tree = ET.parse(src) # xml 파알 구조 불러오기 (tree 형태로)
root = tree.getroot() # 시작지점 설정 (root 찾기)
root # annotation가 최상위 root (태그)
# <Element 'annotation' at 0x16107dcc0>
for i in root.iter('object'): # 5개 object가 있다 / name / pose / truncated /diffiicult / bndbox
    print(i)
# <Element 'object' at 0x163992a90>
# <Element 'object' at 0x163992db0>
# <Element 'object' at 0x163995130>
# <Element 'object' at 0x163995450>
# <Element 'object' at 0x163995770>
for i in root.iter('object'): # object에 대한 정보만 필요하기 때문에 object태그의 하위 요소만 불러온다
    difficult = i.find('difficult').text
    cls = i.find('name').text

Class 이름 key, value 쌍 만들기

classes = '''
Aeroplanes
Bicycles
Birds
Boats
Bottles
Buses
Cars
Cats
Chairs
Cows
Dining tables
Dogs
Horses
Motorbikes
People
Potted plants
Sheep
Sofas
Trains
TVMonitors
'''
classes = [i.lower() for i in classes.strip().split('\n')]
classes = [i[:-1] if i[-1]=='s' else i for i in classes]
classes
['aeroplane',
 'bicycle',
 'bird',
 'boat',
 'bottle',
 'buse',
 'car',
 'cat',
 'chair',
 'cow',
 'dining table',
 'dog',
 'horse',
 'motorbike',
 'people',
 'potted plant',
 'sheep',
 'sofa',
 'train',
 'tvmonitor']
classes = ['aeroplane',
 'bicycle',
 'bird',
 'boat',
 'bottle',
 'bus',
 'car',
 'cat',
 'chair',
 'cow',
 'diningtable',
 'dog',
 'horse',
 'motorbike',
 'people',
 'pottedplant',
 'sheep',
 'sofa',
 'train',
 'tvmonitor']
classes = dict(zip(classes, range(20)))
def annote(img_id):
    '''
    20개 클래스에 해당하는 class id와 4가지 위치 정보를 반환하는 함수 
    '''
    src = f'VOCdevkit/VOC2007/Annotations/{img_id}.xml'
    tree = ET.parse(src)
    root = tree.getroot()
    temp = []
    for i in root.iter('object'):
        difficult = i.find('difficult').text
        cls = i.find('name').text
        if cls not in classes: #  or int(difficult) == 1
            continue
        cls_id = classes[cls]
        xmlbox = i.find('bndbox')
        xmin = int(xmlbox.find('xmin').text)
        ymin = int(xmlbox.find('ymin').text)
        xmax = int(xmlbox.find('xmax').text)
        ymax = int(xmlbox.find('ymax').text)
        
        bb = (xmin,ymin,xmax,ymax)
        temp.append((cls_id, bb))
    return temp
path = pathlib.Path('VOCdevkit/VOC2007/Annotations')
for i in path.iterdir():
    print(str(i).split('/')[-1].split('.')[0])
007826
002786
006286
002962
...
004488
005796
002947
imgs = [str(i).split('/')[-1].split('.')[0] for i in path.iterdir()]
imgs
['007826',
 '002786',
 '006286',
 '002962',
 '008297',
 ...
 '004682',
 '006095',
 '001922',
 '000382',
 ...]
'VOCdevkit/VOC2007/JPEGImages/'+imgs[0]+'.jpg'
# 'VOCdevkit/VOC2007/JPEGImages/007826.jpg'
temp = [
]
for i in imgs:
    temp.append(annote(i))
len(temp)
# 5011
temp

[[(10, (80, 217, 320, 273)),
  (8, (197, 193, 257, 326)),
  (8, (139, 184, 185, 231)),
  ...
  [(9, (264, 148, 496, 280)), (12, (98, 123, 237, 248))],
 [(0, (65, 75, 470, 269))],
 [(3, (3, 167, 163, 500))],
 ...]
annote(imgs[0])
[(10, (80, 217, 320, 273)),
 (8, (197, 193, 257, 326)),
 (8, (139, 184, 185, 231)),
 (8, (258, 180, 312, 314)),
 (8, (10, 195, 93, 358)),
 (8, (82, 252, 243, 372)),
 (8, (43, 319, 144, 375))]
def show(img_id):
    '''
    이미지에 bounding box 그리는 함수 
    '''
    im = plt.imread('VOCdevkit/VOC2007/JPEGImages/'+str(imgs[img_id])+'.jpg')
    fig, ax = plt.subplots(1,1)
    for i in annote(imgs[img_id]):
        rec = mpt.Rectangle((i[1][0],i[1][1]), i[1][2]-i[1][0], i[1][3]-i[1][1], edgecolor='red', fill=False)
        ax.add_patch(rec)
    ax.imshow(im)
show(100)

show(1100)

데이터 불러와서 학습 데이터 구성하는 방법 (모델에 학습 데이터를 전달하기 위한/Multiple object)

1. 데이터를 파일로 부터 불러온다

2. 원하는 데이터 구조로 데이터를 가공한다 # ex) 'filename', (10,20,100,200), '1'

3. DataFrame 형태로 변환한다

4. Generator 형태로 만들거나 tf.data.Dataset으로 만든다

# 상속하는 방식(프레임워크에 한정적이지만 tensorflow에 최적화된 기능을 사용할 수 있다) / seqence data처럼 사용할 수 있기 때문에 학습 데이터 유연하게 전달할 수 있다
tf.keras.utils.Sequence 
# keras.utils.data_utils.Sequence
tf.keras.preprocessing.image_dataset_from_directory()
tf.keras.preprocessing.image.ImageDataGenerator() 
flow_from_directory 
flow_from_dataframe  # geneartor tf.data.Dataset

Numpy 형태 데이터를 학습을 하면 자동으로 tensor로 변환하여 학습이 가능하긴 하지만

이러한 tensor는 데이터 전체 메모리를 한꺼번에 올리기 때문에 컴퓨터 성능에 따라 학습이 불가능할 수도 있다

뿐만아니라 메모리를 효율적으로 사용하지 못하기 때문에 학습 속도가 비교적 느릴 수 있다

 

반면 tf.data.Dataset은 내부적으로 최적화 되어 있기 때문에 cpu, gpu를 동시에 사용하거나

prefetch, cache기법 등 다양한 방법으로 최적화된 학습이 가능하다

따라서 데이터를 generator형태로 불러오거나 tf.data.Dataset으로 변환하는 과정은 중요하다

(단, lazy 방식으로 만들어져 있기 때문에 데이터 하나 확인하는 것이 매우 까다롭다

Network Design

lre = tf.keras.layers.LeakyReLU(alpha=0.1) # 자주 쓰는 것들은 layers에 포함되어 있다 

input_ = tf.keras.Input((448,448,3))
x = tf.keras.layers.Conv2D(64,7,2, padding='same', activation=lre)(input_) 
x = tf.keras.layers.MaxPool2D(2,2)(x)
x = tf.keras.layers.Conv2D(192,3, padding='same', activation=lre)(x)
x = tf.keras.layers.MaxPool2D(2,2)(x)
x = tf.keras.layers.Conv2D(128,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(256,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(256,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,3, padding='same', activation=lre)(x)
x = tf.keras.layers.MaxPool2D(2,2)(x)
x = tf.keras.layers.Conv2D(256,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(256,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(256,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(256,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3, padding='same', activation=lre)(x)
x = tf.keras.layers.MaxPool2D(2,2)(x)
x = tf.keras.layers.Conv2D(512,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(512,1, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3,2, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3, padding='same', activation=lre)(x)
x = tf.keras.layers.Conv2D(1024,3, padding='same', activation=tf.keras.activations.linear)(x)

x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(4096, activation=lre)(x)
x = tf.keras.layers.Dropout(0.5)(x)
x = tf.keras.layers.Dense(1470)(x) 
x = tf.keras.layers.Reshape((7,7,30))(x)
model = tf.keras.models.Model(input_, x)

model.summary()

Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 448, 448, 3)]     0         
_________________________________________________________________
conv2d (Conv2D)              (None, 224, 224, 64)      9472      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 112, 112, 64)      0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 112, 112, 192)     110784    
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 56, 56, 192)       0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 56, 56, 128)       24704     
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 56, 56, 256)       295168    
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 56, 56, 256)       65792     
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 56, 56, 512)       1180160   
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 28, 28, 512)       0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 28, 28, 256)       131328    
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 28, 28, 512)       1180160   
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 28, 28, 256)       131328    
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 28, 28, 512)       1180160   
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 28, 28, 256)       131328    
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 28, 28, 512)       1180160   
_________________________________________________________________
conv2d_12 (Conv2D)           (None, 28, 28, 256)       131328    
_________________________________________________________________
conv2d_13 (Conv2D)           (None, 28, 28, 512)       1180160   
_________________________________________________________________
conv2d_14 (Conv2D)           (None, 28, 28, 512)       262656    
_________________________________________________________________
conv2d_15 (Conv2D)           (None, 28, 28, 1024)      4719616   
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 14, 14, 1024)      0         
_________________________________________________________________
conv2d_16 (Conv2D)           (None, 14, 14, 512)       524800    
_________________________________________________________________
conv2d_17 (Conv2D)           (None, 14, 14, 1024)      4719616   
_________________________________________________________________
conv2d_18 (Conv2D)           (None, 14, 14, 512)       524800    
_________________________________________________________________
conv2d_19 (Conv2D)           (None, 14, 14, 1024)      4719616   
_________________________________________________________________
conv2d_20 (Conv2D)           (None, 7, 7, 1024)        9438208   
_________________________________________________________________
conv2d_21 (Conv2D)           (None, 7, 7, 1024)        9438208   
_________________________________________________________________
conv2d_22 (Conv2D)           (None, 7, 7, 1024)        9438208   
_________________________________________________________________
flatten (Flatten)            (None, 50176)             0         
_________________________________________________________________
dense (Dense)                (None, 4096)              205524992 
_________________________________________________________________
dropout (Dropout)            (None, 4096)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1470)              6022590   
_________________________________________________________________
reshape (Reshape)            (None, 7, 7, 30)          0         
=================================================================
Total params: 262,265,342
Trainable params: 262,265,342
Non-trainable params: 0
_________________________________________________________________

Leaky ReLU

Loss function

10개 -> 두 개의 bounding box / 20개 -> 각각의 클래스 확률 결과를 도출하기 위해서는

Custom layers를 통해 직접 loss function을 구현해야 한다

Regression

Activation function을 linear함수(값의 범위만 정한다)를 사용하거나 사용하지 않으면 Regression 모델을 만들 수 있다

Loss function을 Crossentropy대신 MSE를 사용하면 된다

!pip install -U tensorflow-addons
# 최신 기법 + 중요성이 살짝 떨어지는 것들을 모아둔 추가 패키지 / 기본 tensorflow에 없는 layer를 사용할 수 있다
!pip install typeguard
# How to install tensorflow addons on mac with m1
!pip install --upgrade --force --no-dependencies https://github.com/apple/tensorflow_macos/releases/download/v0.1alpha3/tensorflow_addons_macos-0.1a3-cp38-cp38-macosx_11_0_arm64.whl

 

반응형
728x90
반응형
import matplotlib.pyplot as plt
import matplotlib.patches as mpt
import pandas as pd
import tensorflow as tf
import numpy as np
import cv2
air = pd.read_csv('dataset/annotations/airplane.csv', header=None)
face = pd.read_csv('dataset/annotations/face.csv', header=None)
motorcycle = pd.read_csv('dataset/annotations/motorcycle.csv', header=None)

air.rename(columns={1:'x1',2:'y1',3:'x2',4:'y2',0:'filename',5:'target'}, inplace=True)
face.rename(columns={1:'x1',2:'y1',3:'x2',4:'y2',0:'filename',5:'target'}, inplace=True)
motorcycle.rename(columns={1:'x1',2:'y1',3:'x2',4:'y2',0:'filename',5:'target'}, inplace=True)

air.filename = air.filename.map(lambda x: 'dataset/images/airplane/'+x)
face.filename = face.filename.map(lambda x: 'dataset/images/face/'+x)
motorcycle.filename = motorcycle.filename.map(lambda x: 'dataset/images/motorcycle/'+x)
data=pd.concat([air,face,motorcycle], axis=0, ignore_index=True)
im = plt.imread('dataset/images/airplane/image_0001.jpg')

fig, ax = plt.subplots(1,1)
ax.imshow(im)
pt = mpt.Rectangle((49,30),349-49,137-30, fill=False) 
ax.add_patch(pt)

vgg = tf.keras.applications.VGG16(include_top=False, input_shape=(224,224,3))
vgg.trainable = False

vgg.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 56, 56, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 28, 28, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 28, 28, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 14, 14, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
=================================================================
Total params: 14,714,688
Trainable params: 0
Non-trainable params: 14,714,688
_________________________________________________________________
im = tf.keras.preprocessing.image.load_img('dataset/images/airplane/image_0001.jpg')
t = cv2.resize(np.array(im), (224,224))
t.shape
# (224, 224, 3)
tt = vgg(t[tf.newaxis]).numpy()

tt.shape
# (1, 7, 7, 512)
plt.imshow(tt[0,...,0]) 
# 비행기 이미지를 convolution layer를 통과 했을 때 / 512개 특징중 비행기 특징 중 하나

plt.imshow(tt[0,...,1])

Yolo(You Only Look Once)

YOLO Detection System

1. ImageNet에서 사용했던 이미지 크기에서 키운 크기인 448x448 이미지로 크기를 변경한다

(Convolution 크기 mapping 하기 위해서)

2. Single convolutional neural network를 통과 시킨다

3. Non-max suppression

 

YOLO Architecture

1. Pretrained network

- 주황색 테두리로 표현한 부분은 GoogLeNet을 이용하여 ImageNet 1000-class dataset을 사전에 학습한 결과를 Fine-Tuning한 네트워크이다

- ImageNet의 데이터 셋은 224x224의 크기를 가진 이미지 데이터이지만, 이미지를 키워 448 x 448 x 3 이미지를 입력 데이터로 받는다

 

2. Reduction layer

- Reduction layer는 GoogLeNet의 기법을 응용 하여 연산량은 감소하면서 층은 깊게 쌓는 방식을 이용한다

 

3. Training network

- Pre-trained Network에서 학습한 feature를 이용하여 Class probability와 Bounding box를 학습하고 예측하는 네트워크 이다

- YOLO의 예측 모델은 S x S x (B x 5 + C) 개의 파라미터를 결과로 출력하는데, PASCAL VOC 데이터 셋은 20 클래스를 제공하기 때문에 C의 값은 20이고 B의 값이 2이라는 것은 하나의 그리드 셀에서 2개의 bounding box를 예측하겠다는 의미 이다.

그리고 그리드 셀은 7개로 정의 하였으므로 모두 계산하면 결과값은 1470이다 (7 x 7 x (2 X 5 + 20)

 

NMS(Non Maximum Suppression)

edge thinning 기법으로, 여러 box가 겹치게 되면 가장 확실한 것만 고르는 방법

1. Confidence(score) 높은 순서대로 정렬한다

2. 제일 Confidence값을 기준으로 하나씩 IOU를 비교 하여, 미리 설정해둔 threshold값보다 경우 Bounding box를 버린다

3. 다음 작은 Confidence값을 가진 Bounding box를 기준으로 다시 자신보다 작은 confidence를 가진 Bounding box와 IOU를 비교하여 Bounding box를 선택할지 버릴지 결정한다

4. 3 작업을 지속하여 최종적으로 남은 Bounding box를 사용한다

 

import tensorflow as tf 
import matplotlib.pyplot as plt
import matplotlib.patches as mpt
boxes = tf.constant([
    [190,380,(190+300),(380+150)],
    [300,420,(300+150),(420+210)],
    [320,360,(320+200),(360+200)],
    [390,50,(390+300),(50+300)],
    [390,50,(390+300),(50+300)],
], dtype=tf.float32)
scores = tf.constant([0.9,0.8,0.5,0.7,0.7])

tf.image.non_max_suppression(boxes, scores, 2)
# <tf.Tensor: shape=(2,), dtype=int32, numpy=array([0, 1], dtype=int32)>
fig, ax = plt.subplots(1,1)
im = plt.imread('people.jpg')
plt.imshow(im)
m1 = mpt.Rectangle((60,80),130,200, edgecolor='red', facecolor='none', linewidth=3)
m2 = mpt.Rectangle((90,60),110,50, edgecolor='pink', facecolor='none', linewidth=3)
ax.add_patch(m1)
ax.add_patch(m2)

fig, ax = plt.subplots(1,1)
m1 = mpt.Rectangle((60,80),130,200, edgecolor='red', facecolor='none', linewidth=5)
m2 = mpt.Rectangle((90,60),110,50, edgecolor='pink', facecolor='none', linewidth=5)
ax.add_patch(m1)
ax.add_patch(m2)
plt.plot();

NMS 처리 후 최소한의 Bounding box만 남긴다

 

Loss function

- 1i^obj는 그리드 i 안에 객체가 존재하는지 여부를 의미한다. 값은 객체 존재하면 1, 존재하지 않으면 0이다

- 1ij^obj는 그리드 i의 j번째 bounding box predictor가 사용되는지 여부를 의미한다.

- Object가 존재하는 그리드 i의 bounding box predictor j에 대해, x와 y의 loss를 계산한다

- Object가 존재하는 그리드 i의 bounding box predictor j에 대해, w와 h의 loss를 계산한다. box에 대해서는 작은 분산(small deviation) 반영하기 위해 제곱근을 취한 , sum-squared error를 구한다. (같은 error라도 box의 경우 상대적으로 IOU에 영향을 적게 준다)

- Object가 존재하는 그리드 i의 bounding box predictor j에 대해, confidence score의 loss를 계산한다 (Ci = 1)

- Object가 존재하지 않는 그리드 i의 bounding box predictor j에 대해, confidence score의 loss를 계산한다 (Ci = 0)

- Object가 존재하는 그리드 i에 대해, conditional class probability의 loss를 계산한다. (pi(c)=1 if class c is correct, otherwise: pi(c)=0)

 

- λ_coord: coordinates(x, y, w, h) 대한 loss와 다른 loss들과의 균형을 위한 balancing parameter

- λ_noobj: 객체가 있는 box와 없는 box 간에 균형을 위한 balancing parameter

Learning techniques

1. EarlyStopping

- 성능이 이상 높아지지 않으면 학습을 멈춘다

2. LearningRateScheduler

- Epoch을 기준으로 learning rate를 조절한다

3. ReduceROnPlateau

- 모델의 성능이 시간이 지남에 따라 향상되지 않으면 학습률을 낮춘다

2-Stage-detector vs 1-Stage-detector

1-stage detector는 비교적 빠르지만 정확도가 낮고
2-stage detector는 비교적 느리지만 정확도가 높다

 

 

반응형
728x90
반응형

Object Detection

Single object detection 문제는 학습 데이터 구성을 하나의 물체로만 구성된 이미지들로 학습을 하게 되면 어렵지 않게 구현할 수 있다

하지만, Multiple object detection 문제는 물체가 한 개일 때 두 개 일 때 등 몇 개인지 정해지지 않았을 때는 문제가 까다로워진다

결국 이러한 문제를 해결하기 위해 고안된 방식이 Region proposal인 것이다

Localization이후에 detection을 하게 되면 multiple object detection 문제도 어느 정도 해결이 가능해 진다

Faster R-CNN

Fast R-CNN은 하나의 네트워크로 구성할 수 없기 때문에 병목 현상이 발생하는 문제가 있었다
이러한 문제점을 보완하여 Selective search대신 Region proposal을 네트워크로 만들어 속도를 향상시킨 모델이다

Region proposal 구하는 과정

1. Pre-trained VGG모델에 이미지를 입력값으로 넣는다

2. VGG모델로 부터 나온 feature map 3x3 conv연산을 한다

3. class score를 매기기 위해서 feature map 대하여 1x1 conv 연산을 한다

4. class score에 따라 상위 N개의 region proposals만을 추출한다

import tensorflow as tf 
import numpy as np 
import pandas as pd
import cv2
import matplotlib.pyplot as plt
import matplotlib.patches as pt
img = tf.keras.utils.get_file('zebra.jpg', 'https://i.imgur.com/XjeiRMV.jpg')
h = w = 800

im = cv2.imread(img)
im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)

im_r = cv2.resize(im, (h,w))
im_r_ = im_r.copy()
vgg = tf.keras.applications.VGG16(include_top=False)
backbone = tf.keras.models.Model(vgg.input, vgg.layers[17].output)
backbone(im_r_[tf.newaxis]).shape
# TensorShape([1, 50, 50, 512])
backbone(im_r_[tf.newaxis])[0,...,0].shape
# TensorShape([50, 50])
backbone(im_r_[tf.newaxis])[0,...,0]


<tf.Tensor: shape=(50, 50), dtype=float32, numpy=
array([[ 0.       ,  0.       ,  0.       , ...,  0.       ,  0.       ,
         0.       ],
       [ 0.       ,  0.       ,  0.       , ...,  0.       ,  0.       ,
         0.       ],
       [ 0.       ,  0.       ,  0.       , ...,  0.       ,  0.       ,
         0.       ],
       ...,
       [ 1.2889676, 15.054933 , 11.117959 , ...,  0.       ,  0.       ,
         0.       ],
       [ 0.       ,  0.       ,  0.       , ...,  0.       ,  0.       ,
         0.       ],
       [ 0.       ,  0.       ,  0.       , ...,  0.       ,  0.       ,
         0.       ]], dtype=float32)>
plt.imshow(backbone(im_r_[tf.newaxis])[0,...,0]) 
# 원본 이미지가 vgg네트워크를 통과하면 원본이미지의 16x16크기가 feature map의 1x1로 표현된다

plt.imshow(backbone(im_r_[tf.newaxis])[0,...,1])

plt.imshow(backbone(im_r_[tf.newaxis])[0,...,2])

IOU 계산

box1 = [20,50,200,200]
box2 = [220,220,440,440]

x = np.zeros((500,500))
def iou(box1, box2):
  x1 = max(box1[0], box2[0])
  y1 = max(box1[1], box2[1])

  x2 = min(box1[2], box2[2])
  y2 = min(box1[3], box2[3])

  if (x1 < x2 and y1 < y2):
    w_o = x2-x1 
    h_o = y2-y1 
    area =  w_o*h_o
  else:
    return 0
  
  area_b1 = (box1[2] - box1[0])*(box1[3] - box1[1])
  area_b2 = (box2[2] - box2[0])*(box2[3] - box2[1])
  union =  area_b1 + area_b2 - area

  return area/union
iou(box1, box2)
# 0
fig, ax = plt.subplots()
ax.plot()
ax.add_patch(
   pt.Rectangle(
      (box1[0], box1[1]),                   
      box1[2], box1[3],                     
      edgecolor = 'red',
      facecolor = 'yellow',
      fill=True,
   ))
ax.add_patch(
   pt.Rectangle(
      (box2[0], box2[1]),                   
      box2[2], box2[3],                     
      edgecolor = 'red',
      facecolor = 'blue',
      fill=True,
   ))
plt.show()

x = np.arange(8,800,16)
y = np.arange(8,800,16)
ratio = [0.5,1,2]
scale = [8,16,32]
al = np.zeros((22500,4)) 
count = 0
cl = np.array(np.meshgrid(x,y)).T.reshape(-1,2) 

for i in cl:
  cx, cy = i[0], i[1]
  for r in ratio:
    for s in scale:
      h = pow(pow(s,2)/r,0.5) 
      w = h*r
      h *= 16 
      w *= 16 
      xmin = cx-0.5*w
      ymin = cy-0.5*h
      xmax = cx+0.5*w
      ymax = cy+0.5*h
      al[count] = [xmin,ymin,xmax,ymax]
      count += 1

Anchor는 0보다 작고 800보다 큰 값은 제외 시키고 구한다

is_al = al[np.where((al[:,0]>=0) & (al[:,1]>=0) & (al[:,2]<=800) & (al[:,3]<=800))]
len(is_al)
# 8940
im.shape, im_r_.shape
# ((333, 500, 3), (800, 800, 3))
box1 = [120,25,200,165]
box2 = [300,50,480,320]

point = 550
h = w = 800

x = np.array([120,25,200,165])
y = np.array([300,50,480,320])


img_ = np.copy(im_r_)
for i in range(point,point+9):
  x_min = int(al[i][0])
  y_min = int(al[i][1])
  x_max = int(al[i][2])
  y_max = int(al[i][3])
  cv2.rectangle(img_, (x_min,y_min),(x_max,y_max),(0,255,0),thickness=4)

for i in range(2500):
  cv2.circle(img_, (cl[i,0],cl[i,1]), 1, (255,0,0), thickness=2)

x[0] = int(x[0]*(w/im.shape[1])) 
x[1] = int(x[1]*(h/im.shape[0]))
x[2] = int(x[2]*(w/im.shape[1]))
x[3] = int(x[3]*(h/im.shape[0]))

y[0] = int(y[0]*(w/im.shape[1]))
y[1] = int(y[1]*(h/im.shape[0]))
y[2] = int(y[2]*(w/im.shape[1]))
y[3] = int(y[3]*(h/im.shape[0]))

rec1 = cv2.rectangle(img_, (x[0],x[1]),(x[2],x[3]), color=(255,0,0), thickness=3)
rec2 = cv2.rectangle(img_, (y[0],y[1]),(y[2],y[3]), color=(255,0,0), thickness=3)

plt.imshow(img_)

x # object 1
# array([192,  60, 320, 396])

y # object2
# array([480, 120, 768, 768])
objects = [x,y]
result = np.zeros((8940,len(objects)))

for t, g in enumerate(objects):
  for i,j in enumerate(is_al):
    result[i][t] = iou(j,g)

anchor_id = np.where((al[:,0]>=0) & (al[:,1]>=0) & (al[:,2]<=800) & (al[:,3]<=800))

data = pd.DataFrame(data=[anchor_id[0],result[:,0],result[:,1]]).T # anchor당 iou값 
data.rename(columns={0:'anchor_id',1:'o1_iou',2:'o2_iou'}, inplace=True)
data.anchor_id = data.anchor_id.astype('int')

data
	anchor_id	o1_iou	o2_iou
0	1404	0.0	0.000000
1	1413	0.0	0.000000
2	1422	0.0	0.000000
3	1431	0.0	0.000000
4	1440	0.0	0.000000
...	...	...	...
8935	21051	0.0	0.065818
8936	21060	0.0	0.065818
8937	21069	0.0	0.065818
8938	21078	0.0	0.064846
8939	21087	0.0	0.058693
data.o1_iou.max(), data.o1_iou.argmax()
# (0.6562500000000001, 1785)
data.o2_iou.max(), data.o2_iou.argmax()
# (0.7119140625000001, 7540)
data[data.o1_iou > 0.65]
	anchor_id	o1_iou	o2_iou
1785	6418	0.65625	0.0
1791	6427	0.65625	0.0
2013	6868	0.65625	0.0
2019	6877	0.65625	0.0
2241	7318	0.65625	0.0
2247	7327	0.65625	0.0
2487	7768	0.65625	0.0
2493	7777	0.65625	0.0
data[data.o2_iou > 0.7]

anchor_id	o1_iou	o2_iou
7540	16877	0.0	0.711914
7547	16886	0.0	0.711914
7768	17327	0.0	0.711914
7775	17336	0.0	0.711914
data[data.o2_iou > 0.7].anchor_id.values, 1785 # 5개만 물체라고 볼수 있다 
# (array([16877, 16886, 17327, 17336]), 1785)
top = al[data[data.o2_iou > 0.7].anchor_id.values]
al[1785]
# array([ -8., 712., 120., 840.])
point = 550
h = w = 800

x = np.array([120,25,200,165])
y = np.array([300,50,480,320])


img_2 = np.copy(im_r_)
for i,j in enumerate(top):
  x_min = int(top[i][0])
  y_min = int(top[i][1])
  x_max = int(top[i][2])
  y_max = int(top[i][3])
  cv2.rectangle(img_2, (x_min,y_min),(x_max,y_max),(0,255,0),thickness=1)

# for i in range(2500):
#   cv2.circle(img_2, (cl[i,0],cl[i,1]), 1, (255,0,0), thickness=2)

x[0] = int(x[0]*(w/im.shape[1])) 
x[1] = int(x[1]*(h/im.shape[0]))
x[2] = int(x[2]*(w/im.shape[1]))
x[3] = int(x[3]*(h/im.shape[0]))

y[0] = int(y[0]*(w/im.shape[1]))
y[1] = int(y[1]*(h/im.shape[0]))
y[2] = int(y[2]*(w/im.shape[1]))
y[3] = int(y[3]*(h/im.shape[0]))

rec1 = cv2.rectangle(img_2, (x[0],x[1]),(x[2],x[3]), color=(0,0,255), thickness=3)
rec2 = cv2.rectangle(img_2, (y[0],y[1]),(y[2],y[3]), color=(0,0,255), thickness=3)

plt.figure(figsize=(10,10))
plt.imshow(img_2)

data['o1_iou_objectness'] = data.apply(lambda x: 1 if x['o1_iou'] > 0.7 else -1, axis=1)

data['o2_iou_objectness'] = data.apply(lambda x: 1 if x['o2_iou'] > 0.7 else -1, axis=1)

data[data['o1_iou_objectness']==1]

anchor_id	o1_iou	o2_iou	o1_iou_objectness
data[data['o2_iou_objectness']==1]
	anchor_id	o1_iou	o2_iou	o1_iou_objectness	o2_iou_objectness
7540	16877	0.0	0.711914	-1	1
7547	16886	0.0	0.711914	-1	1
7768	17327	0.0	0.711914	-1	1
7775	17336	0.0	0.711914	-1	1

Region proposal

input_ = tf.keras.Input((50,50,512))
x = tf.keras.layers.Conv2D(512,3, padding='same')(input_)
regressor = tf.keras.layers.Conv2D(4*9,1, activation='linear', name='reg')(x)
classifier = tf.keras.layers.Conv2D(9,1, activation='sigmoid', name='cla')(x)
PRN = tf.keras.models.Model(input_, [regressor, classifier])

PRN.summary()
Model: "model"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_2 (InputLayer)            [(None, 50, 50, 512) 0                                            
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 50, 50, 512)  2359808     input_2[0][0]                    
__________________________________________________________________________________________________
reg (Conv2D)                    (None, 50, 50, 36)   18468       conv2d_2[0][0]                   
__________________________________________________________________________________________________
cla (Conv2D)                    (None, 50, 50, 9)    4617        conv2d_2[0][0]                   
==================================================================================================
Total params: 2,382,893
Trainable params: 2,382,893
Non-trainable params: 0
__________________________________________________________________________________________________

Loss

y_true = np.array([[0.,1.],[0.,0.]])
y_pred = np.array([[1.,1.],[1.,0.]])

loss1 = tf.keras.losses.MeanSquaredError()
loss2 = tf.keras.losses.mean_squared_error

tf.nn.l2_loss(y_true-y_pred)
# <tf.Tensor: shape=(), dtype=float64, numpy=1.0>
loss1(y_true, y_pred)
# <tf.Tensor: shape=(), dtype=float64, numpy=0.5>

loss2(y_true, y_pred)
# <tf.Tensor: shape=(2,), dtype=float64, numpy=array([0.5, 0.5])>

loss(y_true, y_pred)
# <tf.Tensor: shape=(), dtype=float32, numpy=0.5>
def smooth_l1_loss(y_truee, y_pred,smooth=1):
  x = tf.abs(y_true, y_pred)
  mask = tf.cast(tf.less(x,1.0), tf.float32)
  loss = (mask*(0.5*x**2)) + (1-mask)*(x-0.5)
  return loss
class MyLoss(tf.keras.losses.Loss):
  def call(self,y_true,y_pred,smooth=1):
    x = tf.abs(y_true, y_pred)
    mask = tf.cast(tf.less(x,1.0), tf.float32)
    loss = (mask*(0.5*x**2)) + (1-mask)*(smooth-0.5)
    return loss
from functools import partial
mys = partial(smooth_l1_loss, smooth=2)

 

 

반응형
728x90
반응형

MASK RCNN

instance segmentation의 대표적인 모델

- Faster RCNN과 FCN 기법 개선 및 결합

   * ROI-Align

   * 기존 bounding box regression과 classification에 binary mask prediction 추가

- 비교적 빠른 detection 시간과 높은 정확도

- 직관적이고 상대적이고 쉬운 구현

 

 

ROI align

segmentation에서 roi pooling 문제점 : masking을 해야해서 아주 정확해야 함

- roi pooling에서 quantization을 하면서 문제 발생

소수점이 생겨서 들어오는 사이즈가 정확하게 매칭이 되지 않음

 

- ROI를 소수점 그대로 매핑하고 roi의 개별 grid에 4개의 point를 균등하게 배열

- 개별 point에서 가장 가까운 feature map Grid를 고려하면서 포인트를 weighted sum으로 계산

- 계산된 포인트를 기반으로 max pooling 수행

 

 

영상처리 bilinear interpolation 예제

https://blog.naver.com/PostView.nhn?isHttpsRedirect=true&blogId=dic1224&logNo=220882679460&categoryNo=0&parentCategoryNo=207&viewDate=&currentPage=1&postListTopCurrentPage=1&from=search

Bilinear Interpolation을 이용한 ROI-align

확대하면 깨지게 됨, 대신 빈공간을 유추해서 보정함

 

거리에 맞게 계산해서 채워줌

그상태에서 pooling

 

 

mask rcnn Feature Extractor : Resnet + FPN

Loss function

- k개의 정해진 class에 대해서 그 class에 pixel이 속하는지 그렇지 않은지 sigmoid로 결정 binary-cross-entropy-loss

- mask rcnn에서 mask prediction

- prediction후 resize해서 원본 이미지에 적용

 

 

반응형

'Computer_Science > Mask RCNN' 카테고리의 다른 글

13-2. Semantic Segmentation FCN  (0) 2021.10.31
13-1. Segmentation  (0) 2021.10.27
728x90
반응형

FCN (Fully Convolutional Network for Semantic Segmentation)

평이한 느낌이지만 당시, classification에 flatten한 fully connected가 필수였지만 이 모델은 convolution만으로 이루어진 모델임.

 

Semantic Segmentation Encoder-Decoder Model

- 원본 이미지를 convolution으로 차원 축소하여 응축된 정보를 가지고, 이를 다시 복원하면서 필요한 정보를 학습

- 이렇게 학습된 정보를 기반으로 segmentation 수행

축소하면서 사이즈는 줄어들지만 채널 깊이는 깊어짐

응축된 상태에서 재창조, 재해석 추구

feature map 정보를 upsampling하면서 masking 정보를 하면서 prediction 모델의 weight를 채움

 

Fully connected layer vs Fully convolutional layer

imageNet은 classification할 object가 1000개 생김

그런데 가변적인 image size가 들어오기 때문에 좀더 융통성있는 convolution으로 하면 좋다.

grid by grid별로 cat의 정보가 있는 것

각 pixel에 확률값이 있고, 확률값이 우세하면 cat으로 classification

 

 

FCN (Fully Convolutional Network for Semantic Segmentation)

 

마지막의 fully connected를 fully convolution으로 설정

3번째로 32x32로 쭉 늘리면서 복원을 함

masking 정보와 gtbox 정보를 매칭하면서 학습시킴

 

개별 pixel을 학습 시키면서 weight도 적용, upsampling도 weight 적용

 

32x upsampling을 통한 pixel wise prediction

32배 upsampling하면서 뭉개진 형태가 됨

그래서 de-convolution을 통해서 최대한 비슷하게 복구하는 방법 찾음

Feature map 혼합 pixel wise prediction

- con7을 2배시켜서 2x2로 만들어서 pool4이랑 합치고, 합친 concat pool을 16x upsampling 해서 prediction한게 FCN 16s

- con7을 4배시켜서 4x4로 만들어서 2배 pool4이랑 pool3이랑 합치고, 합친 concat pool을 8x upsampling 해서 prediction한게 FCN 8s

 

  FCN-32s FCN-16s FCN-8s
IOU 59.4% 62.4% 62.7%

 

반응형

'Computer_Science > Mask RCNN' 카테고리의 다른 글

13-3~4. MASK RCNN  (0) 2021.10.31
13-1. Segmentation  (0) 2021.10.27
728x90
반응형

Compound Scaling

- 너무 거대한 backbone, 여러겹의 fpn, 큰 입력 이미지의 크기 등의 개별적인 부분들에 집중하는 것은 비효율적

- EfficientNet에서 개별 요소들을 함께 Scaling 하면서 최적 결합을 통한 성능 향상을 보여줌

- EfficientDet에서도 backbone, BiFPN, Prediction Layer, 입력 이미지 크기를 Scaling 기반으로 최적 결합 하여 D0~D7 모델 구성

Backbone Netwrok

- EfficientNet B0~B6 로 Scaling 그대로 적용

BiFPN Network

- depth는 BiFPN 기본 반복 block을 3개로 설정하고 scaling 적용

Dbifpn = 3 + o

- width 채널 수는 {1.2, 1.25, 1.3, 1.25, 1.4, 1.45} 중 grid Search를 통해 1.35로 Scaling계수를 선택하고 이를 기반으로 Scaling 적용

Wbifpn = 64x(1.35^o)

Prediction Network

- width 채널수는 BiFPN채널 수 와 동일

- Detth는 아래식을 적용

Dbox = Dclass = 3 + [o/3]

입력 이미지 크기

Rinput = 512 + ox128

 

 

EfficientDet 기타 적용 요소 및 성능 평가

기타 적용 요소

- activation : siLU(swish)

- Loss : Focal Loss

- augmentation : horizontal flip 과 scale jittering

- NMS : soft nms

 

반응형
728x90
반응형

 Compound Scaling

- 네트웍의 깊이(Depth), 필터 수(width), 이미지 Resolution크기를 함께 최적으로 조합하여 모델 성능 극대화

   => 깊이로 resNet이 이득을 봄

- 그러나 단순한 depth의 양으로는 한계가 있어 엔지니어링 테크닉으로 한계 극복 노력

 

EfficientNet architect

- 필터 수 변경 : channels를 wider

- 네트웍 깊이 변경 : deepper

- 이미지 resolution : 224x224 => 512x512가 더 성능이 좋음

=> compound scaling은 이 3요소를 조합하여 모델 개선

 

개별 scaling 요소에 따른 성능 향상 테스트

                        필터수 변경                                깊이 변경                                이미지 resolution 변경

- 필터수, 네트웍 깊이를 일정 수준 이상 늘려도 성능향상 미비, resource는 더욱 많이 듬

- 단, Resolution이 경우 어느정도 약간씩 성능 향상이 지속.

- ImageNet 데이터 세트 기준 80% 정확도에서 개별 scaling 요소를 증가시키더라도 성능향상이 어려움

=> 체감 한계가 있어서 최적화로 성능향상 필요

 

최적 scaling 도출 기반 식

- depth, width, resolution에 따른 FLOPS 변화를 기반으로 최적 시 도출

- width, resolution은 2배가 되면 flops는 4배가 됨(그래서 제곱을 곱함)

 

- 3가지 scaling Factor를 동시 고려하는 compound scaling 적용

- 최초에는 승수를 1로 고정하고 grid search기반으로 a, b, r의 최적 값을 찾아냄.

   EfficientNetB0의 경우 a = 1.2, b = 1.1, r = 1.15

- 다음으로 a, b, r을 고정하고 승수를 증가시켜가면서 efficient B1 ~ B7까지 Scale up 구성

최적화된 architect로 최적화된 resource로 최적화된 속도, 성능을 냄

 

 

반응형

+ Recent posts