본문 바로가기

dev_AI_framework

모델 모듈의 개발

keras - model.py 파일 내용 확인

주요 구성 요소 및 기능

if backend.backend() == "tensorflow":
    from keras.src.backend.tensorflow.trainer import TensorFlowTrainer as Trainer
elif backend.backend() == "jax":
    from keras.src.backend.jax.trainer import JAXTrainer as Trainer
elif backend.backend() == "torch":
    from keras.src.backend.torch.trainer import TorchTrainer as Trainer
elif backend.backend() == "numpy":
    from keras.src.backend.numpy.trainer import NumpyTrainer as Trainer
else:
    raise RuntimeError(f"Backend '{backend.backend()}' must implement the Trainer class.")
  1. 백엔드 종속적인 트레이너 클래스 선택
    • 현재 사용 중인 백엔드에 따라 적절한 Trainer 클래스를 가져온다.
    • 여러 백엔드를 지원하며 백엔드에 따라 최적화된 트레이너 클래스를 사용해 모델을 학습시킬 수 있다. 

 

Model 클래스 정의

모델을 구성하고 관리하는 핵심 클래스, 레이어들을 그룹화하여 학습 및 추론 기능을 제공하는 객체로 사용된다.

상속 구조 : Trainer, base_trainer.Trainer, Layer 클래스를 상속받는다. 

모델 인스턴스화 방법 : Model 클래스는 세 가지 주요 방법으로 인스턴스화할 수 있다. 

  1. Functional API
    • Input 객체에서 시작하여 레이어 호출을 체인으로 연결하여 모델의 포워드 패스를 정의할 수 있다.
    • 모델의 구조가 복잡하거나 다중 입력, 다중 출력을 다루는 경우에 유용, 
    • 중간 텐서를 사용하여 모델의 서브 컴포넌트를 쉽게 추출할 수 있다.
  2. Subclassing (모델 서브클래싱)
    •  Model 클래스를 서브클래싱하여 커스텀 모델을 정의할 수 있다.
    • init 메서드에서 레이어를 정의하고 call 메서드에서 모델의 포워드 패스를 구현한다.
    • call 메서드는 모델이 학습 중일 때와 추론 중일 때 다른 동작을 수행하도록 training 인자를 받을 수 있다.
    • 복잡한 동작을 하는 모델을 정의하거나 Functional API 로 정의하기 어려운 모델을 만들 때 유용하다.
  3. Sequential API
    • 단일 입력, 단일 출력의 레이어를 순차적으로 쌓아올리는 간단한 모델 정의 시 사용
    • 순차적인 모델 구조가 명확할 때, 이를 사용하여 코드의 간결한 작성

상속 구조

  • Trainer : 모델 학습과 관련된 기능을 제공하는 클래스
  • base_trainer.Trainer : 기본 트레이너 클래스, 공통 학습 기능을 제공
  • Layer: 기본 레이어 클래스, 레이어와 모델의 공통 기능을 정의

모델 구성 및 학습

  • 모델 생성 후 model.compile() - 손실 함수, 옵티마이저, 평가 지표 등을 설정 가능
  • 설정 후 model.fit() - 모델 학습, model.predict() - 새로운 데이터에 대한 예측 수행 가능
## With the "Functional API"

    You start from `Input`,
    you chain layer calls to specify the model's forward pass,
    and finally, you create your model from inputs and outputs:

    ```python
    inputs = keras.Input(shape=(37,))
    x = keras.layers.Dense(32, activation="relu")(inputs)
    outputs = keras.layers.Dense(5, activation="softmax")(x)
    model = keras.Model(inputs=inputs, outputs=outputs)
    ```

    Note: Only dicts, lists, and tuples of input tensors are supported. Nested
    inputs are not supported (e.g. lists of list or dicts of dict).

    A new Functional API model can also be created by using the
    intermediate tensors. This enables you to quickly extract sub-components
    of the model.

    Example:

    ```python
    inputs = keras.Input(shape=(None, None, 3))
    processed = keras.layers.RandomCrop(width=128, height=128)(inputs)
    conv = keras.layers.Conv2D(filters=32, kernel_size=3)(processed)
    pooling = keras.layers.GlobalAveragePooling2D()(conv)
    feature = keras.layers.Dense(10)(pooling)

    full_model = keras.Model(inputs, feature)
    backbone = keras.Model(processed, conv)
    activations = keras.Model(conv, feature)
    ```

    Note that the `backbone` and `activations` models are not
    created with `keras.Input` objects, but with the tensors that originate
    from `keras.Input` objects. Under the hood, the layers and weights will
    be shared across these models, so that user can train the `full_model`, and
    use `backbone` or `activations` to do feature extraction.
    The inputs and outputs of the model can be nested structures of tensors as
    well, and the created models are standard Functional API models that support
    all the existing APIs.

 

