Multi-label Classification problem
캐글에서 진행하고 있는 'Plant Pathology 2021 - FGVC8' competition을 진행하다가 찾게 된 유용한 모듈.
해당 대회는 Multi-label Image Classification 문제로 사과나무 잎에 어떤 병에 걸렸는지 판별해야 한다.
제공되는 데이터셋의 label을 보면 문자열로 병명을 제공하고 있으며 건강할 경우 'healthy', 병에 걸려있는 경우 병 이름들을 공백으로 구분하여 보여주고 있다. 즉, 두 개 이상의 병에 걸려있는 경우 'scab frog_eye_leaf_spot complex' 이런 식으로 알려주고 있다.
>>> train_df.head()
'''
image labels
0 800113bb65efe69e.jpg healthy
1 8002cb321f8bfcdf.jpg scab frog_eye_leaf_spot complex
2 80070f7fb5e2ccaa.jpg scab
3 80077517781fb94f.jpg scab
4 800cbf0ff87721f8.jpg complex
'''
그러면 우리는 모델을 학습시켜서 어떤 병에 걸려있는지 알려줘야 하는데 output을 저런 문자열 형식으로 주는 것은 힘들고 [0, 0, 1, 0, 0, 0] -> 'healthy', [1, 1, 0, 0, 0, 1] -> 'scab frog_eye_leaf_spot complex' 이렇게 0과 1로 이루어진 multi-label class output을 주고 문자열로 매핑해주는 것이 필요하다!
그럼 어떻게 할까?
우선 학습을 위해서 반대로 문자열 label을 0과 1로 이루어진 multi-label class형식으로 바꿔주자!
현재 이 대회에서 분류하고자 하는 병(class)은 다음과 같이 분류된다.
['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew', 'rust', 'scab']
처음에 나는 일일이 label을 보면서 해당 class가 있으면 1, 없으면 0을 넣어 만들어 주었는데 다른 분들의 커널을 보다가 scikit-learn에서 이와 관련된 전처리 모듈이 있어서 참고하였다.
MultiLabelBinarizer 적용하기 (scikit-learn)
scikit-learn 공식 문서에서 다음 예제를 확인할 수 있다.
>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> mlb = MultiLabelBinarizer()
>>> mlb.fit_transform([(1, 2), (3,)])
array([[1, 1, 0],
[0, 0, 1]])
>>> mlb.classes_
array([1, 2, 3])
아주 편하게도 MultiLabelBinarizer 모듈을 사용하게 되면 알아서 class의 종류(개수) 인식과 multi-label encoding을 수행한다.
따라서 대회에 적용시켜본다면 label들을 split 하여 저장한 다음 이 모듈에 넣어주기만 하면 된다.
>>> train_df['labels'] = [x.split(' ') for x in train_df['labels']]
>>> train_df.head()
'''
image labels
0 800113bb65efe69e.jpg [healthy]
1 8002cb321f8bfcdf.jpg [scab, frog_eye_leaf_spot, complex]
2 80070f7fb5e2ccaa.jpg [scab]
3 80077517781fb94f.jpg [scab]
4 800cbf0ff87721f8.jpg [complex]
'''
>>> mlb = MultiLabelBinarizer()
>>> labels = mlb.fit_transform(train_df['labels'].values)
>>> labels
array([[0, 0, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1],
...,
[0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0]])
>>> mlb.classes_
array(['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew',
'rust', 'scab'], dtype=object)
이렇게 만들어진 multi-label class 값을 저장하여 딥러닝 모델의 target 값으로 이용하면 된다 :)
>>> new_train_df = pd.DataFrame(columns=mlb.classes_, data=labels)
>>> new_train_df.insert(0,'image',train_df['image'])
>>> new_train_df.head()
'''
image complex frog_eye_leaf_spot healthy powdery_mildew rust scab
0 800113bb65efe69e.jpg 0 0 1 0 0 0
1 8002cb321f8bfcdf.jpg 1 1 0 0 0 1
2 80070f7fb5e2ccaa.jpg 0 0 0 0 0 1
3 80077517781fb94f.jpg 0 0 0 0 0 1
4 800cbf0ff87721f8.jpg 1 0 0 0 0 0
'''
'Deep Learning > Pytorch' 카테고리의 다른 글
[개발팁] 'MultilabelStrarifiedKFold' : Multi-label classification 에 적용 가능한 strarification cross validator (0) | 2021.04.21 |
---|---|
num_workers & pin_memory in DataLoader (0) | 2021.04.18 |
[개발팁] torch.nn 과 torch.nn.functional 어느 것을 써야 하나? (0) | 2020.08.07 |
[Label Smoothing] 요약 정리 (0) | 2020.07.28 |
[NVIDIA APEX] Amp에 대해 알아보자 (Automatic Mixed Precision) (6) | 2020.07.14 |