JSON модели для Data Science: сохранение и загрузка ML объектов

Раздел: Data Science -> Работа с моделями ML

Работа с JSON моделями в Python для Data Science

Как создать и сериализовать модель данных ML с валидацией?

Наиболее эффективный способ - использование библиотеки pydantic. Она позволяет определить классы данных с автоматической валидацией и сериализацией в JSON. Модели pydantic подходят для описания конфигураций, гиперпараметров, архитектур нейросетей и сохранения результатов предсказаний.


from pydantic import BaseModel
from typing import List, Optional
import json

class ModelConfig(BaseModel):
    model_name: str
    learning_rate: float = 0.001
    layers: List[int]
    activation: str = 'relu'
    dropout: Optional[float] = None

config = ModelConfig(
    model_name='cnn',
    learning_rate=0.0005,
    layers=[32, 64, 128],
    activation='tanh',
    dropout=0.2
)
json_str = config.model_dump_json(indent=2)
print(json_str)
  

Json model python (модель json в python)

{
  "model_name": "cnn",
  "learning_rate": 0.0005,
  "layers": [32, 64, 128],
  "activation": "tanh",
  "dropout": 0.2
}
  

При загрузке JSON данные автоматически валидируются: неправильные типы вызывают ошибку ValidationError. Это предотвращает использование повреждённых конфигураций в ML пайплайне.

Типичная ошибка: сериализация объектов, которые не являются примитивами JSON (например, numpy массивы). Pydantic не поддерживает их напрямую. Решение - использовать кастомные валидаторы или преобразовывать массивы в списки перед созданием модели.

Как сохранить состояние обученной ML модели в JSON с помощью стандартного модуля json?

Библиотека json в Python не умеет сериализовывать сложные объекты, такие как модели scikit-learn или TensorFlow. Но можно сохранить гиперпараметры и веса, преобразовав их в словарь. Для этого пишется кастомный JSONEncoder.


import json
import numpy as np

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return super().default(obj)

weights = {'layer1': np.random.rand(3,3)}
with open('model_weights.json', 'w') as f:
    json.dump(weights, f, cls=NumpyEncoder)
  

При загрузке массивы восстанавливаются из списков обратно в numpy через np.array(). Метод подходит для простых ML алгоритмов, где все параметры умещаются в словарь.

Проблема: потеря информации о типе данных (например, float32 вместо float64). Чтобы избежать потерь, можно сохранять в JSON дополнительное поле dtype.

Как обеспечить обратную совместимость схем JSON для ML моделей?

Когда модель обновляется, а старые JSON‑конфиги должны работать - помогает использование JSON Schema и библиотеки jsonschema. Определите схему, а при загрузке валидируйте её. Допускаются умолчания для отсутствующих полей.


from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "model_name": {"type": "string"},
        "layers": {"type": "array", "items": {"type": "integer"}},
        "activation": {"type": "string", "default": "relu"}
    },
    "required": ["model_name", "layers"]
}

data = {"model_name": "lstm", "layers": [50]}
try:
    validate(instance=data, schema=schema)
    print("JSON корректен")
except ValidationError as e:
    print(f"Ошибка: {e.message}")
  

Этот подход применяется в MLOps для инвариантной загрузки параметров между версиями моделей.

Сложность: поддержка схемы вручную при изменении структуры модели. Рекомендуется генерировать схему автоматически из pydantic модели методом model_json_schema().

Расширенные примеры работы с JSON моделями ML

1. Сериализация полной модели scikit-learn с помощью jsonpickle

Библиотека jsonpickle позволяет сериализовать произвольные Python-объекты, включая обученные модели, с сохранением классов. Это удобно для быстрого прототипирования, но не рекомендуется для продакшна из-за рисков безопасности.

Пример

import jsonpickle
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=100, random_state=42)
model = RandomForestClassifier(n_estimators=10, random_state=42)
model.fit(X, y)

# Сериализация
model_json = jsonpickle.encode(model, indent=2)
with open('rf_model.json', 'w') as f:
    f.write(model_json)

# Десериализация
with open('rf_model.json', 'r') as f:
    loaded_model = jsonpickle.decode(f.read())

# Проверка
predictions = loaded_model.predict(X[:5])
print(predictions)  # [0 1 0 1 0]
[0 1 0 1 0]

Проблемы: десериализация может выполнить произвольный код, если JSON был подделан. Используйте только для доверенных файлов.

2. Преобразование датакласса в JSON с помощью dataclasses + json

Стандартный модуль dataclasses в Python 3.7+ даёт чистый синтаксис для хранения данных ML (например, результатов экспериментов).

Пример

from dataclasses import dataclass, asdict
import json

@dataclass
class Metrics:
    accuracy: float
    f1_score: float
    timestamp: str

metrics = Metrics(accuracy=0.94, f1_score=0.92, timestamp='2025-03-25T12:00:00')
json_str = json.dumps(asdict(metrics), indent=2)
print(json_str)
{
  "accuracy": 0.94,
  "f1_score": 0.92,
  "timestamp": "2025-03-25T12:00:00"
}

Недостаток: нет валидации. Для больших проектов используйте pydantic.

3. Загрузка JSON конфига нейронной сети с автоматическим восстановлением объектов TensorFlow/Keras

Сложные ML модели часто хранят архитектуру в виде JSON (например, формат model.to_json() в Keras). Покажем, как объединить конфиг с весами.

Пример

import tensorflow as tf
import json

# Создаём простую модель
model = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation='relu', input_shape=(5,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

# Сохраняем архитектуру в JSON
arch_json = model.to_json()
with open('model_arch.json', 'w') as f:
    f.write(arch_json)

# Сохраняем веса отдельно (сериализация в JSON через numpy)
weights = [layer.get_weights() for layer in model.layers]
serialized_weights = {
    str(i): [w.tolist() if hasattr(w, 'tolist') else w for w in layer_weights]
    for i, layer_weights in enumerate(weights)
}
with open('model_weights.json', 'w') as f:
    json.dump(serialized_weights, f, indent=2)

# Восстановление
with open('model_arch.json', 'r') as f:
    new_model = tf.keras.models.model_from_json(f.read())
with open('model_weights.json', 'r') as f:
    loaded_weights = json.load(f)
# Приводим обратно к numpy
import numpy as np
for i, layer in enumerate(new_model.layers):
    w = [np.array(arr) for arr in loaded_weights[str(i)]]
    layer.set_weights(w)

print("Модель восстановлена", new_model.summary())
Модель восстановлена
...

Такой подход позволяет хранить архитектуру в читаемом JSON, а веса - в том же формате, но преобразованные в списки.

4. Генерация JSON Schema из pydantic модели для документирования API ML

Пример

from pydantic import BaseModel, Field
from typing import List, Optional

class PredictionRequest(BaseModel):
    features: List[float] = Field(..., description="Входные признаки модели")
    model_version: Optional[str] = "v1.0"

schema = PredictionRequest.model_json_schema()
print(json.dumps(schema, indent=2))
{
  "$defs": {},
  "properties": {
    "features": {
      "items": {"type": "number"},
      "title": "Features",
      "type": "array",
      "description": "Входные признаки модели"
    },
    "model_version": {
      "anyOf": [{"type": "string"}, {"type": "null"}],
      "default": "v1.0",
      "title": "Model Version"
    }
  },
  "required": ["features"],
  "title": "PredictionRequest",
  "type": "object"
}

Схему можно использовать для автоматической валидации входящих запросов к ML‑сервису.

Модель JSON в Python - comments

En
Json model python (python)