일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- Convolutional Neural Networks
- 스무고개 Metric
- cs231
- but how?
- 장영준
- 리멤버나우 요약
- 웹 독학
- flask
- 알고리즘
- multi-task learning
- 리멤버나우
- aws rds
- 2003 에러
- 오픈소스
- 딥러닝
- pytorch-tutorial
- 뤼이드
- 경제 요약
- 백준 2193
- git password
- C++
- git-lfs
- 110 옮기기
- 코딩테스트
- flaks
- 미국 이란 전쟁
- 2003 error
- 프로그래머스
- 이베이 매각
- 프로그래머스 여행경로
- Today
- Total
Nam's
[신발검색엔진] 04 - 이미지 유사도 측정 모델 개발(Autoencoder) 본문
지난 6월 25, 26일(금,토)에는 이미지 유사도 측정 모델을 처음으로 구현해봤다. (ML을 도와주기로한 친구와 같이 진행했다.)
우선은 2만5천장의 사진에 모두 Label을 만드는 것이 현실적으로 어렵다고 판단했고, 장기적으로도 Unsupervised Learning이 유지 보수에 유리하다고 판단했다. 가장 먼저 떠오른 아이디어는 Autoencoder의 형태로 모델을 만들어서 추출된 Feature값을 비교하는 방식으로 이미지 유사도를 측정하는 것이었다.
1. Autoencoder Tutorial
먼저, Tensorflow-Keras 공식 Autoencoder tutorial을 보고 아주 간단한 autoencdoer를 만들었다.
latent_dim = 64
class Autoencoder(Model):
def __init__(self, encoding_dim):
super(Autoencoder, self).__init__()
self.latent_dim = latent_dim
self.encoder = tf.keras.Sequential([
layers.Flatten(),
layers.Dense(latent_dim, activation='relu'),
])
self.decoder = tf.keras.Sequential([
layers.Dense(784, activation='sigmoid'),
layers.Reshape((28, 28))
])
def call(self, x):
encoded = self.encoder(x)
decoded = self.decoder(encoded)
return decoded
autoencoder = Autoencoder(latent_dim)
모델이 Dense Layer만 사용하는 너무 간단한 모델이라서 성능은 안나온다.
2. Autoencoder with CNN layers
이어서 이번에는 간단한 CNN Layer를 사용하는 Autoencoder를 만들어봤다. [참고 문서]
input_img = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(16, (3, 3), activation='relu', padding='same')(input_img)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), padding='same')(x)
# at this point the representation is (4, 4, 8) i.e. 128-dimensional
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(encoded)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(16, (3, 3), activation='relu')(x)
x = layers.UpSampling2D((2, 2))(x)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
autoencoder = keras.Model(input_img, decoded)
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
성능 측정은 encoded 된 numpy array의 L2 norm과 cosine similarity를 사용해서 평가했다.
이번에도 Converutional Layer가 단순해서 그런지? 성능이 기대에 미치지 못했다. 그저 사물의 윤곽만 잡는 수준이고, 슬리퍼와 구두를 구분하지 못하는 것 같다.
그리고 무신사에서 '신발' 키워드로 크롤링해온 데이터에 전처리가 필요해보였다. 사람 사진이 들어간 사진도 많았고, 구두솔, 구두약 같은 신발이 아닌 제품들도 따라 들어온다.
3. Autoencoder with VGG16
이번에는 성능이 어느정도 검증된 VGG16 모델의 CNN의 Layer 구조를 가져와서 쌓아봤다.
input_img = keras.Input(shape=(224, 224, 1))
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(input_img)
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), strides=(2,2))(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), strides=(2,2))(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), strides=(2,2))(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), strides=(2,2))(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), strides=(2,2))(x)
print(encoded.shape)
# (7, 7, 512)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(encoded)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
print(x.shape)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
print(decoded.shape)
autoencoder = keras.Model(input_img, decoded)
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
2만 5천장의 데이터를 epoch 100으로 학습시켰다. 이미지 해상도도 28 pixel에서 224 pixel로 높여줬다.
그 결과 Decoder의 이미지 재현 능력은 올라간듯 보인다. 하지만 여전히 similarity 평가에서 신발의 디테일한 디자인을 파악하지는 못하는 것 같다. 전체적으로 신발의 방향과 윤곽이 이미지 유사도를 결정하는데 가장 큰 영향을 미치는 것으로 보인다.
4. 개선 방향
우선, 신발이 아닌 제품들을 필터링 해주는 데이터 전처리 작업이 필요해보인다.
그리고 친구와 논의 결과 Classification 모델을 먼저 넣는 것이 좋겠다고 결론내렸다. 우선 슬리퍼인지 구두인지 분류한 다음 슬리퍼 카테고리 내에서 이미지 유사도를 측정하는 것이 더 정확하고 빠른 predict이 가능해보인다. 그리고 Classification 모델이 있다면 검색 엔진의 속도도 빨라질 것으로 기대된다. Classification 모델이 일종의 Indexing을 해주는 역할을 할 수 있을 것 같다.
'개발 > Side Project' 카테고리의 다른 글
[신발검색엔진] 06 - 인공지능 모델 배포하기 (1) | 2021.07.03 |
---|---|
[신발검색엔진] 05 - 이미지 유사도 측정 모델 개발(VGG16) (6) | 2021.06.28 |
[신발검색엔진] 03 개발 1주차 - 웹 구현 Debugging (0) | 2021.06.26 |
[신발검색엔진] 02 개발 1주차 - 웹 구현 (0) | 2021.06.26 |
[신발검색엔진] 01 프로젝트 계획 & 시작 (0) | 2021.06.22 |