반응형
목적
- 콘크리트 이미지가 정상인지 비정상인지 분류하는 모델을 만들자
1. 필요한 라이브러리 불러오기
import os
import shutil
import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input
from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
2. 데이터 폴더 생성 및 정리
train = './concrete_image_cjk/src_cjk'
print(len(os.listdir(train)))
test = './concrete_image_cjk/test_cjk'
print(len(os.listdir(test)))
#(1) IMAGE/Negative 와 IMAGE/Positive에 파일 분류해서 넣기
import shutil
# 이미지 폴더 있는지 확인
if not os.path.exists('IMAGE'):
os.mkdir('IMAGE')
if not os.path.exists('IMAGE/Negative'):
os.mkdir('IMAGE/Negative')
if not os.path.exists('IMAGE/Positive'):
os.mkdir('IMAGE/Positive')
count=0
for filename in os.listdir(train):
if filename.endswith('.jpg'):
label=filename.split("_")[-1].split(".")[0]
if(label=="negative"):
shutil.copy(os.path.join("./concrete_image_cjk/src_cjk", filename), os.path.join("IMAGE/Negative", filename))
elif(label=="positive"):
shutil.copy(os.path.join("./concrete_image_cjk/src_cjk", filename), os.path.join("IMAGE/Positive", filename))
3. 하이퍼파라미터 설정
num_epochs = 10
batch_size = 32
learning_rate = 0.001
dropout_rate = 0.5
input_shape = (224, 224, 3) # 사이즈 확인
num_classes = 2 # Postive , Negative
4. 데이터 전처리 및 증강
image_datagen = ImageDataGenerator(
validation_split=0.2, # 80% 학습, 20% 검증
preprocessing_function=preprocess_input,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
5. 학습 및 검증 데이터 로드
training_generator = image_datagen.flow_from_directory(
'./IMAGE',
batch_size=batch_size,
target_size=(224, 224), # 원하는 출력 사이즈 입력. MobileNetV2 위해 사이즈 변경 : 227,227 --> 224,224. 최종 출력 : (224,224,3)
class_mode = 'categorical', # binary , categorical
shuffle = True,
subset = 'training' # training, validation. ImageDataGenerator의 validation_split 사용하므로 subset 지정
)
test_generator = image_datagen.flow_from_directory(
'./IMAGE',
batch_size=batch_size,
target_size=(224, 224), # 원하는 출력 사이즈 입력. MobileNetV2 위해 사이즈 변경 : 227,227 --> 224,224. 최종 출력 : (224,224,3)
class_mode = 'categorical', # binary , categorical
shuffle = True,
subset = 'validation' # training, validation. ImageDataGenerator의 validation_split 사용하므로 subset 지정
)
6. MobileNetV2 모델 불러오기
base_model = MobileNetV2(input_shape=(224, 224, 3), include_top=False, weights='imagenet')
base_model.trainable = False # 사전 학습된 가중치 고정
7. 모델 설계
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
output = tf.keras.layers.Dense(2, activation='softmax')(x) # Positive / Negative 이진 분류
# 최종 모델 생성
model = tf.keras.Model(inputs=base_model.input, outputs=output)
8. 모델 컴파일
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate),
loss='categorical_crossentropy',
metrics=['accuracy']
)
9. 콜백 설정
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=30)
checkpoint = ModelCheckpoint(filepath="checkpoint.weights.h5", save_weights_only=True, save_best_only=True, monitor='val_loss', verbose=1)
lrReducer = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=2, min_lr=0.0001)
callbacks = [es, checkpoint, lrReducer]
10. 모델 학습
history = model.fit(
training_generator,
validation_data=test_generator,
epochs=num_epochs,
callbacks=callbacks
)
11. 모델 저장
model.save('20241220_con.h5')
12. 테스트 데이터 평가
# 정답 데이터 생성
target=[]
label=[]
result=[]
for item in os.listdir("./concrete_image_cjk/test_cjk"):
target.append(item.split(".")[0])
if(item.split("_")[-1].split(".")[0]=="positive"):
label.append('positive')
elif(item.split("_")[-1].split(".")[0]=="negative"):
label.append('negative')
result.append("")
df = pd.DataFrame({"target":target, "label":label, "result":result})
df.to_csv("test.csv")
final=pd.read_csv("test.csv")
# 모델 불러오기
loaded_model = tf.keras.models.load_model('20241220_con.h5')
# 테스트 데이터 불러오기
final = pd.read_csv("test.csv")
answer_class = {0: 'negative', 1: 'positive'}
right = 0
total = 0
# 테스트 이미지 개별 예측
for image, label in zip(final['target'], final['label']):
total += 1
test_image_path = f"./concrete_image_cjk/test_cjk/{image}.jpg"
img = load_img(test_image_path, target_size=(224, 224))
img_array = img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
img_array = preprocess_input(img_array)
predictions = loaded_model(img_array)
predicted_class = np.argmax(predictions, axis=1)[0]
pred = answer_class[predicted_class]
if label == pred:
right += 1
accuracy = (right / total) * 100
print(f"점수는 : {accuracy:.2f}점")
13. 최종파일 생성
real_final=pd.DataFrame({"target":final['target'].tolist(), "label":final['label'].tolist(), "result":result})
real_final.to_csv("real_final.csv")
최종코드
import os
import shutil
import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_input
from tensorflow.keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
train = './concrete_image_cjk/src_cjk'
print(len(os.listdir(train)))
test = './concrete_image_cjk/test_cjk'
print(len(os.listdir(test)))
#(1) IMAGE/Negative 와 IMAGE/Positive에 파일 분류해서 넣기
import shutil
# 이미지 폴더 있는지 확인
if not os.path.exists('IMAGE'):
os.mkdir('IMAGE')
if not os.path.exists('IMAGE/Negative'):
os.mkdir('IMAGE/Negative')
if not os.path.exists('IMAGE/Positive'):
os.mkdir('IMAGE/Positive')
count=0
for filename in os.listdir(train):
if filename.endswith('.jpg'):
label=filename.split("_")[-1].split(".")[0]
if(label=="negative"):
shutil.copy(os.path.join("./concrete_image_cjk/src_cjk", filename), os.path.join("IMAGE/Negative", filename))
elif(label=="positive"):
shutil.copy(os.path.join("./concrete_image_cjk/src_cjk", filename), os.path.join("IMAGE/Positive", filename))
num_epochs = 10
batch_size = 32
learning_rate = 0.001
dropout_rate = 0.5
input_shape = (224, 224, 3) # 사이즈 확인
num_classes = 2 # Postive , Negative
image_datagen = ImageDataGenerator(
validation_split=0.2, # 80% 학습, 20% 검증
preprocessing_function=preprocess_input,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
training_generator = image_datagen.flow_from_directory(
'./IMAGE',
batch_size=batch_size,
target_size=(224, 224), # 원하는 출력 사이즈 입력. MobileNetV2 위해 사이즈 변경 : 227,227 --> 224,224. 최종 출력 : (224,224,3)
class_mode = 'categorical', # binary , categorical
shuffle = True,
subset = 'training' # training, validation. ImageDataGenerator의 validation_split 사용하므로 subset 지정
)
test_generator = image_datagen.flow_from_directory(
'./IMAGE',
batch_size=batch_size,
target_size=(224, 224), # 원하는 출력 사이즈 입력. MobileNetV2 위해 사이즈 변경 : 227,227 --> 224,224. 최종 출력 : (224,224,3)
class_mode = 'categorical', # binary , categorical
shuffle = True,
subset = 'validation' # training, validation. ImageDataGenerator의 validation_split 사용하므로 subset 지정
)
base_model = MobileNetV2(input_shape=(224, 224, 3), include_top=False, weights='imagenet')
base_model.trainable = False # 사전 학습된 가중치 고정
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
output = tf.keras.layers.Dense(2, activation='softmax')(x) # Positive / Negative 이진 분류
# 최종 모델 생성
model = tf.keras.Model(inputs=base_model.input, outputs=output)
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate),
loss='categorical_crossentropy',
metrics=['accuracy']
)
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=30)
checkpoint = ModelCheckpoint(filepath="checkpoint.weights.h5", save_weights_only=True, save_best_only=True, monitor='val_loss', verbose=1)
lrReducer = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=2, min_lr=0.0001)
callbacks = [es, checkpoint, lrReducer]
history = model.fit(
training_generator,
validation_data=test_generator,
epochs=num_epochs,
callbacks=callbacks
)
model.save('20241220_con.h5')
# 정답 데이터 생성
target=[]
label=[]
result=[]
for item in os.listdir("./concrete_image_cjk/test_cjk"):
target.append(item.split(".")[0])
if(item.split("_")[-1].split(".")[0]=="positive"):
label.append('positive')
elif(item.split("_")[-1].split(".")[0]=="negative"):
label.append('negative')
result.append("")
df = pd.DataFrame({"target":target, "label":label, "result":result})
df.to_csv("test.csv")
final=pd.read_csv("test.csv")
# 모델 불러오기
loaded_model = tf.keras.models.load_model('20241220_con.h5')
# 테스트 데이터 불러오기
final = pd.read_csv("test.csv")
answer_class = {0: 'negative', 1: 'positive'}
right = 0
total = 0
# 테스트 이미지 개별 예측
for image, label in zip(final['target'], final['label']):
total += 1
test_image_path = f"./concrete_image_cjk/test_cjk/{image}.jpg"
img = load_img(test_image_path, target_size=(224, 224))
img_array = img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
img_array = preprocess_input(img_array)
predictions = loaded_model(img_array)
predicted_class = np.argmax(predictions, axis=1)[0]
pred = answer_class[predicted_class]
if label == pred:
right += 1
accuracy = (right / total) * 100
print(f"점수는 : {accuracy:.2f}점")
real_final=pd.DataFrame({"target":final['target'].tolist(), "label":final['label'].tolist(), "result":result})
real_final.to_csv("real_final.csv")
반응형
'인공지능' 카테고리의 다른 글
Image Data - 꽃 이미지 분류 모델(MobileNetV2) (0) | 2025.02.09 |
---|---|
Text Data - 네이버 영화리뷰 감정 분석하기(BERT) (0) | 2025.02.09 |
Text Data - 문장 감정분류하기(BERT) (0) | 2025.02.09 |
*빅데이터분석기사 대비! AI 총정리. Tabular, Text, Image (0) | 2025.02.09 |
Tabular Data - 당뇨병에 걸릴 확률 회귀 (0) | 2025.02.09 |