본문 바로가기
DEV/Web 개발

Web 개발 :: 머신러닝 프로젝트 SA_TIL#33

by 올커 2022. 10. 20.

■ JITHub 개발일지 33일차

□  TIL(Today I Learned) ::

파이썬 머신러닝_ResNet을 활용한 이미지 검출

    · 사진에서 과일을 인식시키는 머신러닝 모델을 생성하기 위해서 Keras의 ResNet50을 활용하여 모델학습을 시켰다. 이미 훈련된 모델을 쓰고자 아래와 같이 진행해보았다.

  tensorflow부터 keras, 필요한 모듈들은 모두 임포트해온다. ResNet50도 keras에 포함되어있었다.

import tensorflow as tf
from keras.applications.vgg16 import decode_predictions
from keras.applications.vgg16 import preprocess_input
from keras.preprocessing import image
from keras.applications import ResNet50

  머신러닝을 위한 모듈들도 임포트해온다.

from PIL import Image 
import seaborn as sns
import pandas as pd 
import numpy as np 
import os

  훈련된 모델은 아래와 같이 weights=imagenet으로 로드했다.

resnet50 = ResNet50(weights='imagenet', include_top=False)

  만들어진 모델에 이미지를 전달하고, 각 특징들을 식별한다.

def _get_features(img_path):
    img = tf.keras.utils.load_img(img_path, target_size=(224, 224))
    img_data = tf.keras.utils.img_to_array(img)
    img_data = np.expand_dims(img_data, axis=0)
    img_data = preprocess_input(img_data)
    resnet_features = resnet50.predict(img_data)
    return resnet_features
    
img_path = "./image.jpg"
resnet_features = _get_features(img_path)

  추출된 형상은 resnet_filename에 저장된다. ML모델에 사용하기 위해 flatten, squeeze하여 배열한다.

  머신러닝 모델에 사용하기 위해서는 가져온 형상을 반죽처럼 늘리고 줄이고 맞춰주어야 하나보다. 이 모델만 저급 모델이라 그런건지, 모든 머신러닝에서는 동일하게 폼을 맞춰주어야 하는지 궁금했다.

features_representation_1 = resnet_features.flatten()
features_representation_2 = resnet_features.squeeze()

print ("Shape 1: ", features_representation_1.shape)
print ("Shape 2: ", features_representation_2.shape)

  이제 데이터셋을 준비하였다. 아래처럼 basepath에 각 과일별 폴더가 있고 내부에 test할 사진들이 있었다.

  각각의 과일별 class를 구분해주는 작업이다.

basepath = "./imgs_fruits360/Training/"
class1 = os.listdir(basepath + "Strawberry/")
class2 = os.listdir(basepath + "Lemon/")
class3 = os.listdir(basepath + "Mango/")
class4 = os.listdir(basepath + "Banana/")
...

  각 클래스 중 일부의 사진을 사용하기 위해 data라는 딕셔너리에 넣어주었다. 이 때 각 과일 클래스의 한장씩을 test라는 key에 넣어주었다.

data = {"Strawberry" : class1[:10],
        "Lemon" : class2[:10],
        "Mango" : class3[:10],
        "Banana" : class4[:10],
		...

        'test': [class1[11],
                 class2[11],
                 class3[11],
                 class4[11],
				...
                 ]}

  데이터셋에는 각 과일들의 위치, 각도등이 조금씩 변화된 모습으로 찍혀있다. 

  (사실 데이터셋이 너무 맘에들지 않았다. 예를들어 포도라고 하면 포도송이가 아닌 포도알이 있거나, 망고는 초록색 망고가, 토마토는 찌그러져있고...)

  이 데이터셋을 활용해 전이학습을 할 수 있다. 아래와 같이 feature에는 각 항목별 리스트를 만든다.

features = {"Strawberry" : [],
            "Lemon" : [],
            "Mango" : [],
            "Banana" : [],
			...    
            "test": []}

  각 이미지들을 판별하고, one-hot-encoding된 이름을 원래 이름으로 라벨링한다.

testimgs = []
for label, val in data.items():
    for k, each in enumerate(val):        
        if label == "test" and k == 0:
            img_path = basepath + "/Strawberry/" + each
            testimgs.append(img_path)
        elif label == "test" and k == 1:
            img_path = basepath + "/Lemon/" + each
            testimgs.append(img_path)
        elif label == "test" and k == 2:
            img_path = basepath + "/Mango/" + each
            testimgs.append(img_path)
        elif label == "test" and k == 3:
            img_path = basepath + "/Banana/" + each
            testimgs.append(img_path)
            ...
        else: 
            img_path = basepath + label.title() + "/" + each
        feats = _get_features(img_path) 
        features[label].append(feats.flatten())
        
        
dataset = pd.DataFrame()
for label, feats in features.items():
    temp_df = pd.DataFrame(feats)
    temp_df['label'] = label
    dataset = dataset.append(temp_df, ignore_index=True)
dataset.head()


y = dataset[dataset.label != 'test'].label
X = dataset[dataset.label != 'test'].drop('label', axis=1)

  각 테스트 결과를 플롯으로 사진과 이름을 보여준다.

model = MLPClassifier(hidden_layer_sizes=(100, 10))
pipeline = Pipeline([('low_variance_filter', VarianceThreshold()), ('model', model)])
pipeline.fit(X, y)

print ("Model Trained on pre-trained features")


preds = pipeline.predict(features['test'])

f, ax = plt.subplots(1, 4)
for i in range(4):
    ax[i].imshow(Image.open(testimgs[i]).resize((200, 200), Image.ANTIALIAS))
    ax[i].text(10, 180, '%s' % preds[i], color='k', backgroundcolor='red', alpha=0.8)
plt.show()

 

   1) 문제점 : 어떤 문제가 있었는지? 

    · 일단 학습을 통해 모델도 만들고, 테스트 셋으로 검증도 되는것을 확인했다. (정확도는 높지 않지만..)

    · 그렇지만 문제는 사용할 데이터셋도 불량할 뿐더러, 원하는 과일의 종류로 라벨링을 다 해주어야 했다.

   2) 몰랐던 점 및 알게된 점

    · 원하는 데이터셋으로 모델을 만들기 위해서는 정말 괜찮은 데이터셋을 찾거나, 데이터셋을 만들거나, 암튼 필요한 조건들이 많다. 

    · 데이터 라벨링을 직접 해보기까지 했다. 예전에 데이터 라벨링 알바도 한다고 들은 적이 있다. 왜 알바가 가능한지 알 것 같다.

    · ResNet50으로 위의 코드를 사용하면 Object Classification을 사용한다. 이전에 Yolov5를 사용할 때에는 Object Detection이 되었었고, 우리가 사용할 사진 데이터에는 여러 과일 재료가 들어갈 수 있음을 감안하여 Yolov5로 변경하여 다시 모델을 학습하고자 하였다.


   3) 해결 : 어떻게 해결했는지?

    · 결과적으로 해당 데이터셋과 ResNet을 사용하지 않기로 했다. Yolov5로 진행해볼 예정.

 

반응형

댓글