yetrun's picture
ver3: 将源码迁入 src/deep_learning 包,重塑训练流水线,规范 data/model 契约
07cb7d3
Raw
History Blame Contribute Delete
2.9 kB
from dataclasses import dataclass
from pathlib import Path
import keras
import keras_hub
from keras import layers
from .losses import box_loss
from deep_learning.models.spec import ModelArtifact, SupervisedModelBuilder
def build_yolo_preprocessor(image_size: int = 448):
inputs = keras.Input(shape=(None, None, 3), dtype="uint8")
x = layers.Resizing(
image_size,
image_size,
interpolation="bicubic",
crop_to_aspect_ratio=True
)(inputs)
x = layers.Rescaling(
scale=[0.017124753831663668, 0.01750700280112045, 0.017429193899782133],
offset=[-2.1179039301310043, -2.0357142857142856, -1.8044444444444445]
)(x)
return keras.Model(inputs, x, name="yolo_preprocessor")
@dataclass
class YoloModelBuilder(SupervisedModelBuilder):
image_size: int
grid_size: int
num_labels: int
backbone_preset: str = "resnet_50_imagenet"
def build_training_artifact(self) -> ModelArtifact:
backbone = keras_hub.models.Backbone.from_preset(self.backbone_preset)
inputs = keras.Input(shape=(self.image_size, self.image_size, 3))
x = backbone(inputs)
x = layers.Conv2D(512, (3, 3), strides=(2, 2))(x)
x = layers.Flatten()(x)
x = layers.Dense(2048, activation="relu", kernel_initializer="glorot_normal")(x)
x = layers.Dropout(0.5)(x)
x = layers.Dense(self.grid_size * self.grid_size * (self.num_labels + 5))(x)
x = layers.Reshape((self.grid_size, self.grid_size, self.num_labels + 5))(x)
box_predictions = x[..., :5]
class_predictions = layers.Activation("softmax")(x[..., 5:])
outputs = {"box": box_predictions, "class": class_predictions}
model = keras.Model(inputs, outputs, name="yolo")
return ModelArtifact(model=model)
def convert_to_inference_artifact(
self,
training_artifact: ModelArtifact
) -> ModelArtifact:
inputs = keras.Input(shape=(None, None, 3), dtype="uint8")
preprocessor = build_yolo_preprocessor(image_size=self.image_size)
x = preprocessor(inputs)
outputs = training_artifact.model(x)
inference_model = keras.Model(inputs, outputs, name="yolo_inference")
return ModelArtifact(model=inference_model)
def load_inference_artifact(self, model_path: Path) -> ModelArtifact:
model = keras.models.load_model(
str(model_path),
custom_objects=self._custom_objects()
)
return ModelArtifact(model=model)
def _custom_objects(self) -> dict:
return {
"box_loss": box_loss
}
def compile_training_model(self, model: keras.Model) -> None:
model.compile(
optimizer=keras.optimizers.Adam(2e-4),
loss={
"box": box_loss,
"class": "sparse_categorical_crossentropy"
}
)