Major Study./Bioinformatics

Multi-class와 Multi-label classificiation, 분포가 다른 Output들

sosal 2022. 8. 18. 12:04
반응형

딥러닝 연구를 하다보니, 다양한 task를 수행하게 된다.

 

그 중, 딥러닝을 자주 씀에도 불구하고 내게 조금 헷갈렸던 task가 있는데,

바로 Multi-class와 Multi-label 이다.

 

쉽고 기본적인 내용같지만, Label의 형태에 따라서 매우 복잡한 문제가 될 수도 있다.

 

이 글에서는 Multi-label을 예측하는 문제에서,

Output이 어떤 것은 Regression을 해야하고, 어떤 것은 classification을 수행해야 할 때를

위해 내가 정리하는 글이다.

 

 

 

1. Bianry classification - Sigmoid

 

일단 binary classification은, Logistic regression과 동일한 task로

간단한 sigmoid로 쉽게 해결할 수 있다.

 

Sigmoid는 Output을 0~1 사이로 변형시킴으로써, binary classification을 수행할 수 있다.

 

예측하고자 하는 Label을 0과 1로 둠으로써,

1인 케이스는 output을 1에 가깝게, 0인 case에 대해서는 output을 0에 가깝게 예측한다면

Entropy의 특성상 값이 낮아지기에, Loss를 cross-entropy로 설정하여

쉽게 모델의 최적의 파라미터 (weight)를 유도할 수 있다.

 

* 따라서 Label과 prediction output의 dimension은 (1,), 하나의 '점' 이어야 한다.

 

model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])

 

ex) 강아지 vs 고양이 분류

Label

- 강아지: 0

- 고양이: 1

 

Prediction output

- 강아지: 0.069

- 고양이: 0.831

 

 

 

2. Binary classification - Softmax

 

Softmax는 정말 단순하게, Exponential 값의 ratio를 통해, 총합을 1로 변형하는 것이다.

output의 값을 exp(outputs) / sum(exp(outputs))로 변형시켜, 총합을 1로 만들어

가장 높은 값 하나를 선택하는 것이 바로 softmax이다.

 

- 따라서 Softmax를 활용하여 Binary classification을 수행하기 위해서는 Output을 2개로 만들어야한다. -

 

예를 들어 강아지, 고양이 2개의 class를 분류하는 문제에서 기본 Neural들의 output이 5, 2가 나왔다고 가정한다면,

Softmax라는 activation function을 거치면 0.953, 0.047로 변하게 된다.

 

따라서 Softmax layer를 활용한 binary classification의 경우

Label과 prediction output의 dimension은 (2,) 이어야만 한다.

 

이를 위하여 우리는 One-hot encoding을 활용한다.

 

ex) 강아지 vs 고양이 분류

Label

- 강아지: [1, 0]

- 고양이: [0, 1]

 

Prediction output

- 강아지: [0.931, 0.069]

- 고양이: [0.169, 0.831]

 

model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

 

 

3. binary_crossentropy vs categorical_crossentropy

 

binary_crossentropy 계산은 다음과 같다.

sigmoid activation function을 거친 하나의 output을 계산한다.

 

따라서, 악성 vs 음성을 분류하는 경우,

y를 악성 확률이라고 가정한다면 1-y는 음성일 확률이 된다.

 

따라서 양성과 음성에 대한 entropy를 구하여 계산는 다음의 binary_crossentropy 공식을 활용한다.

binary_crossentropy

 

 

하나의 output을 예측하므로, 당연히 binary classification의 경우 output_size가 1이 된다.

 

binary_crossentropy는 Multi-label classification에 활용될 수 있는데 (아래에서 설명됨)

아래 공식에서 class를 이야기하는 i의 수마다 모두 entropy를 계산한다.

 

 

 

categorical_crossentropy는 one-hot encoding으로 되어있는 binary class [1, 0] 또는 [0, 1]에 대하여

다음을 계산한다.

위 공식을 output [y1, y2]에 대하여 적용한다.

softmax의 특성 상, 두 데이터의 합은 1이므로, [y1, y2]는 [y, 1-y] 와 동일하다고 할 수 있다.

 

