CNN 전쟁: 과일 질병 감지를 위한 ResNet vs. MobileNet vs. EfficientNet

발행: (2026년 1월 14일 오후 04:48 GMT+9)
8 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding any code blocks or URLs you want to keep unchanged) here? Once I have it, I’ll provide the Korean translation while preserving the original formatting and markdown.

Introduction

저는 딥러닝이 실제 문제를 해결하는 방식에 항상 매료되어 왔으며, 과일 질병 탐지는 완벽한 도전 과제로 보였습니다—​너무 단순하지도, 불가능하게 복잡하지도 않으며, 작물 손실에 맞서 싸우는 농부들에게 진정으로 유용합니다.

저는 FruitScan‑AI를 구축하고 세 가지 다른 신경망 아키텍처를 테스트하여 어느 것이 가장 좋은지 확인했습니다. 스포일러: 각각은 강점이 있으며, “최고” 모델은 여러분이 구축하고자 하는 것에 완전히 달려 있습니다.

왜 과일 질병 탐지를 해야 할까?

농부들은 매년 **20 %–40 %**의 작물을 질병과 해충 때문에 잃습니다. 전통적인 점검 방법—밭을 걸으며 모든 식물을 직접 검사하고, 문제를 일찍 발견하려고 애쓰는 방식—은 느리고, 일관성이 없으며, 모든 사람이 갖추지 못한 전문 지식이 필요합니다.

그냥 사진 한 장만 찍으면 즉시 진단을 받을 수 있다면 어떨까요? 바로 그때가 FruitScan‑AI가 등장하는 순간입니다.

내가 만든 것

FruitScan‑AI 은 과일 이미지를 보고 두 가지를 알려주는 딥러닝 시스템입니다:

  1. 어떤 과일인지
  2. 건강한지, 병에 걸렸는지

단일 모델에 머물지 않고 EfficientNet, MobileNetV2, ResNet50을 사용해 세 가지 버전을 만들었으며, 이를 나란히 비교했습니다.

The Dataset

  • 15+ 종류의 과일 이미지 (사과, 바나나, 포도, 망고, 토마토, 고추, …)
  • 각 클래스는 건강한병든 표본을 모두 포함합니다 (세균 반점, 곰팡이 감염, 부패 등)
  • 정확한 분류에 필요한 미세한 디테일을 포착하는 고해상도 이미지

Source:

세 가지 아키텍처 (그리고 내가 선택한 이유)

EfficientNet – 균형 잡힌 모델

EfficientNet는 compound scaling을 통해 깊이, 너비, 해상도를 함께 확장하여, 계산량이 크게 늘지 않으면서도 높은 정확도를 제공합니다. 이미지‑분류 작업에서 효율성과 강력한 성능 때문에 선택했습니다.

MobileNetV2 – 경량 챔피언

모바일 기기를 위해 설계된 MobileNetV2는 depthwise separable convolutions을 사용해 적은 연산으로 더 많은 일을 수행합니다. 농장 한가운데서 라즈베리 Pi 혹은 스마트폰에 배포하기에 완벽합니다. 농부들을 위한 현장 앱을 만든다면 제가 가장 먼저 선택할 모델입니다.

ResNet50 – 헤비웨이트

ResNet50는 skip connections을 도입해 매우 깊은 네트워크도 기울기 소실 없이 학습할 수 있게 합니다. 더 깊고 강력하며, 비교를 위한 견고한 기준선을 제공합니다.

실제 작동 방식

모든 세 모델은 transfer learning을 사용합니다—ImageNet으로 사전 학습되어 있어 이미 가장자리, 텍스처, 형태를 알고 있습니다.

# Freeze the pretrained layers at first
base_model = EfficientNetB0(weights='imagenet', include_top=False)
base_model.trainable = False

# Add custom classification layers on top
model = Sequential([
    base_model,
    GlobalAveragePooling2D(),
    Dense(256, activation='relu'),
    Dropout(0.5),
    Dense(num_classes, activation='softmax')
])

왜 Transfer Learning인가?

  1. 학습 속도가 빠릅니다
  2. 필요한 데이터 양이 적습니다
  3. 더 나은 결과를 얻을 수 있습니다

