CastleJo의 개발일지

Image Classification - 마지막 시도

|

다시 처음으로

결국 많은 실패끝에 다시 처음으로 되돌아왔다.

돌아오고나서 든 생각과 여러가지 토론을 거친 결과 Miss-Labeling 된 데이터들이 많다는것이다.

그래서 일단 EDA부터 다시 시작했다.

EDA

팀원들과의 협업을 할 때, Input 데이터는 모두 용량상 로컬 폴더 안에 있었다.

그래서 모두의 데이터를 바꾸기엔 좀 귀찮기도하고.. 그래서 런타임 내에서 잘못된 데이터가 들어온다면 바꾸는 코드를 Dataset 안에 집어넣었다.

해당 코드는 다음과 같다.

# label_changer.py

from enum import Enum

class IncorrectLabel(int, Enum):
	F2M = 0
	M2F = 1
	INCORRECT2NORMAL = 2

incorrect = {
	'006359': IncorrectLabel.F2M, 
	# 생략...
}

class StateChanger:
	def __init__(self, state:IncorrectLabel):
		self.state = state
	
	def __call__(self, file_name, gender, age):
		if self.state == IncorrectLabel.F2M:
			return self.stateF2M(file_name, gender, age)
		if self.state == IncorrectLabel.M2F:
			return self.stateM2F(file_name, gender, age)
		if self.state == IncorrectLabel.INCORRECT2NORMAL:
			return self.stateI2N(file_name, gender, age)
		
		raise "여긴 또 왜왔냐"

	def stateF2M(self, file_name, gender, age):
		return (file_name, "male", age)

	def stateM2F(self, file_name, gender, age):
		return (file_name, "female", age)

	def stateI2N(self, file_name, gender, age):
		realName = file_name
		if file_name == "incorrect_mask":
			realName = "normal"
		if file_name == "normal":
			realName = "incorrect_mask"

		return (realName, gender, age)


def labelChanger(profile, _file_name, gender, age, _file_names):
	mask_label = _file_names[_file_name]
	manNum = profile.split('_')[0]

	if manNum in incorrect.keys():
		changer = StateChanger(incorrect[manNum])
		(_file_name, gender, age) = changer(_file_name, gender, age)
		mask_label = _file_names[_file_name]
	
	return (mask_label, gender, age)

해당 labelChanger() 메소드를 Dataset의 init 안에 넣어놔 라벨 자체를 틀어놨다.

이렇게 총 18900장 중에 100장정도를 바꿨고, 그 결과 2%정도의 정확도 상승을 보였다.

Augmentation

상당히 편향되어있는 데이터셋에서 한계를 극복하는 방법이었다.
대부분 단색 배경과 옷, 그리고 거의 동일한 포즈인 데이터셋이였다.
따라서 제일 먼저 든 생각은 Crop이다.

Crop

뭐 일단 결과적으로 말하면, 효과가 미미했다.
아무래도 얼굴을 인식하는지라 배경과 옷을 모두 지우는 매우 합리적인 추론을 했다.
이에 대해서도 따로 오픈소스로 열린 모델을 사용했고, 성공적으로 얼굴만을 추출했었는데 아무리해도 정확도가 나아지지 않았다.
ResNet50을 사용하면서는 이미지를 크롭하지 않는게 더욱 정확도가 높았다. 그 이유에 대해 곰곰히 생각해봤는데, 머리카락부분을 대부분 날려버려 남,여를 구분하는게 힘들었지 않는가. 였다

Contrast

나이에 따라 부각되는 특성이 뭐가있을까? 생각하다 딱 생각난게 있었다.
바로 주름이다.
그렇다면 주름을 부각시키는 법은 무엇이있을까 생각해보니, 대비를 올리면 됐다.
육안으로 확인해본 결과 주름이 꽤나 부각이 되었으며 이거다 하고 훈련에 들어갔다.

그 결과, 정확도가 떨어졌다. ㅠㅠ
이에 대해서는 원인 파악을 아직 하지 못하였다…

Flip

사실, 유효할거라고 생각하지 못했다.
솔직히 말하자면 좌우반전만을 하려했는데 코드를 잘못쳐서 상하반전까지 적용되었다.

그런데 이상하게도 상하반전까지 적용한 방법이 정확도가 무려 4%나 높게나왔다.

그래서 이유를 곰곰히 생각해봤는데, 다음과 같다.

  • 모든 데이터는 배경, 같은구도로 구성되어있다.(심지어 검증세트까지)
  • Flip을 하지 않으면, 특성에 배경이 비교적 많이 관여되는것을 보았다.
  • 하지만 상하반전을 하니, 배경이 어떻던 얼굴에만 집중한다는 결과를 보았다.
  • 따라서 ResNet50으로 훈련할 시 Flip된 데이터가 전혀 Input으로 들어올 가능성이 없다고해도 충분히 채용을 해볼만 하다고 결론지었다.

마무리…

완성된 모델의 특징은 다음과 같다.

  • ResNet50을 사용했다.
  • Fine-Tuning을 실행하였다.
  • Miss-Labeling 된 데이터를 최대한 잡아냈다.
  • Flip Augmentation을 적용하였다.(Albumentation 라이브러리 좋다)

뭐 여러가지를 고려했지만, 결국 처음으로 돌아와버렸다. 아직 경험치가 많이 부족하다고 생각했지만, 재밌는 경험이였고 다음에 기회가 된다면 더 열심히 해야겠다고 결심했다.