## By subclassing the `Model` class

    In that case, you should define your
    layers in `__init__()` and you should implement the model's forward pass
    in `call()`.

    ```python
    class MyModel(keras.Model):
        def __init__(self):
            super().__init__()
            self.dense1 = keras.layers.Dense(32, activation="relu")
            self.dense2 = keras.layers.Dense(5, activation="softmax")

        def call(self, inputs):
            x = self.dense1(inputs)
            return self.dense2(x)

    model = MyModel()
    ```

    If you subclass `Model`, you can optionally have
    a `training` argument (boolean) in `call()`, which you can use to specify
    a different behavior in training and inference:

    ```python
    class MyModel(keras.Model):
        def __init__(self):
            super().__init__()
            self.dense1 = keras.layers.Dense(32, activation="relu")
            self.dense2 = keras.layers.Dense(5, activation="softmax")
            self.dropout = keras.layers.Dropout(0.5)

        def call(self, inputs, training=False):
            x = self.dense1(inputs)
            x = self.dropout(x, training=training)
            return self.dense2(x)

    model = MyModel()
    ```

    Once the model is created, you can config the model with losses and metrics
    with `model.compile()`, train the model with `model.fit()`, or use the model
    to do prediction with `model.predict()`.

 

## With the `Sequential` class

    In addition, `keras.Sequential` is a special case of model where
    the model is purely a stack of single-input, single-output layers.

    ```python
    model = keras.Sequential([
        keras.Input(shape=(None, None, 3)),
        keras.layers.Conv2D(filters=32, kernel_size=3),
    ])
    ```

각 인스턴스화 방식의 예시

 

    def __new__(cls, *args, **kwargs):
        # Signature detection for usage of `Model` as a `Functional`
        if functional_init_arguments(args, kwargs) and cls == Model:
            from keras.src.models.functional import Functional

            return Functional.__new__(Functional, *args, **kwargs)
        return typing.cast(Model, super().__new__(cls))

Model 클래스가 인스턴스화 될 때 호출

객체를 생성하기 전에 클래스의 인스턴스를 제어하거나 변경할 수 있는 특별한 메서드

주어진 인자가 Functional API 에 맞는지 확인

def functional_init_arguments(args, kwargs):
    return (
        (len(args) == 2)
        or (len(args) == 1 and "outputs" in kwargs)
        or ("inputs" in kwargs and "outputs" in kwargs)
    )

Functional API 에 해당하지 않는다면 기본 Model 클래스의 인스턴스를 생성한다.

 

 def __init__(self, *args, **kwargs):
        Trainer.__init__(self)
        from keras.src.models import functional

        # Signature detection for usage of a `Model` subclass
        # as a `Functional` subclass
        if functional_init_arguments(args, kwargs):
            inject_functional_model_class(self.__class__)
            functional.Functional.__init__(self, *args, **kwargs)
        else:
            Layer.__init__(self, *args, **kwargs)

인스턴스가 생성될 때 호출된다. API 스타일에 따라 초기화 로직의 분리

  • Trainer 초기화
    • 모델의 학습과 관련된 기능을 제공
  • Functional API 감지 및 초기화
  • Layer 모델 초기화
def inject_functional_model_class(cls):
    """Inject `Functional` into the hierarchy of this class if needed."""
    from keras.src.models import functional

    if cls == Model:
        return functional.Functional
    # In case there is any multiple inheritance, we stop injecting the
    # class if keras model is not in its class hierarchy.
    if cls == object:
        return object

    cls.__bases__ = tuple(
        inject_functional_model_class(base) for base in cls.__bases__
    )
    # Trigger any `__new__` class swapping that needed to happen on `Functional`
    # but did not because functional was not in the class hierarchy.
    cls.__new__(cls)

    return cls

클래스 import

Model 클래스 확인 : 전달된 클래스가 Model 클래스와 동일한지 확인, 주어진 클래스가 Model 자체라면 Functional 클래스가 기본적으로 상속 계층에 들어가야 한다는 것

다중 상속 처리 : model 이 아닌 object 클래스라면, object 반환 - 모든 파이썬 클래스의 기본 부모 클래스

상속 계층에 Functional 클래스 삽입, 재귀적 처리로 상속 계층에서 functional 클래스를 주입할 위치를 결정, 

functional 클래스가 주입되면 __new__ 메서드 트리거, 이를 통해 Functional 클래스가 포함된 새로운 클래스를 올바르게 초기화한다. 상속 계층이 변경되었을 때 새로운 객체 생성 방식을 반영하기 위함

최종 클래스 반환

 

 

call 메서드

def call(self, *args, **kwargs):
        raise NotImplementedError(
            f"Model {self.__class__.__name__} does not have a `call()` "
            "method implemented."
        )

서브 클래싱 된 모델에서 반드시 오버라이드 해야 하는 메서드

이 메서드는 입력 데이터를 어떻게 처리할지에 대한 로직을 집접적으로 구현하는 곳, 

 

 

layer 메서드

@property
    def layers(self):
        return list(self._flatten_layers(include_self=False, recursive=False))

property 데코레이터를 통해 메서드를 호출할 때 () 없이 속성처럼 접근할 수 있다는 것

 

아래는 `Model` 클래스와 관련된 각 메서드 및 함수에 대한 간단한 설명입니다:

