2. Multi Model Classication
데이터 소개
위의 이미지는 다음과 같은 것을 보여줍니다.
- 10,177 개의 신원
- 얼굴 이미지 수 202,599 개
- 5 개의 랜드 마크 위치, 이미지 당 40 개의 바이너리 속성 주석
- 성별
- 큰 코
- 매력적
- 젊음
- 웃음 여부
- 모자 착용 여부
- 안경 착용 여부
- etc
최종 목표
전처리
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
"""
데이터 추출
"""
import tensorflow_datasets as tfds
from skimage.transform import resize
celeb_a = tfds.load('celeb_a')
celeb_a_trian, celeb_a_test = celeb_a['train'], celeb_a['test']
train_images = []
train_labels = []
for tensor in tftd.as_numpy(celeb_a_train):
isMale = tensor['attributes']['Male']
isSmiling = tensor['attributes']['Smiling']
label = np.array([isMale,
isSmiling]).astype(np.int8)
img = resize(tensor['image'], (190//1.5, 89//1.5))
train_labels.append(label)
train_images.append(img)
"""
test dataset도 동일
"""
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
32
33
34
35
36
37
"""
데이터량 축소
"""
import random
m_s = [] # 남자, 웃음
f_s = [] # 여자, 웃음
m_n = [] # 남자, 안웃음
f_n = [] # 여자, 안웃음
for a, b in zip(test_images, test_labels):
if b[0] and b[1]:
m_s.append((a, b))
elif not b[0] and b[1]:
f_s.append((a, b))
elif b[0] and not b[1]:
m_n.append((a, b))
elif not b[0] and not b[1]:
f_n.append((a, b))
total = m_s[:550] + f_s[:550] + m_n[:550] + f_n[:550]
random.shuffle(total)
trains = total[:2000]
tests = total[2000:]
train_images, train_labels = list(zip(*trains))
test_images, test_labels = list(zip(*tests))
train_images, train_labels = np.array(train_iamges), np.array(train_labels)
test_images, test_labels = np.array(test_images), np.array(test_labels)
1
2
3
4
5
6
7
8
9
10
11
12
13
"""
각각 onehot encoding
"""
from keras.utils import to_categorical
train_male_labels, train_smile_labels=np.split(train_labels, 2, axis=1)
test_male_labels, test_smile_labels=np.split(test_labels, 2, axis=1)
train_male_labels = to_categorical(train_male_labels)
train_smile_labels = to_categorical(train_smile_labels)
test_male_labels = to_categorical(test_male_labels)
test_smile_labels = to_categorical(test_smile_labels)
1
2
3
4
5
6
7
8
9
10
11
"""
onehot encoding 합치기
"""
train_labels_onehot = np.concatenate([
train_male_labels,
train_smile_labels], axis=1)
test_labels_onehot = np.concatenate([
test_male_labels,
test_smile_labels], axis=1)
Modeling
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
32
33
34
35
36
37
38
39
40
41
42
43
"""
smile, gender 판별 각각 모델링
"""
from keras.models import Model
from keras.layers import Conv2D, MaxPool2D, Input, Dense, Flatten
def simple_model():
inputs = Input(shape = (72, 59, 3))
# shape 구하기
# n_H' = n_H - f + 1
# n_H = 72 - 3 + 1, n_W = 59 - 3 + 1 = (70, 57, 32)
# 파라미터 갯수 구하기
# 파라미터 수 = (필터 크기 * 입력 채널 수 + 1) * 필터 수
# kernel_size = 3 (3x3 필터를 사용)
# 입력 채널 수 = 3 (입력 이미지의 RGB 채널)
# 필터 수는 filters 매개변수로 지정된 3
# 파라미터 갯수 = (3 * 3 * 3 + 1) * 32 = (27 + 1) * 32 = 28 * 32 = 896
x = Conv2D(filters = 32, kerenl_size = 3, activation = 'relu')(inputs)
# 70 / 2, 57 / 2 = (35, 28, 32) 일반적으로 내림연산
x = MaxPool2D(pool_size = 2)(x)
# (33, 26, 64) (3 * 3 * 32 + 1) * 64 = 18496
x = Conv2D(filters = 64, kerenl_size = 3, activation = 'relu')(x)
# (16, 13, 64)
x = MaxPool2D(pool_size = 2)(x)
# (14, 11, 64)
x = Conv2D(filters = 64, kerenl_size = 3, activation = 'relu')(x)
# 14 * 11 * 64
x = Flatten()(x)
x = Dense(units = 64, activation = 'relu')(x)
outputs = Dense(units = 2, activation = 'softmax')(x)
model = Model(inputs , outputs)
return model
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
32
33
34
35
36
gender_model = simple_model()
smile_model = simple_mode()
gender_model.summary()
"""
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 72, 59, 3)] 0
conv2d (Conv2D) (None, 70, 57, 32) 896
max_pooling2d (MaxPooling2 (None, 35, 28, 32) 0
D)
conv2d_1 (Conv2D) (None, 33, 26, 64) 18496
max_pooling2d_1 (MaxPoolin (None, 16, 13, 64) 0
g2D)
conv2d_2 (Conv2D) (None, 14, 11, 64) 36928
flatten (Flatten) (None, 9856) 0
dense (Dense) (None, 64) 630848
dense_1 (Dense) (None, 2) 130
=================================================================
Total params: 687298 (2.62 MB)
Trainable params: 687298 (2.62 MB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
"""
1
2
3
4
5
6
7
gender_model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['accuracy'])
smile_model.compile(loss = 'categorical_crossentropy',
optimizer = 'adma',
metrics = ['accuracy'])
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
gender_hist = gender_model.fit(
train_images,
train_male_labels,
validation_data = (
test_images,
test_male_labels
),
epochs = 15,
verbose = 1
)
smile_hist = smile_model.fit(
train_images,
train_smile_labels,
validation_data = (
test_images,
test_smile_labels
),
epochs = 15,
verbose = 1
)
1
2
3
gneder_res = gender_model.predict(test_images[1:2])
smile_res = gender_model.predict(test_images[1:2])
Multioutput Modeling
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def multi_model():
inputs = Inputs(shape = (72, 59, 3))
L1 = Conv2D(filters = 32, kernel_size = 3, activation = 'relu')(inputs)
L2 = MaxPool2D(pool_size = 2)(L1)
L3 = Conv2D(filters = 64, kernel_size = 3, activation = 'relu')(L2)
L4 = MaxPool2D(pool_size = 2)(L3)
L5 = Conv2D(filters = 64, kernel_size = 3, activation = 'relu')(L4)
L6 = MaxPool2D(pool_size = 2)(L5)
L7 = Flatten()(L6)
latent_vector = Dnese(units = 64, activation = 'relu')(L7)
gender_outputs = Dense(units = 2, activation = 'softmax')(latent_vector)
smile_outputs = Dense(units = 2, activation = 'softmax')(latent_vector)
model = Model(inputs, [gender_outputs, smile_outputs])
# outputs = Concatenate(axis = 1)([gender_outputs, smile_outputs])
# model = Model(inputs, outputs)
return model
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
32
33
34
35
36
37
38
39
40
41
model = multi_model()
model.summary()
"""
Model: "model"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_3 (InputLayer) [(None, 72, 59, 3)] 0 []
conv2d_6 (Conv2D) (None, 70, 57, 32) 896 ['input_3[0][0]']
max_pooling2d_4 (MaxPoolin (None, 35, 28, 32) 0 ['conv2d_6[0][0]']
g2D)
conv2d_7 (Conv2D) (None, 33, 26, 64) 18496 ['max_pooling2d_4[0][0]']
max_pooling2d_5 (MaxPoolin (None, 16, 13, 64) 0 ['conv2d_7[0][0]']
g2D)
conv2d_8 (Conv2D) (None, 14, 11, 64) 36928 ['max_pooling2d_5[0][0]']
max_pooling2d_6 (MaxPoolin (None, 7, 5, 64) 0 ['conv2d_8[0][0]']
g2D)
flatten_2 (Flatten) (None, 2240) 0 ['max_pooling2d_6[0][0]']
dense_4 (Dense) (None, 64) 143424 ['flatten_2[0][0]']
dense_5 (Dense) (None, 2) 130 ['dense_4[0][0]']
dense_6 (Dense) (None, 2) 130 ['dense_4[0][0]']
==================================================================================================
Total params: 200004 (781.27 KB)
Trainable params: 200004 (781.27 KB)
Non-trainable params: 0 (0.00 Byte)
__________________________________________________________________________________________________
"""
1
2
3
4
model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['accuracy']
)
1
2
3
4
5
6
7
8
9
multi_model_hist = model.fit(
train_images,
[train_male_labels, train_smile_labels],
validation_data = (test_images,
[test_male_labels, test_smile_labels]),
epochs = 15,
verbose = 1
)
모델 분리
1
2
3
4
5
6
7
8
9
10
11
12
splitted_gender_model = Model(
inputs = model.input,
outputs = model.get_layer('dense_5').output)
splitted_gender_res = splitted_gender_model.predict(test_images[0:1])
splitted_gender_res.argmax()
splitted_smile_model = Model(
inputs = model.input,
outputs = model.get_layer('dense_6').output)
This post is licensed under CC BY 4.0 by the author.