강아지와 고양이 이미지 분류
단계별 구현 내용
[1단계]
- 코랩에서 데이터를 다운로드 받는다.
- flow_from_directory 를 통해 데이터를 전처리하며 불러온다.
- cnn 혹은 전이학습을 통해 강아지와 고양이를 분류하는 모델을 학습시킨다.
[2단계]
- flask 프로젝트를 만든다.
- flask를 활용해 웹 상에서 제목과 함께 이미지를 업로드할 수 있는 파일 업로드 기능을 구현한다.
- flask를 활용해 웹 상에서 이미지를 업로드하면 해당 이미지가 강아지인지, 고양이인지에 대한 결과를 출력해준다.
[3단계]
- 파일이 업로드 한다고 해서 바로 결과 페이지로 넘어가지 않고, 제목을 토대로 특정한 이미지를 검색해서 결과를 볼 수 있도록 구현한다.
1단계
- 강아지와 고양이 데이터셋
(출처: https://www.kaggle.com/datasets/tongpython/cat-and-dog)
- CNN을 통한 모델 학습 코드
환경변수 설정
import os
os.environ['KAGGLE_USERNAME'] = '' # username
os.environ['KAGGLE_KEY'] = '' # key
데이터셋 다운 & 압축해제
!kaggle datasets download -d tongpython/cat-and-dog
!unzip -q cat-and-dog.zip
기본 CNN
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing.image import ImageDataGenerator
이미지 증강
train_datagen = ImageDataGenerator(
rescale=1./255, # 일반화
rotation_range=10, # 랜덤하게 이미지를 회전 (단위: 도, 0-180)
zoom_range=0.1, # 랜덤하게 이미지 확대 (%)
width_shift_range=0.1, # 랜덤하게 이미지를 수평으로 이동 (%)
height_shift_range=0.1, # 랜덤하게 이미지를 수직으로 이동 (%)
horizontal_flip=True # 랜덤하게 이미지를 수평으로 뒤집기
)
test_datagen = ImageDataGenerator(
rescale=1./255 # 일반화
)
train_gen = train_datagen.flow_from_directory(
'training_set/training_set',
target_size=(256, 256), # (height, width)
batch_size=32,
seed=2021,
class_mode='binary', # 결과 0(고양이), 1(강아지) 뿐
shuffle=True
)
test_gen = test_datagen.flow_from_directory(
'test_set/test_set',
target_size=(256, 256), # (height, width)
batch_size=32,
seed=2021,
class_mode='binary',
shuffle=False
)
from pprint import pprint
pprint(train_gen.class_indices)
미리보기
preview_batch = train_gen.__getitem__(0)
preview_imgs, preview_labels = preview_batch
plt.title(str(preview_labels[0]))
plt.imshow(preview_imgs[0])
CNN 학습
model = Sequential([
Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation="relu", input_shape=(256, 256, 3)),
MaxPooling2D(pool_size=(2, 2), strides=2),
Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation="relu"),
MaxPooling2D(pool_size=(2, 2), strides=2),
Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation="relu"),
MaxPooling2D(pool_size=(2, 2), strides=2),
Flatten(),
Dense(128, activation='relu'),
Dense(1, activation="sigmoid") # 이진
])
model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.001), metrics=['acc']) # 이진
from tensorflow.keras.callbacks import ModelCheckpoint
history = model.fit(
train_gen,
validation_data=test_gen, # 검증 데이터를 넣어주면 한 epoch이 끝날때마다 자동으로 검증
epochs=20, # epochs 복수형으로 쓰기!
callbacks=[
ModelCheckpoint('model.h5', monitor='val_acc', verbose=1, save_best_only=True)
]
)
2단계
- flask를 활용해 웹상에서 모델 적용하기
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="../static/js/upload.js"></script>
<script src="../static/js/log_in.js"></script>
<title>Document</title>
</head>
<body>
<div class="upload">
<img style="display: none;" id="frame" src="" width="300px"/>
<input type="file" id="upload-file" onchange="preview()">
<input type="text" id="upload-title">
<!--upload() 함수 실행-->
<button onclick="upload()">파일을 업로드해봅시다!</button>
</div>
<div class="search">
<input type="text" id="search-title">
<!--# search() 함수 실행-->
<button onclick="search()">검색해보아요</button>
</div>
</body>
</html>
- javascript
function upload() {
let file = $('#upload-file')[0].files[0] // id:uplad-file, 해당 파일 지정해주는 형식
let title = $('#upload-title').val()
let form_data = new FormData() // 파일 보낼때는 new FormData()를 사용해서 담아보내준다.
form_data.append("file_give", file) // .append를 사용해 " "안의 이름으로 file 변수를 넣는다.
form_data.append("title_give", title)
$.ajax({
type: "POST",
url: "/upload",
data: form_data, // FormData
cache: false,
contentType: false,
processData: false,
success: function (response) {
alert(response["result"])
}
});
}
function search() {
let title = $('#search-title').val()
let form_data = new FormData()
form_data.append("title_give", title)
$.ajax({
type: "POST",
url: "/search",
data: form_data,
cache: false,
contentType: false,
processData: false,
success: function (response) {
let predictions = response["predictions"]
$('.result').remove()
for (let i = 0; i < predictions.length; i++) {
let path = predictions[i]['path']
let result = predictions[i]['result']
// 응답받은값 이미지와 결과 가져오기
let temp_html = `<div class="result"><img src="${path}" width="100px"/>
<p>${result}</p></div>`
$('.search').append(temp_html)
}
}
});
}
function preview() {
let frame = document.getElementById('frame');
frame.src=URL.createObjectURL(event.target.files[0]);
frame.style.display = 'block';
}
- app.py
from flask import Flask, render_template, request, jsonify
from datetime import datetime
import tensorflow as tf
import numpy as np
import os
# 이미지 저장 위해서 pillow 라이브러리 설치 필요!!!
# 학습시킨 모델 불러오기 (0이면 고양이, 1이면 강아지)
# 함수 밖에서 불러야 메모리 손실 방지
model = tf.keras.models.load_model('static/model/model.h5')
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/upload', methods=['POST'])
def upload():
# 받은데이터에서 .files로 ' '안의 이름가진 파일 꺼내담기
file = request.files['file_give']
title = request.form['title_give']
extension = file.filename.split('.')[-1] # 파일 확장자 추출
#현재시간 담기
today = datetime.now()
mytime = today.strftime('%Y-%m-%d-%H-%M-%S')
filename = f'{mytime}'
# 저장 경로에다가 현재시간과 확장자로 파일 이름만들어 저장
save_to = f'static/img/{title}_{filename}.{extension}'
file.save(save_to) # 파일 저장
return jsonify({'result':'success'})
@app.route('/search', methods=['POST'])
def search():
title = request.form['title_give']
filenames = os.listdir('static/img') # os.listdir : 경로에 있는 파일 리스트 가져오기
# 유저가 작성한 이름과 일치하는 파일 경로를 저장한다.
matched_files = ['static/img/'+filename for filename in filenames if title in filename]
result_dict = []
for index, matched_file in enumerate(matched_files): # enumerate : index값이 있는 for문
# .load_img로 경로에있는 파일 가져온다.
image = tf.keras.preprocessing.image.load_img(matched_file, target_size=(224, 224))
# 이미지형태의 데이터타입을 array로 만듬
input_arr = tf.keras.preprocessing.image.img_to_array(image)
# [] 로 배치형태 데이터로 만듬 => .predict 할수 있다.
input_arr = np.array([input_arr])
predictions = model.predict(input_arr)
if predictions[0][0] > 0.5:
result = '강아지'
else:
result = '고양이'
# 파일인덱스번호, 파일경로, 예측결과를 담아서 반환
result_dict.append({'index': index, 'path':matched_file, 'result':result})
return jsonify({'predictions': result_dict})
if __name__ == '__main__':
app.run('0.0.0.0', port=8000, debug=True)
- 결과
'AI 웹 개발 과정 > 개인 프로젝트' 카테고리의 다른 글
django_tutorial 02. | 어플리케이션 만들기 (0) | 2022.05.28 |
---|---|
django_tutorial 01. | vs code에서 django 기본 구성 세팅 하기 (0) | 2022.05.28 |
개인 프로젝트 05 : 타임어택 미션 - 머신러닝 타임어택미션 + 2주차 숙제 (0) | 2022.05.15 |
개인 프로젝트 04 : turtlestagram | 회원가입, 로그인 페이지 구현 (0) | 2022.05.15 |
개인 프로젝트 03 : 타임어택 미션 - 회원가입/로그인 페이지 만들기 (0) | 2022.05.08 |