### `__new__(cls, *args, **kwargs)`
- **설명**: `Model` 클래스의 인스턴스를 생성할 때 호출됩니다. 만약 주어진 인자들이 Functional API에 해당하는 경우, `Functional` 클래스를 사용하여 인스턴스를 생성합니다. 그렇지 않으면 기본 `Model` 클래스를 사용하여 인스턴스를 생성합니다.

### `__init__(self, *args, **kwargs)`
- **설명**: `Model` 클래스의 인스턴스를 초기화하는 메서드입니다. Functional API를 사용하는지 확인하고, 이에 따라 `Functional` 클래스를 상속하거나, 그렇지 않으면 일반적인 `Layer` 클래스를 초기화합니다.

### `call(self, *args, **kwargs)`
- **설명**: 서브클래싱된 `Model` 클래스에서 오버라이드해야 하는 메서드로, 모델의 순전파(forward pass)를 정의합니다. 이 메서드는 기본 `Model` 클래스에서 구현되어 있지 않으며, 호출되면 `NotImplementedError`를 발생시킵니다.

### `layers`
- **설명**: 모델에 포함된 레이어들을 리스트 형태로 반환하는 속성입니다. 이 속성에 접근하면 모델의 레이어들을 평탄화하여 반환합니다.

### `layers.setter`
- **설명**: `layers` 속성을 설정하려고 하면 `AttributeError`를 발생시킵니다. `layers` 속성은 읽기 전용입니다.

### `get_layer(self, name=None, index=None)`
- **설명**: 레이어를 이름이나 인덱스를 기준으로 검색하고 반환하는 메서드입니다. 이름과 인덱스가 모두 제공된 경우 인덱스가 우선합니다. 레이어를 찾을 수 없으면 오류를 발생시킵니다.

### `summary(self, line_length=None, positions=None, print_fn=None, expand_nested=False, show_trainable=False, layer_range=None)`
- **설명**: 모델의 구조를 요약하여 출력하는 메서드입니다. 모델의 레이어와 파라미터의 개요를 보기 쉽게 출력해줍니다.

### `save(self, filepath, overwrite=True, zipped=None, **kwargs)`
- **설명**: 모델을 `.keras` 파일로 저장하는 메서드입니다. 모델의 구조, 가중치, 옵티마이저 상태 등을 저장합니다.

### `save_weights(self, filepath, overwrite=True)`
- **설명**: 모델의 모든 가중치를 `.weights.h5` 파일로 저장하는 메서드입니다. 모델의 아키텍처와 상관없이 가중치만 저장됩니다.

### `load_weights(self, filepath, skip_mismatch=False, **kwargs)`
- **설명**: 저장된 가중치를 모델에 불러오는 메서드입니다. 저장된 가중치가 모델의 아키텍처와 일치하지 않을 경우 오류를 발생시키거나, 오류를 무시하도록 설정할 수 있습니다.

### `quantize(self, mode, **kwargs)`
- **설명**: 모델의 가중치를 양자화(quantize)하는 메서드입니다. 주로 모델 크기를 줄이거나 성능을 최적화하는 데 사용됩니다.

### `build_from_config(self, config)`
- **설명**: 주어진 설정(config)으로부터 모델을 구성하는 메서드입니다. 모델이 특정 설정을 기반으로 자동으로 빌드될 수 있도록 돕습니다.

### `to_json(self, **kwargs)`
- **설명**: 모델의 구성(configuration)을 JSON 문자열로 반환하는 메서드입니다. 이 JSON 문자열을 사용하여 나중에 동일한 모델을 재구성할 수 있습니다.

### `export(self, filepath, format="tf_saved_model")`
- **설명**: TensorFlow SavedModel 형식으로 모델을 내보내는 메서드입니다. 모델을 서버 환경에서 사용할 수 있도록 준비합니다.

### `from_config(cls, config, custom_objects=None)`
- **설명**: 모델의 설정(config)으로부터 모델을 생성하는 클래스 메서드입니다. 주어진 설정에 따라 모델을 재구성합니다.

### `_get_variable_map(self)`
- **설명**: 모델의 변수들을 맵핑하여 저장할 수 있는 형태로 반환하는 메서드입니다. 모델의 가중치를 저장하고 복원하는 데 사용됩니다.

### `model_from_json(json_string, custom_objects=None)`
- **설명**: JSON 문자열로 인코딩된 모델 설정으로부터 모델 인스턴스를 생성하는 함수입니다. 저장된 JSON 구성을 사용하여 모델을 재구성합니다.

### `functional_init_arguments(args, kwargs)`
- **설명**: 주어진 인자들이 Functional API 초기화에 해당하는지 확인하는 함수입니다. 이를 통해 Functional API에 따라 모델을 구성할지 여부를 결정합니다.

### `inject_functional_model_class(cls)`
- **설명**: 주어진 클래스에 `Functional` 클래스를 동적으로 주입하는 함수입니다. 필요한 경우 `Functional` 클래스를 상속 계층에 추가합니다.

이 메서드와 함수들은 Keras의 `Model` 클래스가 다양한 방식으로 모델을 정의하고 관리할 수 있도록 하는 핵심적인 구성 요소들입니다.