336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

세 번째 프로젝트 순서

1. 식물 병충해 자료 파일분류
2. CNN 모델링
3. 이미지화
4. CNN, AlexNet, VGG-16 모델 평가


예전에 네이버 블로그를 하듯이 글을 자유롭게 쓰고 싶은데, 혹시나 틀릴까 하는 마음에 쉽게 글이 작성이 되지 않는다. 너무나 쉽게 생각을 한 것이 아닌가 싶기도 하지만.. 그래도 팀프로젝트 5개 + 현재하고 있는 파이널 프로젝트 관련된 글을 작성하려고 한다.

이번에는 실패했던 시각화에 대한 내용이라 너무 관심 있게 보지는 말아주셨으면 한다. (부끄러우니까)

CNN 모델링을 했을 때 정확도가 90퍼센트 이상이 나왔지만 이를 어떻게 하면 더 개선시킬 수 있을까에 대한 고민을 많이 했다. 그러다가 생각한 것이 학습에 필요한 데이터는 전체 사진이 아닌 식물의 사진만 중요하지 않을까? 그래서 배경을 제외하고 학습을 해보기로 했다.

-배경과 식물 분리하는 mask
-sharpen 값을 줘서 병충해가 있는 데이터는 조금 더 부각이 되게


여러 예제들을 찾아보다가 이거다! 하는 예제가 있어서 처음에 단순히 따라하는 식으로 해봤다! 이건 그냥 너무 쉽게 되겠는 걸?






결과는 참담했다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#배경과 분리하기 위해서 hsv 값 조정
def create_mask_for_plant(image):
    image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
 
    sensitivity = 30
    lower_hsv = np.array([60 - sensitivity, 10050])
    upper_hsv = np.array([60 + sensitivity, 255255])
 
    mask = cv2.inRange(image_hsv, lower_hsv, upper_hsv)
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
    
    return mask
 
#비트연산 and 모든 색이 같을 때만 색 표현
def segment_plant(image):
    mask = create_mask_for_plant(image)
    output = cv2.bitwise_and(image, image, mask = mask)
    return output
 
#샤픈, 특징을 조금더 부각시키게
def sharpen_image(image):
    image_blurred = cv2.GaussianBlur(image, (00), 3)
    image_sharp = cv2.addWeighted(image, 1.5, image_blurred, -0.50)
    return image_sharp
cs

sensitivity를 어떻게 하느냐에 따라서 결과값이 많이 차이가 났다. 위의 경우가 1을 뒀을 때고, 아래의 경우가 30일 때 실행을 했는데 단점이 배경 없이 잎만 찍은 데이터의 경우 분간이 제대로 되지가 않았다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
%matplotlib inline
import os
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import cv2
import numpy as np
from glob import glob
import seaborn as sns
 
image = cv2.imread('8_9_2.jpg')
 
image_mask = create_mask_for_plant(image)
image_segmented = segment_plant(image)
image_sharpen = sharpen_image(image_segmented)
 
fig, axs = plt.subplots(14, figsize=(2020))
axs[0].imshow(image)
axs[1].imshow(image_mask)
axs[2].imshow(image_segmented)
axs[3].imshow(image_sharpen)
cs

그래도 이전보다는 배경과 잎의 경계가 뚜렷하게 나눠지는 것을 확인할 수 있었다. 그런데도 문제가 되는 부분은 잎을 나눈데 있어서 hsv 값을 비슷하게 판단해서인지? 식물의 잎도 같이 사라지는 마술을 보여줬다. 병충해가 있어서 저렇게 빵꾸가 뚤렸다고 생각하면 좋겠지만, 병충해가 있는 부분은 중간 아래부분이다.