따라서 sigmoid output [y] 에 대한 binary_crossentropy와

softmax output [y, 1-y] 에 대한 categorical_crossentropy의 결과는 동일하다.

 

(sigmoid는 multi-label, softmax는 multi-class를 구현할 수 있다)

 

 

 

 

 


4. Multi-class classification

 

Multi-class는 다중의 class가 존재할 수 있는 output에서, 하나를 선택하는 것이다.

예를 들어, 꽃의 사진을 입력으로 받아, 꽃의 이름을 예측하는 Task를 들 수 있다.

즉, Output이 나올 수 있는 class의 수는 여러개지만, 오직 한가지의 정답이 존재한다는 것이다.

 

따라서 Multi-class classification은 output class 종류의 수와 상관없이

'Softmax' activation function을 활용하면 매우 쉽게 해결할 수 있다.

 

10가지의 class 중 하나를 선택하는 문제를 푸는 예.

model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])

 

output class 중 하나를 선택하는 softmax를 활용하면 이 문제를 풀 수 없다.

하나를 선택하는 것이므로, categorical_crossentropy를 활용한다.

 

 

 

5. Multi-label classification

 

Multi-label은 Mutli-class와 다르게, 다중의 정답이 동시에 존재할 수 있는 것이다.

예를 들어, 폐에서 다중의 병변 및 증상을 찾아내야 하는 Task인 경우,

한 환자에서 폐렴, 폐결절, 심장비대증 등 다양한 증상이 동시에 존재할 수 있다.

 

 

위 그림의 예는 8개의 label이 존재하고, 각각은 독립적으로 동시에 발생한다.

따라서 이를 해결하기 위해서는 8개의 output을 sigmoid로 output을 해야하며,

동시에 label이 존재할 수 있으므로 binary_crossentropy를 활용하여야 한다.

model.add(Dense(8, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])

 

 

 

 

 

6. Multi-label & different type of output

output이 여러개인데, 만약 특정 값은 classification을 수행하는 것이고,

특정 값은 regression으로 값을 근사하여야 한다면?

 

이는 매우 어려운 문제이다.

 

하나의 layer는 하나의 activation function밖에 가질 수 없다.

따라서 multi-output deep learning model을 구현하여야 한다.

 

나는 하나의 이미지로부터,

5가지의 이미징 Feature 및 환자의 나이, 병변길이를 예측하고자 하였다.

 

하나의 이미지로부터 5가지의 multi-label classification을 수행하는 동시에

2가지의 regression problem을 해결해야 하는 아주 복잡한 문제이다.

ResNet50 = tf.keras.applications.ResNet50(include_top=False, weights='imagenet', input_tensor=None, input_shape=(img_width,img_height,3), pooling=None, classes=1)
x = GlobalAveragePooling2D()(ResNet50.output)

output1 = Dense(5, activation='sigmoid', name='Categorical')(x)
output2 = Dense(2,  activation='linear',  name='Numeric')(x)

model = Model(inputs=ResNet50.input, outputs=[output1, output2])

model.compile(
	loss={
		'Categorical': 'binary_crossentropy',
		'Numeric': 'mean_absolute_error'
	},
	optimizer='adam',
	loss_weights={
		'Categorical': 1.0,
		'Numeric': 0.3
	}
)

 

5가지의 multi-label classification이므로, 5개의 sigmoid outputs을 가지는 layer를 구성하여 binary_crossentropy를 loss로,

2가지의 regression을 수행하므로 2개의 linear outputs을 가지는 layer를 구성하여 mean_absolute_error를 loss로 주었다.

 

다만 MAE에 대한 error가 cross-entropy보다 훨씬 크므로, loss_weight로 loss의 중요도를 조절하였다.

 

다만 keras에서 이미지를 읽으려면, Generator를 활용하여야 하는데,

이 generator의 output이 [y1, y2, y3, y4, y5], [y6, y7] 형태로 nested list로 보내주어야 한다.

이를 위한 custom generator를 구성하는 것 또한 귀찮은 일이다..