이 프로젝트는 네이버에 합격한 선배의 딥러닝 포트폴리오입니다.
잘 된 딥러닝 포트폴리오를 잘 필사해서 여러분들것으로 만들고 더 좋은 포트폴리오를 만드세요
#1. 정상 이파리와 질병 이파리 데이터를 다운로드 받습니다.
https://cafe.daum.net/oracleoracle/SpOP/283
훈련 4000장( 정상: 2000장, 질병: 2000장 ) 테스트 100장
#2. 일반 컬러 사진을 신경망에 넣고 분류하는 모델 만드는 전체적인 과정
■ 실습
구글 코랩 드라이브 마운트
##### 마운트 안 됐을 수도 있으니 다음 코드 실행
from google.colab import drive
drive.mount('/content/drive')
구글 코렙에 /content/drive/MyDrive/leaf 디렉토리를 만들고 train4000 폴더와 test100 폴더를 생성하시오 !
train4000.zip 파일과 test100.zip 을 코렙에 올리는데
train4000.zip 파일을 /content/drive/MyDrive/leaf/train4000 폴더에 압축을 풀고 test100.zip 파일을 /content/drive/MyDrive/leaf/test100 폴더에 압축을 풉니다.
코렙 셀에서 다음과 같이 압축을 풉니다.
!unzip -uq /content/drive/MyDrive/leaf/train4000.zip -d /content/drive/MyDrive/leaf/train4000
!ls -l /content/drive/MyDrive/leaf/train4000/*
!unzip -uq /content/drive/MyDrive/leaf/test100.zip -d /content/drive/MyDrive/leaf/test100
!ls -l /content/drive/MyDrive/leaf/test100/*
/content/drive/MyDrive/leaf 밑에 train_resize 와 test_resize 폴더를 각각 만드시오 !
원본 이미지가 256x256 사이즈의 이미지를 32x32 로 resize 해서 train_resize 폴더와 test_resize 폴더에 넣으시오 !
# 1. resize 하는데 필요한 모듈을 임폴트 합니다.
import cv2
import os
import numpy as np
# 2. 원본 이미지가 있는 디렉토리를 지정합니다.
path = '/content/drive/MyDrive/leaf/train4000'
file_list = os.listdir(path) # path 경로에 있는 이미지들을 하나씩 불러오는 코드
# 3. file_list 안에 있는 파일들을 하나씩 불러와서 32x32 로 리사이즈합니다.
for k in file_list: # 리스트안에 있는 파일들을 하나씩 빼내는 코드
# .ipynb_checkpoints 폴더를 제외합니다.
if k == '.ipynb_checkpoints':
continue
# 이미지 파일 경로를 생성합니다.
image_path = os.path.join(path, k)
# 이미지 파일인지 확인합니다.
if os.path.isfile(image_path) and image_path.lower().endswith(('.png', '.jpg', '.jpeg')):
img = cv2.imread(image_path) # 이미지를 숫자로 변환
# 이미지를 읽어들이는 데 실패했는지 확인합니다.
if img is not None:
resize_img = cv2.resize(img, (32, 32), interpolation=cv2.INTER_CUBIC) # 32X32로...
cv2.imwrite('/content/drive/MyDrive/leaf/train_resize/' + k, resize_img) # 이미지 저장
else:
print(f"이미지를 읽어들일 수 없습니다: {image_path}")
else:
print(f"이미지 파일이 아닙니다: {image_path}")
테스트 데이터 100장도 같은 방법으로 resize 를 하는데 아래의 디렉토리에 저장되게하시오
/content/drive/MyDrive/leaf/test_resize/
# 1. resize 하는데 필요한 모듈을 임폴트 합니다.
import cv2
import os
import numpy as np
# 2. 원본 이미지가 있는 디렉토리를 지정합니다.
path = '/content/drive/MyDrive/leaf/test100'
file_list = os.listdir(path) # path 경로에 있는 이미지들을 하나씩 불러오는 코드
# 3. file_list 안에 있는 파일들을 하나씩 불러와서 32x32 로 리사이즈합니다.
for k in file_list: # 리스트안에 있는 파일들을 하나씩 빼내는 코드
# .ipynb_checkpoints 폴더를 제외합니다.
if k == '.ipynb_checkpoints':
continue
# 이미지 파일 경로를 생성합니다.
image_path = os.path.join(path, k)
# 이미지 파일인지 확인합니다.
if os.path.isfile(image_path) and image_path.lower().endswith(('.png', '.jpg', '.jpeg')):
img = cv2.imread(image_path) # 이미지를 숫자로 변환
# 이미지를 읽어들이는 데 실패했는지 확인합니다.
if img is not None:
resize_img = cv2.resize(img, (32, 32), interpolation=cv2.INTER_CUBIC) # 32X32로...
cv2.imwrite('/content/drive/MyDrive/leaf/test_resize/' + k, resize_img) # 이미지 저장
else:
print(f"이미지를 읽어들일 수 없습니다: {image_path}")
else:
print(f"이미지 파일이 아닙니다: {image_path}")
사진을 숫자로 변경해야 신경망에 집어 넣을 수 있으므로 사진을 숫자로 변경하는 함수를 생성합니다. (함수만 생성)
# 신경망에 이미지를 넣으려면 리사이즈한 사진을 숫자로 변경을 해야하는데
# 사진을 숫자로 변경하는 함수를 다음과 같이 생성합니다.
train_images='/content/drive/MyDrive/leaf/train_resize'
import os
import re
import cv2
import numpy as np
def image_load(path):
#1. 사진 파일명에서 숫자부분만 취합니다.
file_list = os.listdir(path) # path 디렉토리에 파일명들을 불러옵니다.
file_name = []
for i in file_list:
a = int( re.sub('[^0-9]', '', i ) ) # i 가 숫자가 아니라면 null 로 변경해라
file_name.append(a)
file_name.sort()
#2. 디렉토리와 숫자 파일명을 이어 붙입니다.
file_res = [ ]
for j in file_name:
file_res.append( path + '/' + str(j) + '.jpg') # 전체 경로 + 파일명을 생성
#3. 위에서만든 디렉토리와 파일명을 가지고 사진을 숫자로 변경합니다.
image= [ ]
for k in file_res:
img = cv2.imread(k) # 이미지를 숫자로 변경합니다.
image.append(img)
return np.array(image)
#print ( image_load(train_images) )
test_resize 밑에 있는 사진들도 위의 load_image 함수로 숫자로 잘 변경이 되는지 확인하시오 !
test_images ='/content/drive/MyDrive/leaf/test_resize'
print( image_load( test_images) )
정답 csv 파일 생성하기
path = '/content/drive/MyDrive/leaf/train_label.csv'
file = open( path, 'w' ) # 비어있는 파일 생성
# 숫자0 을 2000개, 숫자 1을 2000개 씁니다.
for i in range(1, 2001):
file.write( str(0) + '\\n')
for i in range(2001, 4001):
file.write( str(1) + '\\n')
file.close() # 저장합니다.
# 테스트 데이터도 만드세요 !
path = '/content/drive/MyDrive/leaf/test_label.csv'
file = open( path, 'w' ) # 비어있는 파일 생성
# 숫자0을 50개, 숫자 1을 50개 씁니다.
for i in range(1, 51):
file.write( str(0) + '\\n')
for i in range(51, 101):
file.write( str(1) + '\\n')
file.close() # 저장합니다.
정답 csv 파일을 불러와서 one hot encoding 하는 함수를 생성하시오 !
from tensorflow.keras.utils import to_categorical
import csv
import numpy as np
def label_load(path):
file = open(path)
labeldata = csv.reader(file)
labellist = [ ]
for i in labeldata:
labellist.append(i)
label = np.array( labellist ) # 넘파이 배열로 변환
label = label.astype(int) # 숫자로 변환
label = to_categorical(label) # [ 1, 0] 또는 [0, 1] 로 one hot encoding 합니다.
# 0 -> [1, 0] 1 -> [0, 1]
return label
train_label = '/content/drive/MyDrive/leaf/train_label.csv'
print( label_load(train_label) )
# 테스트 데이터도 원핫 인코딩이 잘되는지 확인합니다.
from tensorflow.keras.utils import to_categorical
import csv
import numpy as np
test_label = '/content/drive/MyDrive/leaf/test_label.csv'
print( label_load(test_label) )
코렙에 텐써 플로우 버젼이 어떻게 되는지 확인합니다.
import tensorflow as tf
print( tf.__version__ ) # 2.17.0
위의 image_load 와 label_load 함수를 이용해서 신경망에 입력할 이미지들을 숫자로 변경하는 코드를 수행하시오 !
# 1. 필요한 패키지 가져오는 코드
import tensorflow as tf # 텐써 플로우 2.0
from tensorflow.keras.datasets.mnist import load_data # 텐써플로우에 내장되어있는
# mnist 데이터를 가져온다.
from tensorflow.keras.models import Sequential # 모델을 구성하기 위한 모듈
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten # CNN, 완전 연결계층을 구성하기 위한 모듈
from tensorflow.keras.utils import to_categorical # one encoding 하는 모듈
tf.random.set_seed(777)
# 이파리 데이터를 가져오는 코드
train_images='/content/drive/MyDrive/leaf/train_resize'
test_images ='/content/drive/MyDrive/leaf/test_resize'
train_label = '/content/drive/MyDrive/leaf/train_label.csv'
test_label ='/content/drive/MyDrive/leaf/test_label.csv'
x_train = image_load( train_images)
x_test = image_load( test_images )
y_train = label_load(train_label)
y_test = label_load(test_label)
print(x_train.shape)
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)
# (4000, 32, 32, 3)
# (4000, 2)
# (100, 32, 32, 3)
# (100, 2)
#2. 신경망 구현 코드를 수행합니다.
# 2. 정규화를 진행합니다.
x_train = x_train / 255.0
x_test = x_test / 255.0
print(x_train.shape) # (4000, 32, 32, 3)
# 3. 모델을 구성합니다. 3층 신경망으로 구성
model = Sequential()
model.add(Conv2D(100, kernel_size=(5,5), input_shape=(32,32,3), padding='same', activation='relu') )
model.add(MaxPooling2D(pool_size=(2,2), padding='same') ) # 이미지를 선명하게 해주는 층
model.add(Flatten() ) # 완전연결계층에 들어갈수 있도록 이미지(피쳐맵들)를 1차원으로 변경합니다.
model.add(Dense(50, activation = 'sigmoid', input_shape = (784, ))) # 1층
model.add(Dense(50, activation = 'sigmoid') ) # 2층 은닉층
model.add(Dense( 2, activation = 'softmax')) # 3층 출력층
# 5. 모델을 설정합니다. ( 경사하강법, 오차함수를 정의해줍니다. )
model.compile(optimizer='SGD',
loss = 'categorical_crossentropy',
metrics=['acc']) # 학습과정에서 정확도를 보려고
#6. 모델을 훈련시킵니다.
history = model.fit(x_train, y_train,
epochs = 30, # 30에폭
batch_size = 100,
validation_data=(x_test, y_test) )
# 7.모델을 평가합니다. (오차, 정확도가 출력됩니다.)
model.evaluate(x_test, y_test)
train_acc_list=history.history['acc']
train_acc_list
test_acc_list=history.history['val_acc']
test_acc_list
import matplotlib.pyplot as plt
x = np.arange( len(train_acc_list) )
plt.plot( x, train_acc_list, label='train acc')
plt.plot( x, test_acc_list, label='test acc', linestyle='--')
plt.ylim(0, 1)
plt.legend(loc='lower right')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.show()
# Epoch 30/30
# 40/40 ━━━━━━━━━━━━━━━━━━━━ 23s 323ms/step - acc: 0.6706 - loss: 0.6786 - val_acc: 0.6200 - val_loss: 0.6823
# 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 19ms/step - acc: 0.6261 - loss: 0.6827
문제1. 위의 코드에 배치 정규화와 드롭아웃과 모델 저장하는 코드까지 추가해서 돌리시오 !
import tensorflow as tf # 텐서플로우 2.0
from tensorflow.keras.datasets.mnist import load_data # MNIST 데이터를 가져온다.
from tensorflow.keras.models import Sequential # 모델을 구성하기 위한 모듈
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten, Dropout, BatchNormalization # CNN, 완전 연결계층, 드롭아웃, 배치 정규화를 구성하기 위한 모듈
from tensorflow.keras.callbacks import EarlyStopping # 얼리 스탑핑을 위한 모듈
from tensorflow.keras.utils import to_categorical # one-hot encoding을 위한 모듈
import numpy as np
import matplotlib.pyplot as plt
tf.random.set_seed(777)
# 이미지와 라벨 데이터를 불러오는 코드
train_images = '/content/drive/MyDrive/leaf/train_resize'
test_images = '/content/drive/MyDrive/leaf/test_resize'
train_label = '/content/drive/MyDrive/leaf/train_label.csv'
test_label = '/content/drive/MyDrive/leaf/test_label.csv'
x_train = image_load(train_images)
x_test = image_load(test_images)
y_train = label_load(train_label)
y_test = label_load(test_label)
# 정규화 진행
x_train = x_train / 255.0
x_test = x_test / 255.0
print(x_train.shape) # (4000, 32, 32, 3)
# 모델 구성
model = Sequential()
model.add(Conv2D(100, kernel_size=(5, 5), input_shape=(32, 32, 3), padding='same', activation='relu'))
model.add(BatchNormalization()) # 배치 정규화 추가
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Flatten())
model.add(Dense(50, activation='relu'))
model.add(BatchNormalization()) # 배치 정규화 추가
model.add(Dropout(0.2)) # 드롭아웃 추가 (20% 비율)
model.add(Dense(50, activation='relu'))
model.add(Dropout(0.2)) # 드롭아웃 추가 (20% 비율)
model.add(Dense(2, activation='softmax')) # 출력층
# 모델 컴파일
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics=['acc'])
# 얼리 스탑핑 설정 (validation accuracy가 5번 향상되지 않으면 학습 중단)
early_stopping = EarlyStopping(monitor='val_acc', patience=10, restore_best_weights=True)
# 모델 훈련
history = model.fit(x_train, y_train,
epochs=40, # 최대 30 에폭
batch_size=100,
validation_data=(x_test, y_test),
callbacks=[early_stopping]) # 얼리 스탑핑 콜백 추가
# 모델 평가
model.evaluate(x_test, y_test)
# 훈련 및 검증 정확도 시각화
train_acc_list = history.history['acc']
test_acc_list = history.history['val_acc']
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.ylim(0, 1)
plt.legend(loc='lower right')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.show()
# 모델 저장
model.save('/content/drive/MyDrive/leaf/my_model.keras') # 모델을 h5 파일로 저장
문제2. 저장된 모델을 불러와서 이미지 1장을 맞추는 코드를 구현하시오 !
import tensorflow as tf
from tensorflow.keras.models import load_model
import numpy as np
from PIL import Image
# 모델 불러오기
model = load_model('c:\\\\data\\\\my_model.h5')
# 이미지를 불러오는 함수 정의 (모델에 맞는 크기로 이미지를 조정)
def load_and_process_image(image_path):
img = Image.open(image_path)
img = img.resize((32, 32)) # 모델 입력 크기에 맞게 32x32로 크기 조정
img = np.array(img) # 이미지 배열로 변환
img = img / 255.0 # 정규화 (모델 학습 시 정규화했으므로 동일하게 적용)
img = np.expand_dims(img, axis=0) # 배치 차원 추가 (1, 32, 32, 3)
return img
# 이미지 경로 설정
image_path = '테스트 할 이미지 경로'
# 이미지 로드 및 처리
processed_image = load_and_process_image(image_path)
# 예측 수행
predictions = model.predict(processed_image)
# 결과 출력
class_names = ['Normal', 'Disease'] # 클래스 이름 설정
predicted_class = np.argmax(predictions) # 예측된 클래스 (0 또는 1)
predicted_probability = predictions[0][predicted_class] # 예측된 클래스의 확률
print(f'Predicted class: {class_names[predicted_class]}')
print(f'Confidence: {predicted_probability * 100:.2f}%')
image_path = 'C:\\\\data\\\\train4000\\\\1354.jpg'
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 265ms/step
Predicted class: Normal
Confidence: 99.31%
image_path = 'C:\\\\data\\\\train4000\\\\17666.jpg'
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 158ms/step
Predicted class: Disease
Confidence: 98.88%
문제3. 5기 임미선 선배가 만든 신경망으로 코드를 구현하시오 !
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, BatchNormalization, Dropout
from tensorflow.keras.callbacks import EarlyStopping
# 모델 구성 시작
model = Sequential()
# 첫 번째 컨볼루션 레이어 (CONV1) + 배치 정규화 + 두 번째 컨볼루션 레이어 (factorization)
model.add(Conv2D(32, (3, 3), padding='same', activation='relu', input_shape=(32, 32, 3)))
model.add(Conv2D(32, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')) # 첫 번째 풀링 레이어
# 두 번째 컨볼루션 레이어 (CONV2) + 배치 정규화 + 풀링 레이어
model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')) # 두 번째 풀링 레이어
# 세 번째 컨볼루션 레이어 (CONV3) + 배치 정규화 + 풀링 레이어
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')) # 세 번째 풀링 레이어
# 네 번째 컨볼루션 레이어 (CONV4) + 배치 정규화 + 풀링 레이어
model.add(Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')) # 네 번째 풀링 레이어
# 완전 연결 계층 (Fully Connected Layers)
model.add(Flatten()) # 평탄화
model.add(Dense(2560, activation='relu')) # 첫 번째 FC 레이어
model.add(Dropout(0.5)) # 드롭아웃 추가
model.add(Dense(1000, activation='relu')) # 두 번째 FC 레이어
# 출력층 (2개의 클래스, softmax 활성화 함수 사용)
model.add(Dense(2, activation='softmax'))
# 모델 요약 출력
model.summary()
# 모델 컴파일
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# 얼리 스토핑 설정 (검증 정확도가 10번 향상되지 않으면 중단)
early_stopping = EarlyStopping(monitor='val_accuracy', patience=10, restore_best_weights=True)
# 모델 훈련 (데이터는 가상의 변수로 사용 중)
history = model.fit(x_train, y_train,
epochs=100,
batch_size=64,
validation_data=(x_test, y_test),
callbacks=[early_stopping])
# 모델 평가
test_loss, test_acc = model.evaluate(x_test, y_test)
print(f'테스트 정확도: {test_acc}')
# 학습 결과 시각화 (정확도 그래프)
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'], label='train accuracy')
plt.plot(history.history['val_accuracy'], label='validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
# Epoch 37/100
# 63/63 ━━━━━━━━━━━━━━━━━━━━ 41s 508ms/step - accuracy: 0.9940 - loss: 0.0169 - val_accuracy: 0.8600 - val_loss: 0.6808
# 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 46ms/step - accuracy: 0.8984 - loss: 0.5437
# 테스트 정확도: 0.9100000262260437
문제4. 이파리 모델을 손쉽게 사용할 수 있는 화면 인터페이스를 생성하시오 !
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import numpy as np
import tensorflow as tf
import cv2 # 이미지를 전문으로 전처리하는 모듈
# 신경망 모델 로드 (질병 잎사귀 분류 모델)
model = tf.keras.models.load_model('c:\\\\data\\\\my_model.keras')
# 타겟 딕셔너리 (정상 및 질병에 해당하는 레이블)
target_dict = {
0: 'Healthy',
1: 'Disease',
}
# 이미지 전처리 함수
def preprocess_image(image_path):
# 이미지 불러오기
img = cv2.imread(image_path)
# 이미지 크기를 32x32로 조정 (모델 입력 크기)
resized_img = cv2.resize(img, (32, 32))
# RGB 이미지를 그대로 사용
img_array = np.array(resized_img) / 255.0 # 정규화
img_array = img_array.reshape(1, 32, 32, 3) # CNN 입력 형태로 변환 (배치 크기 포함)
return img_array
# 이미지 선택 및 표시
def select_image():
global file_path
file_path = filedialog.askopenfilename() # 선택한 이미지 경로 저장
if not file_path:
return
# 선택한 이미지 표시
img_display = cv2.imread(file_path)
img_display = cv2.resize(img_display, (400, 400)) # 화면에 출력할 크기로 조정
img_display = cv2.cvtColor(img_display, cv2.COLOR_BGR2RGB) # OpenCV는 BGR, tkinter는 RGB를 사용함
img_tk = ImageTk.PhotoImage(Image.fromarray(img_display))
# 이미지 위젯 업데이트
label_image.config(image=img_tk)
label_image.image = img_tk
# 예측 및 결과 표시
def predict_image():
if not file_path:
label_prediction.config(text="No image selected")
return
# 이미지를 전처리하여 예측
img = preprocess_image(file_path)
prediction = model.predict(img)
predicted_label = np.argmax(prediction)
# 라벨 번호에 해당하는 타겟 텍스트
predicted_text = target_dict.get(predicted_label, "Unknown")
# 예측된 클래스의 확률
predicted_probability = prediction[0][predicted_label] # 예측된 클래스의 확률
# 예측 결과 업데이트
label_prediction.config(text=f"Prediction: {predicted_text} ({predicted_probability:.4f})")
# tkinter 윈도우 설정
root = tk.Tk()
root.title("Leaf Disease Classifier")
root.geometry("600x700") # 기본 창 크기 설정
# 이미지 선택 버튼 (위쪽에 배치)
button_select = tk.Button(root, text="Select Image", command=select_image)
button_select.pack(pady=10) # 위쪽에 공간을 추가
# 이미지 출력할 라벨 (이미지 박스)
label_image = tk.Label(root)
label_image.pack(pady=10)
# 예측 버튼 (이미지 아래에 배치)
button_predict = tk.Button(root, text="Predict", command=predict_image)
button_predict.pack(pady=10)
# 예측 결과 출력할 라벨 (예측 버튼 아래에 배치)
label_prediction = tk.Label(root, text="", font=("Helvetica", 16))
label_prediction.pack(pady=20)
# tkinter 실행
root.mainloop()