Instructions to use flowrs-cnn-makers/flower-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use flowrs-cnn-makers/flower-model with Keras:
# Available backend options are: "jax", "torch", "tensorflow". import os os.environ["KERAS_BACKEND"] = "jax" import keras model = keras.saving.load_model("hf://flowrs-cnn-makers/flower-model") - Notebooks
- Google Colab
- Kaggle
| # app.py - версия с двумя моделями | |
| import gradio as gr | |
| import numpy as np | |
| from PIL import Image | |
| import tensorflow as tf | |
| from tensorflow.keras.models import load_model | |
| import os | |
| # Конфигурация | |
| IMG_SIZE_150 = 150 | |
| IMG_SIZE_224 = 224 | |
| # Порядок классов | |
| CLASS_NAMES = ['Daisy', 'Dandelion', 'Rose', 'Sunflower', 'Tulip'] | |
| # Пути к моделям | |
| MODEL_150_PATH = 'flower_recognition_model.keras' # модель на 150x150 | |
| MODEL_224_PATH = 'final_ensemble_model.keras' # модель на 224x224 | |
| # Глобальные переменные | |
| model_150 = None | |
| model_224 = None | |
| def load_models(): | |
| """Загрузка обеих моделей""" | |
| global model_150, model_224 | |
| # Загрузка модели 150x150 | |
| try: | |
| if os.path.exists(MODEL_150_PATH): | |
| model_150 = load_model(MODEL_150_PATH) | |
| print(f"✅ Model 150x150 loaded from {MODEL_150_PATH}") | |
| else: | |
| print(f"⚠️ Model 150x150 not found at {MODEL_150_PATH}") | |
| except Exception as e: | |
| print(f"❌ Error loading model 150x150: {e}") | |
| # Загрузка модели 224x224 | |
| try: | |
| if os.path.exists(MODEL_224_PATH): | |
| model_224 = load_model(MODEL_224_PATH) | |
| print(f"✅ Model 224x224 loaded from {MODEL_224_PATH}") | |
| else: | |
| print(f"⚠️ Model 224x224 not found at {MODEL_224_PATH}") | |
| except Exception as e: | |
| print(f"❌ Error loading model 224x224: {e}") | |
| # Функции для обработки изображений | |
| try: | |
| import cv2 | |
| USE_CV2 = True | |
| print("✅ Using OpenCV for image processing") | |
| except ImportError: | |
| USE_CV2 = False | |
| print("⚠️ Using PIL fallback for image processing") | |
| def resize_image(img_array, target_size): | |
| """Ресайз изображения""" | |
| if USE_CV2: | |
| return cv2.resize(img_array, target_size) | |
| else: | |
| from PIL import Image | |
| img_pil = Image.fromarray(img_array.astype('uint8')) | |
| img_resized = img_pil.resize(target_size, Image.Resampling.LANCZOS) | |
| return np.array(img_resized) | |
| def convert_to_bgr(img_array): | |
| """Конвертация RGB -> BGR""" | |
| if USE_CV2: | |
| return cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR) | |
| else: | |
| return img_array[:, :, ::-1] | |
| def preprocess_image(image, img_size): | |
| """ | |
| Предобработка изображения для конкретной модели | |
| img_size: tuple (height, width) | |
| """ | |
| # Конвертируем PIL в numpy | |
| if isinstance(image, Image.Image): | |
| img_array = np.array(image) | |
| else: | |
| img_array = np.array(image) | |
| # Конвертируем RGB в BGR (как в Colab) | |
| img_bgr = convert_to_bgr(img_array) | |
| # Ресайз | |
| img_resized = resize_image(img_bgr, img_size) | |
| # Нормализация и добавление batch dimension | |
| img_normalized = img_resized / 255.0 | |
| img_batch = np.expand_dims(img_normalized, axis=0) | |
| return img_batch | |
| def predict_with_model(model, image, img_size, model_name): | |
| """Предсказание одной моделью""" | |
| if model is None: | |
| return None, f"❌ Модель {model_name} не загружена" | |
| try: | |
| processed_img = preprocess_image(image, img_size) | |
| predictions = model.predict(processed_img, verbose=0) | |
| predicted_index = np.argmax(predictions[0]) | |
| confidence = float(predictions[0][predicted_index]) | |
| predicted_flower = CLASS_NAMES[predicted_index] | |
| probabilities = { | |
| class_name: float(predictions[0][i]) | |
| for i, class_name in enumerate(CLASS_NAMES) | |
| } | |
| return { | |
| 'flower': predicted_flower, | |
| 'confidence': confidence, | |
| 'probabilities': probabilities, | |
| 'model': model_name | |
| }, None | |
| except Exception as e: | |
| return None, f"❌ Ошибка в модели {model_name}: {str(e)}" | |
| def predict_ensemble(image): | |
| """ | |
| Предсказание с использованием двух моделей | |
| Результат: усреднение предсказаний или выбор лучшего | |
| """ | |
| results = [] | |
| errors = [] | |
| # Предсказание моделью 150x150 | |
| if model_150 is not None: | |
| result_150, error_150 = predict_with_model( | |
| model_150, image, (IMG_SIZE_150, IMG_SIZE_150), "150x150" | |
| ) | |
| if result_150: | |
| results.append(result_150) | |
| elif error_150: | |
| errors.append(error_150) | |
| # Предсказание моделью 224x224 | |
| if model_224 is not None: | |
| result_224, error_224 = predict_with_model( | |
| model_224, image, (IMG_SIZE_224, IMG_SIZE_224), "224x224" | |
| ) | |
| if result_224: | |
| results.append(result_224) | |
| elif error_224: | |
| errors.append(error_224) | |
| if not results: | |
| error_msg = "\n".join(errors) if errors else "❌ Нет доступных моделей" | |
| return error_msg, None | |
| # Усредняем вероятности | |
| avg_probabilities = {} | |
| for class_name in CLASS_NAMES: | |
| probs = [r['probabilities'][class_name] for r in results] | |
| avg_probabilities[class_name] = np.mean(probs) | |
| # Выбираем класс с максимальной средней вероятностью | |
| predicted_index = np.argmax(list(avg_probabilities.values())) | |
| predicted_flower = CLASS_NAMES[predicted_index] | |
| avg_confidence = avg_probabilities[predicted_flower] | |
| # Определяем, какая модель была увереннее | |
| model_confidences = [] | |
| for r in results: | |
| model_confidences.append(f"{r['model']}: {r['confidence']:.1%}") | |
| model_info = " | ".join(model_confidences) | |
| # Формируем результат | |
| if avg_confidence > 0.7: | |
| confidence_emoji = "🎯" | |
| elif avg_confidence > 0.4: | |
| confidence_emoji = "👍" | |
| else: | |
| confidence_emoji = "🤔" | |
| # Сортируем вероятности | |
| sorted_probs = sorted(avg_probabilities.items(), key=lambda x: x[1], reverse=True) | |
| result_text = f""" | |
| ## 🌸 **{predicted_flower}** {confidence_emoji} | |
| ### Уверенность (ансамбль): **{avg_confidence:.1%}** | |
| --- | |
| **📊 Детали по моделям:** | |
| {model_info} | |
| **🎯 Вероятности по классам:** | |
| {chr(10).join([f"- {name}: {prob:.1%}" for name, prob in sorted_probs])} | |
| --- | |
| *Ансамбль из 2 нейросетей (150x150 и 224x224)* | |
| """ | |
| return result_text, avg_probabilities | |
| def predict_single_150(image): | |
| """Предсказание только моделью 150x150""" | |
| if model_150 is None: | |
| return "❌ Модель 150x150 не загружена", None | |
| result, error = predict_with_model( | |
| model_150, image, (IMG_SIZE_150, IMG_SIZE_150), "150x150" | |
| ) | |
| if error: | |
| return error, None | |
| # Форматируем результат | |
| sorted_probs = sorted(result['probabilities'].items(), key=lambda x: x[1], reverse=True) | |
| result_text = f""" | |
| ## 🌸 **{result['flower']}** | |
| ### Уверенность: **{result['confidence']:.1%}** | |
| *Модель: 150x150* | |
| --- | |
| **Вероятности:** | |
| {chr(10).join([f"- {name}: {prob:.1%}" for name, prob in sorted_probs])} | |
| """ | |
| return result_text, result['probabilities'] | |
| def predict_single_224(image): | |
| """Предсказание только моделью 224x224""" | |
| if model_224 is None: | |
| return "❌ Модель 224x224 не загружена", None | |
| result, error = predict_with_model( | |
| model_224, image, (IMG_SIZE_224, IMG_SIZE_224), "224x224" | |
| ) | |
| if error: | |
| return error, None | |
| # Форматируем результат | |
| sorted_probs = sorted(result['probabilities'].items(), key=lambda x: x[1], reverse=True) | |
| result_text = f""" | |
| ## 🌸 **{result['flower']}** | |
| ### Уверенность: **{result['confidence']:.1%}** | |
| *Модель: 224x224* | |
| --- | |
| **Вероятности:** | |
| {chr(10).join([f"- {name}: {prob:.1%}" for name, prob in sorted_probs])} | |
| """ | |
| return result_text, result['probabilities'] | |
| # Загружаем модели при старте | |
| load_models() | |
| # Создаем интерфейс Gradio | |
| with gr.Blocks(title="Flower Recognition - Ensemble of 2 CNNs", theme="soft") as demo: | |
| gr.Markdown(""" | |
| # 🌼 Flower Recognition - Ансамбль из 2 нейросетей 🌻 | |
| ### Определяет 5 видов цветов: Daisy, Dandelion, Rose, Sunflower, Tulip | |
| **🎯 Доступные модели:** | |
| - Модель 1: CNN 150x150 пикселей | |
| - Модель 2: CNN 224x224 пикселей (final_ensemble_model) | |
| - Ансамбль: усреднение предсказаний обеих моделей | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_image = gr.Image(label="📸 Загрузите фото цветка", type="pil", height=350) | |
| with gr.Row(): | |
| ensemble_btn = gr.Button("🎯 Ансамбль (2 модели)", variant="primary", size="lg") | |
| with gr.Row(): | |
| model150_btn = gr.Button("📱 Модель Оленбергер Данила", variant="secondary") | |
| model224_btn = gr.Button("💻 Модель Виговской Марии", variant="secondary") | |
| clear_btn = gr.Button("🗑️ Очистить", size="sm") | |
| with gr.Column(): | |
| output_text = gr.Markdown(label="📊 Результат", value="### ⏳ Выберите модель и загрузите фото") | |
| output_probs = gr.Label(label="📈 Вероятности по классам", num_top_classes=5) | |
| with gr.Row(): | |
| gr.Markdown(""" | |
| --- | |
| **💡 Как это работает:** | |
| - **Ансамбль** - использует обе модели и усредняет их предсказания (рекомендуется) | |
| - **150x150** - быстрая модель, хороша для простых случаев | |
| - **224x224** - более точная модель, требует больше ресурсов | |
| **🎨 Порядок цветов:** | |
| Daisy (Маргаритка) → Dandelion (Одуванчик) → Rose (Роза) → Sunflower (Подсолнух) → Tulip (Тюльпан) | |
| """) | |
| # Обработчики | |
| ensemble_btn.click( | |
| fn=predict_ensemble, | |
| inputs=input_image, | |
| outputs=[output_text, output_probs] | |
| ) | |
| model150_btn.click( | |
| fn=predict_single_150, | |
| inputs=input_image, | |
| outputs=[output_text, output_probs] | |
| ) | |
| model224_btn.click( | |
| fn=predict_single_224, | |
| inputs=input_image, | |
| outputs=[output_text, output_probs] | |
| ) | |
| clear_btn.click( | |
| fn=lambda: [None, "### ⏳ Выберите модель и загрузите фото", None], | |
| inputs=None, | |
| outputs=[input_image, output_text, output_probs] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |