general-deep-learning / test /tasks /image_classification_gradio_test.py
yetrun's picture
ver3: 将源码迁入 src/deep_learning 包,重塑训练流水线,规范 data/model 契约,并补齐文档与测试
2c90129
Raw
History Blame Contribute Delete
6.35 kB
from pathlib import Path
import gradio as gr
import numpy as np
from tasks.image_classification.gradio import (
ImageClassificationAppBuilder,
ImageClassificationPageAdapter,
ImageClassificationTool
)
from tasks.image_classification.runner import pipeline as task_pipeline
class DummyModel:
def __init__(self, probability: float):
self.probability = probability
def __call__(self, model_input, training=False):
return np.asarray([[self.probability]], dtype="float32")
class DummyArtifact:
def __init__(self, probability: float):
self.model = DummyModel(probability)
class DummyTool:
def classify(self, image):
return "预测类别:dog,概率:90.00%"
class DummyCheckpointLoadRules:
def __init__(self, model_dir: Path):
self.model_dir = model_dir
def resolve_test_rule(self, default_dirs):
return {
"dirs": [self.model_dir],
"suffix": None
}
class DummyModelBuilder:
def load_inference_artifact(self, model_path):
return DummyArtifact(0.7)
class DummyPipeline:
def __init__(self, name: str, model_dir: Path):
self.name = name
self.checkpoint_load_rules = DummyCheckpointLoadRules(model_dir)
self.model_builder = DummyModelBuilder()
def create_image_classification_app_builder(tmp_path):
model_dir = tmp_path / "models" / "image_classification_test"
model_dir.mkdir(parents=True)
(model_dir / "model_epoch_001.keras").write_text("stub", encoding="utf-8")
return ImageClassificationAppBuilder(
pipeline=DummyPipeline("image_classification_test", model_dir),
tool_factory=lambda inference_artifact, resource: DummyTool(),
sample_images=["sample.jpg"],
load_sample_image=lambda sample_name: np.zeros((8, 8, 3), dtype="uint8"),
title="测试图片分类页面"
)
def test_image_classification_app_builder_can_create_ui(tmp_path):
"""验证图片分类 Gradio 页面可以创建 Blocks。"""
builder = create_image_classification_app_builder(tmp_path)
demo = builder.create_ui()
assert isinstance(demo, gr.Blocks)
def test_image_classification_app_builder_configures_prediction_flow(tmp_path):
"""验证图片分类页面包含示例选择、分类按钮和预测结果输出。"""
builder = create_image_classification_app_builder(tmp_path)
demo = builder.create_ui()
config = demo.get_config_file()
input_image = next(
component for component in config["components"]
if component["type"] == "image" and component["props"].get("label") == "输入图片"
)
output_text = next(
component for component in config["components"]
if component["type"] == "textbox" and component["props"].get("label") == "预测结果"
)
dropdown = next(
component for component in config["components"]
if component["type"] == "dropdown" and component["props"].get("label") == "示例图片"
)
buttons = [component for component in config["components"] if component["type"] == "button"]
dependencies = config["dependencies"]
assert dropdown["props"]["value"] is None
assert len(buttons) == 1
assert buttons[0]["props"]["value"] == "开始分类"
assert any(
dependency["targets"] == [(dropdown["id"], "change")]
and dependency["inputs"] == [dropdown["id"]]
and dependency["outputs"] == [input_image["id"]]
for dependency in dependencies
)
assert any(
dependency["targets"] == [(buttons[0]["id"], "click")]
and dependency["inputs"] == [input_image["id"]]
and dependency["outputs"] == [output_text["id"]]
for dependency in dependencies
)
def test_image_classification_app_builder_uses_single_input_image(tmp_path):
"""验证选择示例图片后会把当前输入图片交给分类工具。"""
builder = create_image_classification_app_builder(tmp_path)
builder._tool = DummyTool()
selected_image = builder.select_sample_image("sample.jpg")
result = builder.classify_image(selected_image)
assert selected_image.shape == (8, 8, 3)
assert result == "预测类别:dog,概率:90.00%"
def test_image_classification_app_builder_loads_deployment_model_without_training_data(tmp_path):
"""验证图片分类推理加载只读取部署模型,不读取训练数据目录。"""
builder = create_image_classification_app_builder(tmp_path)
inference_artifact, resource = builder._load_inference_artifact()
assert isinstance(inference_artifact.model, DummyModel)
assert resource is None
def test_image_classification_page_adapter_lists_sample_images():
"""验证图片分类示例图片列表来自分类 dev 示例目录。"""
adapter = ImageClassificationPageAdapter(task_pipeline)
sample_images = adapter.list_sample_images()
assert len(sample_images) == 10
assert sample_images[0].endswith(".jpg")
assert "/" not in sample_images[0]
def test_image_classification_page_adapter_loads_rgb_sample_image():
"""验证选择分类示例图片会读取为 RGB 图片数组。"""
adapter = ImageClassificationPageAdapter(task_pipeline)
sample_name = adapter.list_sample_images()[0]
image = adapter.load_sample_image(sample_name)
assert image.shape[-1] == 3
assert image.dtype == np.uint8
def test_image_classification_tool_returns_highest_probability_class():
"""验证图片分类工具只返回最大概率类别及该类别概率。"""
tool = ImageClassificationTool(
DummyPipeline("unused", Path("unused")),
DummyArtifact(0.8),
None,
(2, 3),
["cat", "dog"]
)
image = np.zeros((4, 5, 3), dtype="uint8")
result = tool.classify(image)
assert result == "预测类别:dog,概率:80.00%"
def test_image_classification_tool_converts_low_sigmoid_to_first_class():
"""验证 sigmoid 小于 0.5 时会返回第一个类别及反向概率。"""
tool = ImageClassificationTool(
DummyPipeline("unused", Path("unused")),
DummyArtifact(0.2),
None,
(2, 3),
["cat", "dog"]
)
image = np.zeros((4, 5, 3), dtype="uint8")
result = tool.classify(image)
assert result == "预测类别:cat,概率:80.00%"