라이트룸이나 사진 편집을 할 때, 어떤 식으로 특정 색만 색깔을 남길까 생각을 해봤을 때.. hsv 전체 색 공간이 아닌 말 그대로 특정색만 추출하면 되는데 왜 이생각을 못 했을까 하고 무릎을 탁 쳤다. 그래서 초록색을 가장 잘 나타낼 수 있는 값들을 조절해봤다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np 
import cv2 
img_color = cv2.imread('4_7_5.jpg'
 
img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV) # cvtColor 함수를 이용하여 hsv 색공간으로 변환 
lower_green = (03030)
upper_green = (80255255
img_mask = cv2.inRange(img_hsv, lower_green, upper_green) #hsv 색공간 전체가 아닌 지정한 범위 내의 
img_result = cv2.bitwise_and(img_color, img_color, mask = img_mask) # 바이너리 이미지를 마스크로 사용하여 원본이미지에서 범위값에 해당하는 부분을 획득 
 
 
fig, axs = plt.subplots(13, figsize=(2020))
axs[0].imshow(img_color) 
axs[1].imshow(img_mask) 
axs[2].imshow(img_result) 
cs

이정도면 나름 선방한 결과였다. 하지만 이 이미지들을 다 다시 저장시키고, 식물마다 톤이 다르고, 사진 찍은 곳 조명이 달라서 lower_green과 upper_green을 일일이 다 조정해야 한다는 치명적인 단점이 있어서 실패를 했다.

그래도 어떤 식으로 사진과 배경을 분리하고, 샤픈을 줘서 CNN이 사진의 특징을 학습할 때 조금 더 도움을 줄 수 있지 않을까 하는 생각이 든다.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

세 번째 프로젝트 순서 

 

1. 식물 병충해 자료 파일분류

2. CNN 모델링

3. 이미지화

4. CNN, AlexNet, VGG-16 모델 평가




쉼호흡부터 한 번 후~ 하~ 파이썬 팀프로젝트 당시에도 내용이 어려웠는데, 지금 다시 봐도 내용이 어렵다. 그래도 블로그로 글을 쓰면서 다시 정리한다는 생각으로 일단 간단하게 정리를 해봤다. 

 

 

인공지능 : 인간의 지능을 기계로 구현한 것

머신러닝 : 인간이 개발한 알고리즘을 컴퓨터 언어를 통해 기계에게 학습. 데이터로부터 스스로 학습을 통해 데이터를 가장 잘 표현하는 규칙, 패턴을 찾는 것(함수로 정의하는 과정 - x와 y관계)

딥러닝 : 인간의 뇌 신경망을 모방한 인공 신경망, 분류 예측 등의 머신러닝 수행  (입력층과 출력층 사이에 여러 층을 거쳐서 학습)

 

지도학습 : 입력 데이터(feature, 독립변수)와 출력데이터(class, target, 종속변수)를 이용해서 학습 – 분류, 회귀

비지도학습 : 입력 데이터를(feature)를 이용한 학습 – 군집

강화 학습 : 학습 결과에 대한 보상이 주는 방식으로 학습

 

train data : 모델 구축시 사용되는 데이터 (학습)

test data  : 구축된 모델 검증하는데 사용 (검증)

 

케라스(keras) ㅡ 저차원의 딥러닝 라이브러리를 래핑한 고차원의 라이브러리

sequential – 딥러닝의 구조를 한 층 한층 순차적으로 층을 쌓은 신경망 모델

dense – 신경망 모델에 포함된 완전 연결층 (각 층이 각각 어떤특성을 가질지 옵션을 설정)

activation – 다음 층으로 어떻게 값을 넘길지 결정하는 부분(relu, sigmoid, softmax 등)

loss – 한 번 신경망이 실행될 때마다 오차 값을 추적하는 함수 (mse, rmse 등)

optimizer – 오차를 어떻게 줄여 나갈지 정하는 함수 (adam, 경사하강법, 확률적 경사하강법)

input_shape – 입력 데이터의 형태

epoch - 주어진 데이터를 신경망 모델에서 한 번 훈련하는 단위

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from keras.models import Sequential
from keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.layers import Dropout, Activation, Dense
from keras.layers import Flatten, MaxPooling2D
from keras.layers import Conv2D
from keras.models import load_model
from keras.optimizers import Adam
from tensorflow.keras.layers import BatchNormalization
import os
import numpy as np
 
# dataset 불러오기
if not os.path.exists("./model/"):
    os.mkdir('./model/')
X_train, X_test, Y_train, Y_test = np.load('./data/img_data.npy', allow_pickle=True)
 
# 기본 설정
categories = list(str(i) for i in range(20))
EPOCHS = 30
BS = 32
INIT_LR = 1e-3
n_classes = len(categories)
 
 
# CNN 모델
model = Sequential()
model.add(Conv2D(32, (33), padding="same", input_shape=X_train.shape[1:], activation='relu'))
model.add(MaxPooling2D(pool_size=(22)))
model.add(Dropout(0.2))
 
model.add(Conv2D(64, (33), padding="same", activation='relu'))
model.add(MaxPooling2D(pool_size=(22)))
model.add(Dropout(0.2))
 
model.add(Conv2D(64, (33), padding="same", activation='relu'))
model.add(MaxPooling2D(pool_size=(22)))
model.add(Dropout(0.25))
 
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
 
model.add(Dense(n_classes, activation='softmax'))
 
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
 
 
# 모델 요약
print(model.summary())
 
# 모델 학습
# opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
# model.compile(loss="binary_crossentropy", optimizer=opt,metrics=["accuracy"])
# print("트레이닝 ")
 
#EarlyStopping
model_dir = './model'
model_filepath = "model/se_cnn.h5"
if os.path.exists(model_filepath):
    model.load_weights(model_filepath)
else:
    model_path = model_dir + '/multi_img_classification.model'
    checkpoint = ModelCheckpoint(filepath=model_path, monitor='val_loss', verbose=1, save_best_only=True)
    early_stopping = EarlyStopping(monitor='val_loss', patience=6)
 
    model.fit(
        X_train,
        Y_train,
        batch_size=BS,
        validation_data=(X_test, Y_test),
        steps_per_epoch=len(X_train) // BS,
        epochs=EPOCHS, verbose=1,
        callbacks=[checkpoint, early_stopping]
    )
    model.save_weights(model_filepath)
 
cs

지속적으로 층을 바꿔가면서 모델링을 진행했다. 솔직히 어떤 부분에서 무엇을 바꿔야 하는지 이해는 쉽지 않았다. 같은 모델을 돌린다고 해도 train, test 데이터가 바뀌어서 학습이 진행되기 때문에, 데이터 중에 인간도 판별하기 힘든 데이터가 많이 섞여 있으면 정확도가 계속 떨어졌다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#모델 시각화
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)

