2022. 1. 22. 14:03ㆍ작업/ComputerVision
퍼셉트론 : Fully Connected Layer
따라서 일반 딥러닝이 아닌 이미지 처리에 특화된 딥러닝 모델이 등장
Convolution 연산
커널=필터 인데 우리는 의미상 커널이라고 표현해본다
2차원 이미지 데이터를 행렬로 표시하고, 커널(필터)도 2차원 행렬로 표현해서 연산. 이미지데이터를 변형 없이 그대로 사용할 수 있다.
Convolution 연산과정
이미지에 커널을 겹침. 겹치는 요소를 곱해서 결과에 넣는다. 커널은 이미지 영역 내에만 들어가야 한다.!
결과 3X3 은 겹쳐서 나올 수 있는 경우의 수에 따라 다름
컬러 이미지의 Convolution 연산
input채널의 갯수와 커널의 채널 갯수는 동일하게 해줘야 한다. (Filters always extend the full depth of the input volumne)
RGB처럼 채널이 여러개 있으면 커널도 여러개 있어야하고 Feature Map(컨볼루션 결과)도 여러개 나온다
채널(input) + 커널(필터) -> 피쳐맵(Feature Map)
CNN의 구성요소
# 1. Convolutional Layer
하나의 convolutional layer에는 여러 커널이 있을 수 있따. 저 그림에서도 보면 6개를 쌓아서 6채널 만들고, 그 다음 10개를 쌓아서 10채널 만듦
Featuer map = convolution 결과 = 이미지의 특징을 담고 있다
CNN에서는 저 Feature 맵은 커널을 학습하여 나온 결과이다(저런 색깔, 세로선 등)
커널에 따라 추출하는 Feature를 다르게 학습한다
레이어에 따라 Feature의 양상이 다르다(Low level -> high level)
Hyper parameter 사람이 정해줘야 하는 변수
1. Stride 보폭 = 커널이 이미지 내에서 이동하는 칸수
원래는 한칸씩 이동하는데 stride가 2칸이어서 커널이 2칸씩 이동한다
2. Padding 이미지의 테두리를 감싼다 (padding=1 1칸씩) 3x3 이미지 -> 5x5
feature map을 3x3으로 할 수 있다.
padding에는 보통 0을 넣어놓는다
Convolutional Layer를 왜 쓰는가
FC Layer는 1차원배열01001101011 (우리가 가진 이미지는 2x2) -> 선 하나마다 하나의 가중치
CNN은 커널 사이즈에 의해만 가중치가 결정됨(가중치 개수가 줄어든다-> 과적합 방지에 유리)
곱셈과 덧셈으로만 이루어짐 -> 선형 연산 a1x1+a2x2...=Ax
# 2. Pooling layer
방법1 max pooling 각 영역에서 최대값을 뽑아내서 새로운 Feature map 구성
일반적으로 Max Pooling을 많이 쓴다(영향력이 큰 Feature)
분류기(Classfier)
CNN은 2차원으로 했는데 왜 다시 1차원(FC)으로 하느냐.. 개,고양이,자동차, 사람.. 구분함
대표적인 CNN 모델
Lenet 1990 - 우편번호 인식을 위한 모델
SVM - 고성능컴퓨터
AlexNet 2012 - 유명한 데이터셋 imageNet에서 가장 좋은 성능을 보임(이떄부터 딥러닝으로 시작)
VGGNet 2014
ResNet 2015
Layer가 무작정 많으면 문제가 있을 수도 있다.
해결책 : Residual Connection 우회로 주기 -> 항상 기울기가 1이 넘는다.
(pooling layer는 가중치에 영향X, 두 weight layer가 존재하는데
---> 이 모든 모델들은 일단은 분류모델이다
분류작업이 아닌 경우는 YOLO, R-CNN, (객체 인식)/U-Net(이미지 segmentation) 등의 예시가 있다
분류작업이 아니라면 모델의 출력값, 손실함수, 데이터셋구성 이 완전히 다르게 이루어진다.
tensorflow로 conv2d 사용하기
import tensorflow as tf
from tensorflow import keras
tf.ones((2,2,1,1)) 2x2x1 필터가 1개
tf.ones((1,3,3,1)) 3x3x1 이미지가 1개
output = tf.nn.conv2d(inp, filter, strides,padding = 'VALID') # padding을 'VALID'으로 설정 = 패딩을 하지 않음
print(output)
# [[ [[4.] [4.]]
# [[4.] [4.]] ]], shape=(1, 2, 2, 1), dtype=float32)
keras 사용
y = tf.keras.layers.Conv2D( filters = 1, # 필터의 갯수
kernel_size = [2, 2], # "kernel_size = 2" 와 같은 의미 (높이, 너비)
strides = (1, 1),
padding = 'same', # keras.layers.Conv2D 의 padding은 소문자 'same', 'valid'
activation = 'relu',
input_shape = input_shape[1:]) (x) # 입력 : x
print(y)
# [[ [[0.36910588] [0.36910588] [0.54728895]]
# [[0.36910588] [0.36910588] [0.54728895]]
# [[0.8551657 ] [0.8551657 ] [0.6025906 ]] ]], shape=(1, 3, 3, 1), dtype=float32)
실습1
padding, stride와 layer size
import tensorflow as tf
from tensorflow.keras import layers, Sequential
# TODO: [지시사항 1번] 지시사항 대로 Conv2D 하나로 이루어진 모델을 완성하세요
def build_model1(input_shape):
model = layers.Conv2D(1, kernel_size=(3,3), strides=(1,1), padding='same',
# 커널개수, 커널크기, 스트라이드(오른쪽왼쪽), 패딩값 그대로나오게
activation="relu",
input_shape=input_shape[1:])
return model
# TODO: [지시사항 2번] 지시사항 대로 Conv2D 두개로 이루어진 모델을 완성하세요
def build_model2(input_shape):
model = Sequential([layers.Conv2D(4,kernel_size=(3,3), strides=(1,1), padding='same', input_shape=input_shape[1:]),
layers.Conv2D(4,kernel_size=(3,3), strides=(1,1), padding='same')]) # Sequential ([리스트])에 담으면 딥러닝모델로 만들어준다.
return model
# TODO: [지시사항 3번] 지시사항 대로 Conv2D 세개로 이루어진 모델을 완성하세요
def build_model3(input_shape):
model = Sequential()
model.add(layers.Conv2D(2,kernel_size=(3,3), strides=(1,1), padding='same', input_shape=input_shape[1:]))
model.add(layers.Conv2D(4,kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(layers.Conv2D(8, kernel_size=(3,3), strides=(1,1)))
return model
def main():
input_shape = (1, 5, 5, 1)
model1 = build_model1(input_shape)
model2 = build_model2(input_shape)
model3 = build_model3(input_shape)
x = tf.ones(input_shape)
print("model1을 통과한 결과:", model1(x).shape)
print("model2을 통과한 결과:", model2(x).shape)
print("model3을 통과한 결과:", model3(x).shape)
if __name__=="__main__":
main()
실습2
MLP로 이미지데이터 학습하기
CIFAR-10 데이터셋 사용
from elice_utils import EliceUtils
elice_utils = EliceUtils()
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow.keras import layers, Sequential, Input
from tensorflow.keras.optimizers import Adam
import numpy as np
import matplotlib.pyplot as plt
SEED = 2021
def load_cifar10_dataset():
train_X = np.load("./dataset/cifar10_train_X.npy")
train_y = np.load("./dataset/cifar10_train_y.npy")
test_X = np.load("./dataset/cifar10_test_X.npy")
test_y = np.load("./dataset/cifar10_test_y.npy")
train_X, test_X = train_X / 255.0, test_X / 255.0 #이미지픽셀0~255, 각 픽셀을 0~1사이로 정규화
return train_X, train_y, test_X, test_y
def build_mlp_model(img_shape, num_classes=10):
model = Sequential()
model.add(Input(shape=img_shape))
# TODO: [지시사항 1번] 모델을 완성하세요.
model.add(layers.Flatten())
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(1024, activation='relu'))
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax')) #분류기니까 분류class갯수로 하고
# 활성화 함수는 확률계산인 softmax로 해주기
return model
def plot_history(hist):
train_loss = hist.history["loss"]
train_acc = hist.history["accuracy"]
valid_loss = hist.history["val_loss"]
valid_acc = hist.history["val_accuracy"]
fig = plt.figure(figsize=(8, 6))
plt.plot(train_loss)
plt.plot(valid_loss)
plt.title('Loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['Train', 'Valid'], loc='upper right')
plt.savefig("loss.png")
elice_utils.send_image("loss.png")
fig = plt.figure(figsize=(8, 6))
plt.plot(train_acc)
plt.plot(valid_acc)
plt.title('Accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.savefig("accuracy.png")
elice_utils.send_image("accuracy.png")
def main(model=None, epochs=10):
tf.random.set_seed(SEED)
np.random.seed(SEED)
train_X, train_y, test_X, test_y = load_cifar10_dataset()
img_shape = train_X[0].shape
# TODO: [지시사항 2번] Adam optimizer를 설정하세요.
optimizer = Adam(learning_rate=0.001)
mlp_model = model
if model is None:
mlp_model = build_mlp_model(img_shape)
# TODO: [지시사항 3번] 모델의 optimizer, 손실 함수, 평가 지표를 설정하세요.
mlp_model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# TODO: [지시사항 4번] 모델 학습을 위한 hyperparameter를 설정하세요.
hist = mlp_model.fit(train_X, train_y, epochs=epochs, batch_size=64, validation_split=0.2, shuffle=True, verbose=2)
# validation은 training 데이터 중 20퍼센트를 검증에서 사용하겠다
# shuffle은 순서를 섞어줘서 trainig하게 된다.
plot_history(hist)
test_loss, test_acc = mlp_model.evaluate(test_X, test_y)
print("Test Loss: {:.5f}, Test Accuracy: {:.3f}%".format(test_loss, test_acc * 100))
return optimizer, hist
if __name__ == "__main__":
main()
실습3
MLP vs CNN 모델 비교
tensorflow에서는 .compile, .fit 등 제공하지만 .summary하면 내 모델잉 ㅓ떻게 바뀌는지
특히 Trainable params 를 알려줘서 실제 모델 학습에 사용되는 파라미터 개수를 알 수 있다.
from elice_utils import EliceUtils
elice_utils = EliceUtils()
import tensorflow as tf
from tensorflow.keras import layers, Sequential, Input
from tensorflow.keras.optimizers import Adam
import numpy as np
import matplotlib.pyplot as plt
SEED = 2021
def load_cifar10_dataset():
train_X = np.load("./dataset/cifar10_train_X.npy")
train_y = np.load("./dataset/cifar10_train_y.npy")
test_X = np.load("./dataset/cifar10_test_X.npy")
test_y = np.load("./dataset/cifar10_test_y.npy")
train_X, test_X = train_X / 255.0, test_X / 255.0
return train_X, train_y, test_X, test_y
def build_mlp_model(img_shape, num_classes=10):
model = Sequential()
model.add(Input(shape=img_shape))
# TODO: [지시사항 1번] MLP 모델을 완성하세요.
model.add(layers.Flatten())
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(1024, activation='relu'))
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
def build_cnn_model(img_shape, num_classes=10):
model = Sequential()
# TODO: [지시사항 2번] CNN 모델을 완성하세요.
model.add(layers.Conv2D(16, kernel_size=(3,3), padding='same', input_shape=(img_shape), activation='relu')) # strides default는 1,1
model.add(layers.Conv2D(32, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.MaxPool2D(pool_size=(2,2), strides=(2,2)))
# model.add(layers.MaxPool2D(2))와도 같은 의미
# 이미지 사이즈가 2배로 줄도록 설정하세요.
model.add(layers.Conv2D(64, kernel_size=(3,3), padding='same', strides=(2,2), activation='relu'))
model.add(layers.Conv2D(64,kernel_size=(3,3), padding='same', strides=(2,2), activation='relu'))
model.add(layers.MaxPool2D(2))
model.add(layers.Flatten()) # FC사용하겠다 분류기시작
model.add(layers.Dense(128,activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
def plot_history(hist):
train_loss = hist.history["loss"]
train_acc = hist.history["accuracy"]
valid_loss = hist.history["val_loss"]
valid_acc = hist.history["val_accuracy"]
fig = plt.figure(figsize=(8, 6))
plt.plot(train_loss)
plt.plot(valid_loss)
plt.title('Loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['Train', 'Valid'], loc='upper right')
plt.savefig("loss.png")
elice_utils.send_image("loss.png")
fig = plt.figure(figsize=(8, 6))
plt.plot(train_acc)
plt.plot(valid_acc)
plt.title('Accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.savefig("accuracy.png")
elice_utils.send_image("accuracy.png")
def run_model(model, train_X, train_y, test_X, test_y, epochs=10):
# TODO: [지시사항 3번] Adam optimizer를 설정하세요.
optimizer = Adam(learning_rate=0.001)
model.summary()
# TODO: [지시사항 4번] 모델의 optimizer, 손실 함수, 평가 지표를 설정하세요.
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# TODO: [지시사항 5번] 모델 학습을 위한 hyperparameter를 설정하세요.
hist = model.fit(train_X, train_y, epochs=epochs, batch_size=64, validation_split=0.2, shuffle=True, verbose=2)
plot_history(hist)
test_loss, test_acc = model.evaluate(test_X, test_y)
print("Test Loss: {:.5f}, Test Accuracy: {:.3f}%".format(test_loss, test_acc * 100))
return optimizer, hist
def main():
tf.random.set_seed(SEED)
np.random.seed(SEED)
train_X, train_y, test_X, test_y = load_cifar10_dataset()
img_shape = train_X[0].shape
mlp_model = build_mlp_model(img_shape)
cnn_model = build_cnn_model(img_shape)
print("=" * 30, "MLP 모델", "=" * 30)
run_model(mlp_model, train_X, train_y, test_X, test_y)
print()
print("=" * 30, "CNN 모델", "=" * 30)
run_model(cnn_model, train_X, train_y, test_X, test_y)
if __name__ == "__main__":
main()
실습4 VGG16 모델 구현 ( 모든 커널 크기를 3x3으로 고정하여 CNN모델의 Layer개수를 늘리기 시작한 모델)
VGGNet은 기존 AlexNet의 Layer 개수보다 두배 이상 늘어난 16개와 19개의 두가지 모델이 있습니다. 이번 실습에서는 이 중에서 16개로 이루어진 VGGNet, 즉 VGG16 모델을 구현하도록 하겠습니다.
# layer 갯수 : parameter가 존재하는 층만 세주면 된다 그래서 Flatten이나 Maxpool2D는 포함X
Conv2D 13개, Dense 3개 총 16개 VGG16
import tensorflow as tf
from tensorflow.keras import Sequential, layers
def build_vgg16():
# Sequential 모델 선언
model = Sequential()
# TODO: [지시시항 1번] 첫번째 Block을 완성하세요.
model.add(layers.Conv2D(64,kernel_size=(3,3), padding='same',activation='relu', input_shape=(224, 224, 3)))
model.add(layers.Conv2D(64, kernel_size=(3,3), padding='same',activation='relu'))
model.add(layers.MaxPooling2D(2)) #이미지2배로줄임
# TODO: [지시시항 2번] 두번째 Block을 완성하세요.
model.add(layers.Conv2D(128,kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(128, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D(2))
# TODO: [지시시항 3번] 세번째 Block을 완성하세요.
model.add(layers.Conv2D(256, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(256, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(256, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D(2))
# TODO: [지시시항 4번] 네번째 Block을 완성하세요.
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D(2))
# TODO: [지시시항 5번] 다섯번째 Block을 완성하세요.
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, kernel_size=(3,3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D(2))
# Fully Connected Layer
model.add(layers.Flatten())
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dense(4096, activation="relu"))
model.add(layers.Dense(1000, activation="softmax"))
return model
def main():
model = build_vgg16()
model.summary()
if __name__ == "__main__":
main()
실습5 ResNet 구현
Residual Connection(우회로 ) 생기는 Net,
레이어 개수가 매우 많은 경우에 발생할 수 있는 기울기 소실(Vanishing Gradient) 문제를 해결하고자 등장
import tensorflow as tf
from tensorflow.keras import layers, Model, Sequential
class ResidualBlock(Model):
def __init__(self, num_kernels, kernel_size):
super(ResidualBlock, self).__init__()
# TODO: [지시사항 1번] 2개의 Conv2D Layer를 지시사항에 따라 추가하세요.
self.conv1 = layers.Conv2D(num_kernels, kernel_size=kernel_size, padding='same', activation='relu')
self.conv2 = layers.Conv2D(num_kernels, kernel_size=kernel_size, padding='same', activation='relu')
self.relu = layers.Activation("relu")
# TODO: [지시사항 1번] Add Layer를 추가하세요.
# 텐서 두개 Add([x,y])
self.add = layers.Add()
def call(self, input_tensor):
x = self.conv1(input_tensor)
x = self.conv2(x)
x = self.add([x, input_tensor]) # 두 값을 더하는 과정 F(x) + x
x = self.relu(x)
return x
def build_resnet(input_shape, num_classes):
model = Sequential()
model.add(layers.Conv2D(64, kernel_size=(3, 3), padding="same", activation="relu", input_shape=input_shape))
model.add(layers.MaxPool2D(2))
model.add(ResidualBlock(64, (3, 3)))
model.add(ResidualBlock(64, (3, 3)))
model.add(ResidualBlock(64, (3, 3)))
model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(num_classes, activation="softmax"))
return model
def main():
input_shape = (32, 32, 3)
num_classes = 10
model = build_resnet(input_shape, num_classes)
model.summary()
if __name__=="__main__":
main()
'작업 > ComputerVision' 카테고리의 다른 글
22.02.09 윈도우에서 pf-afn 환경설정 + 인공지능 가상 옷 피팅 (Virtual Try On) demo 돌려보기 (0) | 2022.02.09 |
---|---|
22.02.06 교통표지판 이미지 분류 프로젝트 공부 (0) | 2022.02.07 |
22.01.30 윈도우에 tensorflow GPU까지 연결해서 환경설정하기(cuDNN, CUDA, tensorflow, 1050Ti) (0) | 2022.01.30 |
22.01.28(중요) Tensorflow로 배우는 CNN 핵심정리 (0) | 2022.01.29 |
22.01.19 CNN, 이미지 데이터 (0) | 2022.01.19 |