학습 파이프라인

  1. Resize 이미지를 각 모델이 기대하는 입력 크기(보통 224×224)로 조정합니다.
  2. Normalize ImageNet 통계값을 사용해 정규화합니다.
  3. Data augmentation(플립, 회전, 밝기 조정 등)을 적용해 과도한 기억을 방지합니다.
  4. Batch training으로 GPU가 원활히 작동하도록 합니다.

각 모델이 어느 부분에서 어려움을 겪는지 확인하기 위해 accuracy, precision, recall, F1‑score, 그리고 confusion matrices와 같은 일반적인 지표들을 추적했습니다.

시작하기 (시도해 보고 싶다면)

필요 사항

pip install tensorflow keras numpy pandas matplotlib scikit-learn

코드 가져오기

git clone https://github.com/sisodiajatin/FruitScan-AI.git
cd FruitScan-AI

저장소 구조

FruitScan-AI/
├── EfficientNet/   # EfficientNet notebooks
├── MobileNetV2/    # MobileNetV2 experiments
└── ResNet50/      # ResNet50 implementation

노트북 실행

cd EfficientNet   # or whichever model you want
jupyter notebook
# Open the training notebook and run it cell by cell

예측 수행

# Load your model
model = tf.keras.models.load_model('fruit_disease_model.h5')

# Prepare the image
img = tf.keras.utils.load_img('suspicious_apple.jpg', target_size=(224, 224))
img_array = tf.keras.utils.img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
img_array = tf.keras.applications.efficientnet.preprocess_input(img_array)

# Get prediction
predictions = model.predict(img_array)
class_idx = np.argmax(predictions[0])

print(f"This looks like: {class_labels[class_idx]}")
print(f"Confidence: {predictions[0][class_idx] * 100:.2f}%")

간단한 Flask 래퍼 (API)

from flask import Flask, request, jsonify
import tensorflow as tf

app = Flask(__name__)
model = tf.keras.models.load_model('best_model.h5')

@app.route('/predict', methods=['POST'])
def predict():
    # Expect an image file under the key 'file'
    file = request.files['file']
    img = tf.keras.utils.load_img(file, target_size=(224, 224))
    img_array = tf.keras.utils.img_to_array(img)
    img_array = np.expand_dims(img_array, axis=0)
    img_array = tf.keras.applications.efficientnet.preprocess_input(img_array)

    preds = model.predict(img_array)
    class_idx = np.argmax(preds[0])
    confidence = preds[0][class_idx] * 100

    return jsonify({
        'class': class_labels[class_idx],
        'confidence': f'{confidence:.2f}%'
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

마무리 생각

각 아키텍처는 다양한 상황에서 빛을 발합니다:

  • EfficientNet – 전반적인 정확도와 효율성 비율이 가장 뛰어납니다.
  • MobileNetV2 – 리소스가 제한된 디바이스에서 추론하기에 이상적입니다.
  • ResNet50 – 강력한 베이스라인을 제공하며, 충분한 연산 자원이 있을 때 뛰어납니다.

자유롭게 탐색하고, 조정하며, 코드를 여러분의 과일 질병 감지 프로젝트에 맞게 적용하세요!

def predict():
    file = request.files['image']
    img = preprocess_image(file)
    prediction = model.predict(img)

    return jsonify({
        'fruit': get_fruit_name(prediction),
        'status': 'healthy' if is_healthy(prediction) else 'diseased',
        'confidence': float(np.max(prediction))
    })

그럼… 어떤 모델이 이겼을까?

솔직히? 무엇을 최적화하느냐에 따라 달라요.

모델정확도속도 (이미지당)크기 / 사용 사례
EfficientNet92 % – 95 %30 ms – 50 ms전반적으로 좋음
MobileNetV288 % – 91 %10 ms – 20 ms빠르고 작음 – 모바일 앱에 최적
ResNet5090 % – 93 %50 ms – 80 ms느리고 크다 – 연구용이나 정확도가 가장 중요한 경우에 적합

직접 사용해 보세요!

이것이 흥미롭게 들린다면:

레포에 별표 달기

Back to Blog

관련 글

더 보기 »