#모델 정확도
plt.rc('font',family='Malgun Gothic')
plt.plot(epochs, acc, 'b', label='Training accurarcy')
plt.plot(epochs, val_acc, 'r', label='Testing accurarcy')
plt.title('학습과 훈련 정확도')
plt.legend()
plt.figure()
 
#모델 손실
plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, val_loss, 'r', label='Testing loss')
plt.title('학습과 훈련 손실')
plt.legend()
plt.show()
cs

신기한 부분은 모델을 돌리게 되면 정확도가 90%가 넘는게 쉽지 않은데... 데이터 자체가 양질의 데이터고 분류가 잘 돼서 더 잘 학습이 되는 것으로 보인다. 다음에는 시각화와 어떻게 하면 정확도를 높일 수 있을지에 대한 고민이 담긴 글이다. 실패는 했지만 그래도 어떻게 하면 계선을 할 수 있을까 많은 고민을 했다.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

세 번째 프로젝트 순서 

 

1. 식물 병충해 자료 파일분류

2. CNN 모델링

3. 이미지화

4. CNN, AlexNet, VGG-16 모델 평가


언어 : Python

패키지 : Tensorflow, Keras, NumPy, Maplotlib

툴 : Colab, PyCharm, Jupyter Notebook

 

여러가지 주제를 가지고 고민을 하다가 딥러닝을 제대로 배우지도 않은 상태에서 진행을 하려고 해서 쉽지 않았다. 그래서 이런 저런 자료들을 찾아보다가 '정보통신산업진흥원 주최  2020 인공지능 문제해결 경진대회 예선 문제' 데이터셋이 있어서 배운 것을 적용해보는 시간을 가지려고 했다.

 

 

 

train 데이터가 16000개, test 데이터가 3997개로 구성되어 있었다. 하지만 test 데이터는 라벨링이 되어있지 않아서, 모델을 학습시킨다고 해서 딥러닝 모델이 얼마나 좋은지 성능을 평가할 수 없었다. 대회 자체가 워낙 폐쇄적이라서 현재 데이터도 이미 가지고 있던 팀원이 있어서 구할 수 있었다. 직접 전화도 해봤지만 정답을 알려주긴 어렵다는 말을 들었다. 그래서 추후에 데이터를 따로 수집을 했다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
plant_label = ["Apple""Blueberry""Cherry_(including_sour)""Corn_(maize)",
              "Grape""Orange""Peach""Pepper,_bell""Potato""Raspberry",
              "Soybean""Squash""Strawberry""Tomato"]
 
disease_label = ["Apple_scab""Bacterial_spot""Black_rot""Cedar_apple_rust",
                 "Cercospora_leaf_spot_Gray_leaf_spot""Common_rust_",
                 "Early_blight""Esca_(Black_Measles)""Haunglongbing_(Citrus_greening)",
                 "Late_blight""Leaf_Mold""Leaf_blight_(lsariopsis_Leaf_Spot)",
                 "Leaf_scorch""Northem_Leaf_Blight""Powdery_mildew""Septoria_leaf_spot",
                 "Spider_mites_Two-spotted_spider_mite""Target_Spot",
                 "Tomato_Yellow_Leaf_Curl_Virus""Tomato_mosaic_virus""healthy"]
 
