mxlpy 0.16.0__py3-none-any.whl → 0.17.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mxlpy/npe.py DELETED
@@ -1,277 +0,0 @@
1
- """Neural Network Parameter Estimation (NPE) Module.
2
-
3
- This module provides classes and functions for training neural network models to estimate
4
- parameters in metabolic models. It includes functionality for both steady-state and
5
- time-series data.
6
-
7
- Functions:
8
- train_torch_surrogate: Train a PyTorch surrogate model
9
- train_torch_time_course_estimator: Train a PyTorch time course estimator
10
- """
11
-
12
- from __future__ import annotations
13
-
14
- __all__ = [
15
- "AbstractEstimator",
16
- "DefaultCache",
17
- "TorchSSEstimator",
18
- "TorchTimeCourseEstimator",
19
- "train_torch_ss_estimator",
20
- "train_torch_time_course_estimator",
21
- ]
22
-
23
- from abc import abstractmethod
24
- from dataclasses import dataclass
25
- from pathlib import Path
26
- from typing import TYPE_CHECKING, cast
27
-
28
- import numpy as np
29
- import pandas as pd
30
- import torch
31
- import tqdm
32
- from torch import nn
33
- from torch.optim.adam import Adam
34
-
35
- from mxlpy.nn._torch import LSTM, MLP, DefaultDevice
36
- from mxlpy.parallel import Cache
37
-
38
- if TYPE_CHECKING:
39
- from collections.abc import Callable
40
-
41
- from torch.optim.optimizer import ParamsT
42
-
43
- DefaultCache = Cache(Path(".cache"))
44
-
45
-
46
- @dataclass(kw_only=True)
47
- class AbstractEstimator:
48
- """Abstract class for parameter estimation using neural networks."""
49
-
50
- parameter_names: list[str]
51
-
52
- @abstractmethod
53
- def predict(self, features: pd.Series | pd.DataFrame) -> pd.DataFrame:
54
- """Predict the target values for the given features."""
55
-
56
-
57
- @dataclass(kw_only=True)
58
- class TorchSSEstimator(AbstractEstimator):
59
- """Estimator for steady state data using PyTorch models."""
60
-
61
- model: torch.nn.Module
62
-
63
- def predict(self, features: pd.Series | pd.DataFrame) -> pd.DataFrame:
64
- """Predict the target values for the given features."""
65
- with torch.no_grad():
66
- pred = self.model(torch.tensor(features.to_numpy(), dtype=torch.float32))
67
- return pd.DataFrame(pred, columns=self.parameter_names)
68
-
69
-
70
- @dataclass(kw_only=True)
71
- class TorchTimeCourseEstimator(AbstractEstimator):
72
- """Estimator for time course data using PyTorch models."""
73
-
74
- model: torch.nn.Module
75
-
76
- def predict(self, features: pd.Series | pd.DataFrame) -> pd.DataFrame:
77
- """Predict the target values for the given features."""
78
- idx = cast(pd.MultiIndex, features.index)
79
- features_ = torch.Tensor(
80
- np.swapaxes(
81
- features.to_numpy().reshape(
82
- (
83
- len(idx.levels[0]),
84
- len(idx.levels[1]),
85
- len(features.columns),
86
- )
87
- ),
88
- axis1=0,
89
- axis2=1,
90
- ),
91
- )
92
- with torch.no_grad():
93
- pred = self.model(features_)
94
- return pd.DataFrame(pred, columns=self.parameter_names)
95
-
96
-
97
- def _train_batched(
98
- approximator: nn.Module,
99
- features: torch.Tensor,
100
- targets: torch.Tensor,
101
- epochs: int,
102
- optimizer: Adam,
103
- batch_size: int,
104
- ) -> pd.Series:
105
- losses = {}
106
-
107
- for epoch in tqdm.trange(epochs):
108
- permutation = torch.randperm(features.size()[0])
109
- epoch_loss = 0
110
- for i in range(0, features.size()[0], batch_size):
111
- optimizer.zero_grad()
112
- indices = permutation[i : i + batch_size]
113
-
114
- loss = torch.mean(
115
- torch.abs(approximator(features[indices]) - targets[indices])
116
- )
117
- loss.backward()
118
- optimizer.step()
119
- epoch_loss += loss.detach().numpy()
120
-
121
- losses[epoch] = epoch_loss / (features.size()[0] / batch_size)
122
- return pd.Series(losses, dtype=float)
123
-
124
-
125
- def _train_full(
126
- approximator: nn.Module,
127
- features: torch.Tensor,
128
- targets: torch.Tensor,
129
- epochs: int,
130
- optimizer: Adam,
131
- ) -> pd.Series:
132
- losses = {}
133
- for i in tqdm.trange(epochs):
134
- optimizer.zero_grad()
135
- loss = torch.mean(torch.abs(approximator(features) - targets))
136
- loss.backward()
137
- optimizer.step()
138
- losses[i] = loss.detach().numpy()
139
- return pd.Series(losses, dtype=float)
140
-
141
-
142
- def train_torch_ss_estimator(
143
- features: pd.DataFrame,
144
- targets: pd.DataFrame,
145
- epochs: int,
146
- batch_size: int | None = None,
147
- approximator: nn.Module | None = None,
148
- optimimzer_cls: Callable[[ParamsT], Adam] = Adam,
149
- device: torch.device = DefaultDevice,
150
- ) -> tuple[TorchSSEstimator, pd.Series]:
151
- """Train a PyTorch steady state estimator.
152
-
153
- This function trains a neural network model to estimate steady state data
154
- using the provided features and targets. It supports both full-batch and
155
- mini-batch training.
156
-
157
- Examples:
158
- >>> train_torch_ss_estimator(features, targets, epochs=100)
159
-
160
- Args:
161
- features: DataFrame containing the input features for training
162
- targets: DataFrame containing the target values for training
163
- epochs: Number of training epochs
164
- batch_size: Size of mini-batches for training (None for full-batch)
165
- approximator: Predefined neural network model (None to use default MLP)
166
- optimimzer_cls: Optimizer class to use for training (default: Adam)
167
- device: Device to run the training on (default: DefaultDevice)
168
-
169
- Returns:
170
- tuple[TorchTimeSeriesEstimator, pd.Series]: Trained estimator and loss history
171
-
172
- """
173
- if approximator is None:
174
- n_hidden = max(2 * len(features.columns) * len(targets.columns), 10)
175
- n_outputs = len(targets.columns)
176
- approximator = MLP(
177
- n_inputs=len(features.columns),
178
- neurons_per_layer=[n_hidden, n_hidden, n_outputs],
179
- ).to(device)
180
-
181
- features_ = torch.Tensor(features.to_numpy(), device=device)
182
- targets_ = torch.Tensor(targets.to_numpy(), device=device)
183
-
184
- optimizer = optimimzer_cls(approximator.parameters())
185
- if batch_size is None:
186
- losses = _train_full(
187
- approximator=approximator,
188
- features=features_,
189
- targets=targets_,
190
- epochs=epochs,
191
- optimizer=optimizer,
192
- )
193
- else:
194
- losses = _train_batched(
195
- approximator=approximator,
196
- features=features_,
197
- targets=targets_,
198
- epochs=epochs,
199
- optimizer=optimizer,
200
- batch_size=batch_size,
201
- )
202
-
203
- return TorchSSEstimator(
204
- model=approximator,
205
- parameter_names=list(targets.columns),
206
- ), losses
207
-
208
-
209
- def train_torch_time_course_estimator(
210
- features: pd.DataFrame,
211
- targets: pd.DataFrame,
212
- epochs: int,
213
- batch_size: int | None = None,
214
- approximator: nn.Module | None = None,
215
- optimimzer_cls: Callable[[ParamsT], Adam] = Adam,
216
- device: torch.device = DefaultDevice,
217
- ) -> tuple[TorchTimeCourseEstimator, pd.Series]:
218
- """Train a PyTorch time course estimator.
219
-
220
- This function trains a neural network model to estimate time course data
221
- using the provided features and targets. It supports both full-batch and
222
- mini-batch training.
223
-
224
- Examples:
225
- >>> train_torch_time_course_estimator(features, targets, epochs=100)
226
-
227
- Args:
228
- features: DataFrame containing the input features for training
229
- targets: DataFrame containing the target values for training
230
- epochs: Number of training epochs
231
- batch_size: Size of mini-batches for training (None for full-batch)
232
- approximator: Predefined neural network model (None to use default LSTM)
233
- optimimzer_cls: Optimizer class to use for training (default: Adam)
234
- device: Device to run the training on (default: DefaultDevice)
235
-
236
- Returns:
237
- tuple[TorchTimeSeriesEstimator, pd.Series]: Trained estimator and loss history
238
-
239
- """
240
- if approximator is None:
241
- approximator = LSTM(
242
- n_inputs=len(features.columns),
243
- n_outputs=len(targets.columns),
244
- n_hidden=1,
245
- ).to(device)
246
-
247
- optimizer = optimimzer_cls(approximator.parameters())
248
- features_ = torch.Tensor(
249
- np.swapaxes(
250
- features.to_numpy().reshape((len(targets), -1, len(features.columns))),
251
- axis1=0,
252
- axis2=1,
253
- ),
254
- device=device,
255
- )
256
- targets_ = torch.Tensor(targets.to_numpy(), device=device)
257
- if batch_size is None:
258
- losses = _train_full(
259
- approximator=approximator,
260
- features=features_,
261
- targets=targets_,
262
- epochs=epochs,
263
- optimizer=optimizer,
264
- )
265
- else:
266
- losses = _train_batched(
267
- approximator=approximator,
268
- features=features_,
269
- targets=targets_,
270
- epochs=epochs,
271
- optimizer=optimizer,
272
- batch_size=batch_size,
273
- )
274
- return TorchTimeCourseEstimator(
275
- model=approximator,
276
- parameter_names=list(targets.columns),
277
- ), losses
File without changes