SIENTIAPDE-1241: Remove model equation implementation documentation and add test coverage for _generate_artifacts in ModelRepository.
This commit is contained in:
@@ -1,78 +0,0 @@
|
|||||||
# Implementação da Equação do Modelo como Artefato JSON
|
|
||||||
|
|
||||||
## Visão Geral
|
|
||||||
|
|
||||||
Esta implementação adiciona a capacidade de extrair e salvar a equação do modelo de regressão linear como um artefato JSON, seguindo a arquitetura existente do projeto.
|
|
||||||
|
|
||||||
## Mudanças Implementadas
|
|
||||||
|
|
||||||
### 1. TrainModelResult
|
|
||||||
- **Arquivo**: `model_manager/utils/models/train_model_result.py`
|
|
||||||
- **Mudanças**:
|
|
||||||
- Adicionado campo `equation: dict | None = None` para armazenar os metadados da equação
|
|
||||||
- Adicionado campo `equation_path: str | None = None` para armazenar o caminho do arquivo JSON
|
|
||||||
|
|
||||||
### 2. TrainingRepository
|
|
||||||
- **Arquivo**: `model_manager/utils/repository/training_repository.py`
|
|
||||||
- **Mudanças**:
|
|
||||||
- Adicionado método `_extract_model_equation()` para extrair coeficientes e intercept do modelo
|
|
||||||
- Integrado a extração da equação no método `after_train_calculation()`
|
|
||||||
|
|
||||||
### 3. ModelRepository
|
|
||||||
- **Arquivo**: `model_manager/utils/repository/model_repository.py`
|
|
||||||
- **Mudanças**:
|
|
||||||
- Adicionado import do módulo `json`
|
|
||||||
- Modificado `_generate_report()` para salvar a equação como arquivo JSON
|
|
||||||
- Modificado `_save_run()` para fazer log do artefato da equação no MLflow
|
|
||||||
|
|
||||||
## Estrutura do JSON da Equação
|
|
||||||
|
|
||||||
O arquivo `model_equation.json` terá a seguinte estrutura:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"target_variable": "target_column_name",
|
|
||||||
"coefficients": {
|
|
||||||
"feature1": 0.123456,
|
|
||||||
"feature2": -0.789012,
|
|
||||||
"feature3": 0.345678
|
|
||||||
},
|
|
||||||
"intercept": 1.234567,
|
|
||||||
"equation_string": "target_column_name = 1.234567 + 0.123456 * feature1 + -0.789012 * feature2 + 0.345678 * feature3",
|
|
||||||
"latex_equation": "target_column_name = 1.234567 + 0.123456 \\cdot feature1 + -0.789012 \\cdot feature2 + 0.345678 \\cdot feature3",
|
|
||||||
"model_type": "Linear Regression"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Fluxo de Execução
|
|
||||||
|
|
||||||
1. **Treinamento**: O modelo é treinado no `TrainingRepository.train()`
|
|
||||||
2. **Pós-treinamento**: O método `after_train_calculation()` é chamado, que:
|
|
||||||
- Calcula as métricas (MSE, MAE, R²)
|
|
||||||
- Extrai a equação usando `_extract_model_equation()`
|
|
||||||
3. **Salvamento**: O `ModelRepository.save_model()` é chamado, que:
|
|
||||||
- Gera os artefatos (relatórios, dados CSV)
|
|
||||||
- Salva a equação como `model_equation.json`
|
|
||||||
- Faz log de todos os artefatos no MLflow
|
|
||||||
|
|
||||||
## Benefícios
|
|
||||||
|
|
||||||
- **Rastreabilidade**: A equação fica disponível como artefato versionado no MLflow
|
|
||||||
- **Transparência**: Fácil acesso aos coeficientes e estrutura do modelo
|
|
||||||
- **Compatibilidade**: Formato JSON facilita integração com outras ferramentas
|
|
||||||
- **Flexibilidade**: Inclui tanto formato legível quanto LaTeX para diferentes usos
|
|
||||||
|
|
||||||
## Compatibilidade
|
|
||||||
|
|
||||||
Esta implementação é totalmente compatível com:
|
|
||||||
- A arquitetura existente do projeto
|
|
||||||
- O fluxo de treinamento atual
|
|
||||||
- O sistema de logging do MLflow
|
|
||||||
- Os testes existentes (não quebra funcionalidades)
|
|
||||||
|
|
||||||
## Exemplo de Uso
|
|
||||||
|
|
||||||
Após o treinamento, a equação estará disponível em:
|
|
||||||
- **Memória**: `train_result.equation` (dicionário Python)
|
|
||||||
- **Arquivo**: `train_result.equation_path` (caminho para o JSON)
|
|
||||||
- **MLflow**: Como artefato `model_equation.json` no run do experimento
|
|
||||||
@@ -802,3 +802,48 @@ def test_generate_artifacts_header_not_found(
|
|||||||
|
|
||||||
with pytest.raises(FileNotFoundError, match='Header file does not exist'):
|
with pytest.raises(FileNotFoundError, match='Header file does not exist'):
|
||||||
repo._generate_artifacts(mock_train_result)
|
repo._generate_artifacts(mock_train_result)
|
||||||
|
|
||||||
|
|
||||||
|
@patch('model_manager.utils.repository.model_repository.ModelServing')
|
||||||
|
@patch('model_manager.utils.repository.model_repository.path.exists')
|
||||||
|
@patch('model_manager.utils.repository.model_repository.path.join')
|
||||||
|
def test_generate_artifacts_success(
|
||||||
|
mock_join, mock_exists, mock_model_serving_class, mock_logger, mock_train_result
|
||||||
|
):
|
||||||
|
"""Test _generate_artifacts success case covering lines 147-148."""
|
||||||
|
from model_manager.utils.repository.model_repository import ModelRepository
|
||||||
|
|
||||||
|
repo = ModelRepository(
|
||||||
|
url='http://mlflow.test', username='user', password='pass', logger=mock_logger
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mock path.join to return predictable paths
|
||||||
|
def join_side_effect(*args):
|
||||||
|
return '/'.join(args)
|
||||||
|
|
||||||
|
mock_join.side_effect = join_side_effect
|
||||||
|
mock_exists.return_value = True # Both reports dir and header.html exist
|
||||||
|
|
||||||
|
# Mock the internal methods to avoid actual file operations
|
||||||
|
with (
|
||||||
|
patch.object(repo, '_setup_run_directory') as mock_setup,
|
||||||
|
patch.object(repo, '_generate_report') as mock_generate_report,
|
||||||
|
patch.object(repo, '_init_artifacts_data') as mock_init_data,
|
||||||
|
patch.object(repo, '_get_reports_directory') as mock_get_reports_dir,
|
||||||
|
patch.object(repo, '_create_run_directory') as mock_create_run_dir,
|
||||||
|
):
|
||||||
|
# Setup mocks
|
||||||
|
mock_init_data.return_value = (pd.DataFrame(), pd.DataFrame())
|
||||||
|
mock_get_reports_dir.return_value = '/reports'
|
||||||
|
mock_create_run_dir.return_value = '/reports/run_1'
|
||||||
|
mock_generate_report.return_value = mock_train_result
|
||||||
|
|
||||||
|
# Call the method
|
||||||
|
result = repo._generate_artifacts(mock_train_result)
|
||||||
|
|
||||||
|
# Verify the methods on lines 147-148 were called
|
||||||
|
mock_setup.assert_called_once_with('/reports/run_1', '/reports/header.html')
|
||||||
|
mock_generate_report.assert_called_once()
|
||||||
|
|
||||||
|
# Verify result
|
||||||
|
assert result == mock_train_result
|
||||||
|
|||||||
Reference in New Issue
Block a user