들어가기전
프로젝트를 진행하면서 인공지능 파트를 맡게됐다.(사실 백엔드 하고 싶어서 백엔드 한다고 했는데 어쩌다 보니 인공지능 간건 안비밀....)
팀원 전체가 인공지능에 대해 잘 아는 사람이 없었고, 나도 마찬가지로 인공지능을 실제로 구현해본 경험은 없었다. 그래서 사실 기대반 걱정반으로 인공지능을 맡게 되었다.
인공지능을 총 3명의 인원이 맡게 되었다. 기획단계에서 모델을 학습할 수 있는 데이터셋을 구하는 것이 중요하기 때문에 데이터셋을 제공해주는 사이트를 여러 곳 찾아봤고, 그 중에서 우리는 AI허브에 있는 반려동물 질환 이미지 데이터셋을 이용하기로 했다.
해당 데이터셋 안에 분류 모델과 그와 관련된 명세서가 있었기 때문에 처음에는 그것를 따라하면서 감을 익히려고 했다. 처음에는 GPU서버가 없는지 알고 로컬에서 학습을 시켰었는데 알고보니 GPU서버가 제공이 된다고 해서 GPU서버에서 학습을 시키긴 했다.
하지만 공용으로 사용하는 서버이다보니 터미널에서 아무런 동작을 하지 않으면 서버가 자동으로 꺼졌다. 그래서 문의도 넣어보고 했는데 자꾸 꺼져서 학습이 중간에 중단되는 현상이 발생했다. 그리고 공용 서버라서 sudo 권한을 주지 않았다.... 권한달라고 하면 본인들이 해주겠으니 요청하라는 답변이 달렸다....
제일 답답했던건, 문의를 남기면 빠르면 하루고 늦으면 하루 넘게 답변이 달렸다. 그러나 우리는 시간이 정해져있고, 현상이 해결되지 않으면 아무것도 못해서 할 수 있는게 없었다. 그래서 결국에 이렇게는 안되겠다 싶어서 데이터 셋을 가지고 직접 모델 학습하는걸 다른 블로그를 참고해서 하던지, 티처블 머신에서 만들었던 모델을 활용하던지 하기로 했다.
티처블 머신에는 그 전에 모델 정확도를 비교하기 위해서 여러개 만들어놓은게 있었다. 그래서 우선은 직접 모델 학습하는게 안될 것을 대비하려고 했다.
그리고 명세서에서 따라한대로 학습을 하면 모델 파일이 checkpoint 형태로 나왔다. 이 파일을 활용해보려고 했으나 도저히 어떻게 사용하는지 모르겠고, 비슷한 게시글이 있어도 그 게시글에는 있는 파일이 명세서 따라한대로 한 산출물에는 보이지 않아서 너무 막막했다.
그래서 모델 학습하는 사람 2명과 티처블 머신 모델 활용하는 방법 찾는 사람 1명 나눠서 다시 프로젝트를 진행했다.
나는 모델 학습하는 것을 맡아서 진행했다.
처음에는 이미지 분류 모델 학습하는 예제 찾기만 하면 되니까 쉬울 줄 알았는데, 우선 파이썬도 한지 오래됐고, 인공지능 관련된 것을 하나도 몰랐기 때문에 이미지 불러오는 것부터 해맸다.
다른 예제들 보면 보통 다들 keras에 있는 강아지 vs 고양이 데이터나 숫자 데이터, 의류 데이터 등을 가져와서 사용한다.
하지만 우리는 다른 곳에서 가져온 데이터, 즉 우리가 필요한 데이터로 학습을 시켜야했기 때문에 그것과 비슷한 예제를 찾아야했다. 그래서 찾은 곳들이 아래 링크 2개 였다.
(이 분들 아니였으면 프로젝트 완성 못할 뻔 했다..........정말 감사합니다.....)
본문
이제 CNN을 사용해서 모델 학습하는 방법을 정리하려고 한다.
우선 이미지 경로와 클래스를 먼저 선언해줬다.
img_folder_path='../Model/Skin/classification/workspace/data/dog/bbox/Symptom/'
categories=["A1", "A2","A3","A4","A5","A6"]
num_classes = len(categories)
그리고 이제 이미지 전처리 과정을 진행해준다.
우선 나는 학습 데이터가 "Sympotm/질병종류/_bbox" 폴더 별로 이미지가 있었기 때문에 그 경로는 따로 설정해줬다.
image_w = 28
image_h = 28
X=[]
Y=[]
for idex, categorie in enumerate(categories):
label = [0 for i in range(num_classes)]
label[idex] = 1
image_dir = img_folder_path + categorie + '/_bbox/'
for top, dir, f in os.walk(image_dir):
for filename in f:
img = cv2.imread(image_dir+filename)
img = cv2.resize(img, None, fx=image_w/img.shape[1], fy=image_h/img.shape[0])
X.append(img/256)
Y.append(label)
# print(X)
X = np.array(X)
Y = np.array(Y)
X_train, X_test, Y_train, Y_test = train_test_split(X,Y)
그러면 이제 X_train, X_test, Y_train, Y_test 안에 이미지와 라벨 데이터가 담기게 된다.
그리고 이제 모델을 선언해주고 학습해준다.
X_train = np.append(X_train,X_test, axis=0)
Y_train = np.append(Y_train,Y_test, axis=0)
model = Sequential()
model.add(Convolution2D(16, 3, 3, padding='same', activation='relu', input_shape=X_train.shape[1:]))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(64, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2), padding='same'))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation = 'relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes,activation = 'softmax'))
model.compile(loss='binary_crossentropy',optimizer='Adam',metrics=['accuracy'])
Datetime = datetime.datetime.now().strftime('%m%d_%H%M')
epoch_num = 50; # EPOCH 설정
RESULT_FILE_DIR=f"Model_1_EPOCH_{epoch_num}" #모델 저장할 폴더
modelpath=f"{RESULT_FILE_DIR}/Model.h5" #모델이름
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='loss', verbose=1, save_best_only=True)
early_stopping_callback = EarlyStopping(monitor='loss', patience=100)
# Learning and save models
hist = model.fit(X_train, Y_train, validation_split=0.1, epochs=epoch_num, batch_size=10, verbose=0, callbacks=[early_stopping_callback,checkpointer])
마지막으로 나는 정확도와 손실 정도를 그래프 이미지로 저장하고 싶었기 때문에 아래와 같이 코드를 작성해줬다.
# 6 훈련 과정 시각화 (정확도)
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Model accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend(['Train', 'Test'], loc='upper left')
save_path = os.path.join(os.path.expanduser(RESULT_FILE_DIR), 'accuracy.png')
plt.savefig(save_path)
plt.show()
plt.cla()
# 7 훈련 과정 시각화 (손실)
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Model loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(['Train', 'Test'], loc='upper left')
save_path = os.path.join(os.path.expanduser(RESULT_FILE_DIR), 'loss.png')
plt.savefig(save_path)
plt.show()
plt.cla()
위와 같이 코드를 작성하면 이제 모델 학습이 진행되고, 위에서 작성해둔 폴더안에 산출물이 저장이 된다.
다음과 같이 결과물이 잘 나온 것을 볼 수 있다.
처음에 적용했을때 정확도가 많이 낮은 편이라서 현재는 InceptionResNetV2, VGG16 등의 모델을 적용해보고 있다.
오류 모음
정말정말 많은 오류를 만났다....뭐만 할려고 하면 오류였고, 다 기록은 못하지만 몇개만 기록해보려고 한다.
오류1. ValueError: `logits` and `labels` must have the same shape, received ((None, 1) vs (None, 6)).
ValueError: `logits` and `labels` must have the same shape, received ((None, 1) vs (None, 6)).
이 오류는 모델의 output과 클래스의 개수가 동일 하지 않아서 발생하는 문제였다.
VGG16 모델을 가져와서 사용하는데
model_tr = Sequential([
model,
Flatten(),
Dense(64, activation='relu'),
Dense(1, 'sigmoid')
])
다음과 같이 모델을 정의했다. 그런데 마지막에 Dense(1, 'sigmoid') 로 끝나는데 내가 하려는 클래스의 개수는 6이기 때문에 오류가 발생한 것이다.
그래서 마지막 코드를 다음과 같이 수정해주면 된다.
model_tr = Sequential([
model,
Flatten(),
Dense(64, activation='relu'),
Dense(num_classes, 'sigmoid') #num_classes는 클래스 개수
])
오류2. ValueError: Input size must be at least 32x32; Received: input_shape=(16, 16, 3)
ValueError: Input size must be at least 32x32; Received: input_shape=(16, 16, 3)
이거는 해석한 그대로 모델 사용할 때 최소 사이즈보다 input_shape사이즈가 작아서 발생한 문제이다. 마지막에 있는 옵션인 input_shape가 최소 (32, 32, 3) 으로 설정해줘야한다.
또한 추가적으로 input_shape에 들어가는 숫자는 이미지 전처리할 때 사이즈 숫자와 동일해야한다.
위 코드를 보면 나는 28로 해줬기 때문에 input_shape도 원래는 (28, 28, 3) 이어야 한다. 하지만 최소 32보다 커야한다고 했으니 그건 이제 사용자가 원하는 대로 설정해주면 된다.
마무리
그동안 블로그에 글도 안올렸는데 갑자기 파이썬과 인공지능이라니.....내가 생각해도 웃긴걸...?
하면서 느낀점은 인공지능은 매우 어렵다는 것이다....사실 그동안 많은 블로그의 글과 설명들을 보았는데 이해도 잘 안되고 어려웠다. 처음 2-3주는 거의 찾고 오류 해결하고 다른 방법으로 시도해보고 반복이였다. 그래서 사실 프로젝트가 잘 마무리 될 수 있을지에 대한 의문도 들었다. 너무 답답하고 길이 안보여서...
하지만 마지막에 이렇게 다른 방안으로 돌려서 해결하게 됐고, 다행히도 남은 일들은 이제 api만들어서 예측 값을 넘겨주는 일만 남았기 때문에 완성을 할 수 있을 것이라고 생각한다.
같이 고생한 팀원에게 수고했다고 말하고 싶다...진짜 고생많았따ㅠㅠㅠ
'개발 공부 > 기타' 카테고리의 다른 글
[Github] ReadMe 리드미 꾸미기 (및 매우 소소한 팁들) (1) | 2022.03.01 |
---|