combined_labels = ["Corn_(maize)_Common_rust_""Corn_(maize)_healthy""Grape_Black_rot",
                   "Grape_Esca_(Black_Measles)""Grape_Leaf_blight_(lsariopsis_Leaf_Spot)",
                   "Orange_Haunglongbing_(Citrus_greening)""Pepper,_bell_Bacterial_spot",
                   "Pepper,_bell_healthy""Potato_Early_blight""Potato_Late_blight",
                   "Soybean_healthy""Squash_Powdery_mildew""Tomato_Bacterial_spot",
                   "Tomato_Early_blight""Tomato_Late_blight""Tomato_Septoria_leaf_spot",
                   "Tomato_Spider_mites_Two-spotted_spider_mite""Tomato_Target_Spot",
                   "Tomato_Tomato_Yellow_Leaf_Curl_Virus""Tomato_healthy"]
len(combined_labels)


####################################################################################
#라벨 폴더 생성
import shutil, glob, os
path = "./train"
if not os.path.isdir(path):                                                           
    os.mkdir(path)
 
for i in range(len(combined_labels)):
    path2 = f"./train/{combined_labels[i]}"
    if not os.path.isdir(path2):                                                           
        os.mkdir(path2)
 
 
####################################################################################
#사진 폴더별로 복사붙여넣기 
path_data = './eda/식물병충해data/train'
file_list = os.listdir(path_data)
 
#plant_label 딕셔너리
list1 = list(range(14))
dict1 = dict(zip(list1,plant_label))
 
#disease_label 딕셔너리
list2 = list(range(21))
dict2 = dict(zip(list2,disease_label))
 
#
for i in range(16000):
    cl_list = file_list[i][:-4].split('_'#이름을 나누기 plant + disease + 번호
    find_name = dict1.get(int(cl_list[0])) + '_' + dict2.get(int(cl_list[1])) #Combined Labels 이름 찾기
    if file_list[i] not in path_data :
        shutil.copy(f'{path_data}/{file_list[i]}', f'{path}/{find_name}')
    #print('복사완료')
cs

폴더명이 숫자 클래스로 필요할 수도 있고 combined_labels로 필요할 수도 있어서 폴더명을 바꾸기 쉽게 수정하는 코드를 추가했다. 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#class name으로 변경
from os import rename, listdir
 
path = "./train"
 
list3 = list(str(i) for i in range(20))
dict3 = dict(zip(combined_labels,list3))
 
for fname in os.listdir(path):
    newname = dict3.get(fname)
    if newname not in os.listdir(path) :    
        os.rename(os.path.join(path, fname), os.path.join(path,newname))
print("class name으로 변경완료")
 
 
 
#labeled_name으로 되돌리고 싶을 때
list3 = list(str(i) for i in range(20))
dict3 = dict(zip(list3, combined_labels))
 
for fname in os.listdir(path):
    newname = dict3.get(fname)
    if newname not in os.listdir(path) :    
        os.rename(os.path.join(path, fname), os.path.join(path,newname))
print("labeled name으로 변경완료")
cs

 

 

 

 

반복해서 학습을 위해서 numpy 배열을 npy 파일로 저장을 하려고 했다. 하지만 모든 팀원들 컴퓨터 사양이 좋지 않아서 이미지 사이즈를 128x128로 하려다가 다들 맛이 가서 64x64로 어쩔 수 없이 저장했다.. ㅠㅠㅠ

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import os, re, glob
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
  
groups_folder_path = './train/'
categories = list(str(i) for i in range(20))
 
num_classes = len(categories)
  
image_w = 64
image_h = 64
  
= []
= []
  
for idex, categorie in enumerate(categories):
    label = [0 for i in range(num_classes)]
    label[idex] = 1
    image_dir = groups_folder_path + categorie + '/'
  
    for top, dir, f in os.walk(image_dir):
        for filename in f:
            print(image_dir+filename)
            img = cv2.imread(image_dir+filename)
            img = cv2.resize(img, dsize=(image_w, image_h))
            X.append(img/256)
            Y.append(label)
 
= np.array(X)
= np.array(Y)
 
X_train, X_test, Y_train, Y_test = train_test_split(X,Y)
xy = (X_train, X_test, Y_train, Y_test)
 
np.save("./img_data.npy", xy)
cs

#NumPy 배열을 npy 외부 파일로 저장

+ Recent posts