mostlyai-engine 1.4.2__tar.gz → 1.4.4__tar.gz

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.
Files changed (51) hide show
  1. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/PKG-INFO +1 -1
  2. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/__init__.py +4 -5
  3. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_common.py +1 -3
  4. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/language/categorical.py +1 -1
  5. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/language/text.py +1 -1
  6. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/categorical.py +1 -1
  7. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/common.py +4 -4
  8. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/encoding.py +4 -4
  9. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/engine/hf_engine.py +2 -52
  10. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/generation.py +18 -8
  11. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/lstm.py +2 -2
  12. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/tokenizer_utils.py +3 -4
  13. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/training.py +29 -22
  14. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/argn.py +2 -3
  15. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/common.py +2 -1
  16. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/encoding.py +5 -5
  17. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/fairness.py +5 -6
  18. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/generation.py +24 -26
  19. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/training.py +24 -26
  20. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_workspace.py +2 -2
  21. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/analysis.py +15 -16
  22. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/domain.py +1 -1
  23. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/generation.py +4 -3
  24. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/splitting.py +6 -8
  25. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/training.py +2 -2
  26. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/pyproject.toml +5 -1
  27. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/.gitignore +0 -0
  28. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/LICENSE +0 -0
  29. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/README.md +0 -0
  30. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_dtypes.py +0 -0
  31. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/__init__.py +0 -0
  32. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/language/__init__.py +0 -0
  33. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/language/datetime.py +0 -0
  34. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/language/numeric.py +0 -0
  35. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/__init__.py +0 -0
  36. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/character.py +0 -0
  37. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/datetime.py +0 -0
  38. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/itt.py +0 -0
  39. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/lat_long.py +0 -0
  40. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_encoding_types/tabular/numeric.py +0 -0
  41. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/__init__.py +0 -0
  42. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/engine/__init__.py +0 -0
  43. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/engine/base.py +0 -0
  44. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/engine/vllm_engine.py +0 -0
  45. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_language/xgrammar_utils.py +0 -0
  46. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_memory.py +2 -2
  47. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_tabular/__init__.py +0 -0
  48. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/_training_utils.py +1 -1
  49. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/encoding.py +1 -1
  50. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/logging.py +1 -1
  51. {mostlyai_engine-1.4.2 → mostlyai_engine-1.4.4}/mostlyai/engine/random_state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mostlyai-engine
3
- Version: 1.4.2
3
+ Version: 1.4.4
4
4
  Summary: Synthetic Data Engine
5
5
  Project-URL: homepage, https://github.com/mostly-ai/mostlyai-engine
6
6
  Project-URL: repository, https://github.com/mostly-ai/mostlyai-engine
@@ -13,17 +13,16 @@
13
13
  # limitations under the License.
14
14
  import warnings
15
15
 
16
+ from mostlyai.engine.analysis import analyze
17
+ from mostlyai.engine.encoding import encode
18
+ from mostlyai.engine.generation import generate
16
19
  from mostlyai.engine.logging import init_logging
17
20
  from mostlyai.engine.random_state import set_random_state
18
21
  from mostlyai.engine.splitting import split
19
- from mostlyai.engine.analysis import analyze
20
22
  from mostlyai.engine.training import train
21
- from mostlyai.engine.encoding import encode
22
- from mostlyai.engine.generation import generate
23
-
24
23
 
25
24
  __all__ = ["split", "analyze", "encode", "train", "generate", "init_logging", "set_random_state"]
26
- __version__ = "1.4.2"
25
+ __version__ = "1.4.4"
27
26
 
28
27
  # suppress specific warning related to os.fork() in multi-threaded processes
29
28
  warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*multi-threaded.*fork.*")
@@ -18,6 +18,7 @@ import json
18
18
  import logging
19
19
  import platform
20
20
  import time
21
+ from collections.abc import Callable, Iterable
21
22
  from functools import wraps
22
23
  from pathlib import Path
23
24
  from typing import (
@@ -26,17 +27,14 @@ from typing import (
26
27
  NamedTuple,
27
28
  Protocol,
28
29
  )
29
- from collections.abc import Callable, Iterable
30
30
 
31
31
  import numpy as np
32
32
  import pandas as pd
33
33
  from pydantic import BaseModel
34
34
 
35
-
36
35
  from mostlyai.engine._dtypes import is_boolean_dtype, is_float_dtype, is_integer_dtype
37
36
  from mostlyai.engine.domain import ModelEncodingType
38
37
 
39
-
40
38
  _LOG = logging.getLogger(__name__)
41
39
 
42
40
  _LOG.info(f"running on Python ({platform.python_version()})")
@@ -18,7 +18,7 @@ Categorical encoding for language models.
18
18
 
19
19
  import pandas as pd
20
20
 
21
- from mostlyai.engine._common import safe_convert_string, STRING
21
+ from mostlyai.engine._common import STRING, safe_convert_string
22
22
  from mostlyai.engine._encoding_types.tabular.categorical import analyze_categorical, analyze_reduce_categorical
23
23
 
24
24
  CATEGORICAL_UNKNOWN_TOKEN = "_RARE_"
@@ -14,7 +14,7 @@
14
14
 
15
15
  import pandas as pd
16
16
 
17
- from mostlyai.engine._common import safe_convert_string, STRING
17
+ from mostlyai.engine._common import STRING, safe_convert_string
18
18
 
19
19
 
20
20
  def analyze_text(values: pd.Series, root_keys: pd.Series, _: pd.Series | None = None) -> dict:
@@ -18,7 +18,7 @@ Categorical encoding maps each categorical value to its own integer code.
18
18
 
19
19
  import pandas as pd
20
20
 
21
- from mostlyai.engine._common import get_stochastic_rare_threshold, safe_convert_string, dp_non_rare
21
+ from mostlyai.engine._common import dp_non_rare, get_stochastic_rare_threshold, safe_convert_string
22
22
 
23
23
  CATEGORICAL_UNKNOWN_TOKEN = "_RARE_"
24
24
  CATEGORICAL_NULL_TOKEN = "<<NULL>>"
@@ -14,13 +14,13 @@
14
14
 
15
15
  import importlib
16
16
  import logging
17
-
18
- from peft import PeftConfig, prepare_model_for_kbit_training
19
- from transformers import AutoConfig, AutoModelForCausalLM, BitsAndBytesConfig, PreTrainedModel, PretrainedConfig
20
- from mostlyai.engine._language.lstm import LSTMFromScratchConfig
21
17
  from pathlib import Path
22
18
 
23
19
  import torch
20
+ from peft import PeftConfig, prepare_model_for_kbit_training
21
+ from transformers import AutoConfig, AutoModelForCausalLM, BitsAndBytesConfig, PretrainedConfig, PreTrainedModel
22
+
23
+ from mostlyai.engine._language.lstm import LSTMFromScratchConfig
24
24
 
25
25
  _LOG = logging.getLogger(__name__)
26
26
 
@@ -23,15 +23,15 @@ from pandas.core.dtypes.common import is_datetime64_any_dtype
23
23
  from tokenizers.pre_tokenizers import ByteLevel
24
24
 
25
25
  from mostlyai.engine._common import (
26
- is_sequential,
26
+ TABLE_COLUMN_INFIX,
27
27
  ProgressCallback,
28
28
  ProgressCallbackWrapper,
29
- TABLE_COLUMN_INFIX,
29
+ is_sequential,
30
30
  )
31
- from mostlyai.engine._workspace import ensure_workspace_dir, Workspace, reset_dir
32
31
  from mostlyai.engine._encoding_types.language.categorical import encode_language_categorical
33
- from mostlyai.engine._encoding_types.language.numeric import encode_language_numeric
34
32
  from mostlyai.engine._encoding_types.language.datetime import encode_language_datetime
33
+ from mostlyai.engine._encoding_types.language.numeric import encode_language_numeric
34
+ from mostlyai.engine._workspace import Workspace, ensure_workspace_dir, reset_dir
35
35
 
36
36
  _LOG = logging.getLogger(__name__)
37
37
 
@@ -20,11 +20,10 @@ from os import PathLike
20
20
  from pathlib import Path
21
21
 
22
22
  import torch
23
- import transformers
24
- import xgrammar as xgr
25
23
  from peft import PeftModel
26
24
  from pydantic import BaseModel
27
25
  from transformers import AutoTokenizer
26
+ from xgrammar.contrib.hf import LogitsProcessor
28
27
 
29
28
  from mostlyai.engine._language.common import load_base_model_and_config
30
29
  from mostlyai.engine._language.engine.base import EngineMetrics, LanguageEngine
@@ -32,55 +31,6 @@ from mostlyai.engine._language.tokenizer_utils import tokenize_fn
32
31
  from mostlyai.engine._language.xgrammar_utils import create_compiled_grammars
33
32
 
34
33
 
35
- class XGrammarLogitsProcessor(transformers.LogitsProcessor):
36
- """
37
- Inspired by [LogitsProcessor](https://github.com/mlc-ai/xgrammar/blob/414473e7c029d0d9e2dfbeacb48afa946d0e3419/python/xgrammar/contrib/hf.py#L14).
38
- HuggingFace's XGrammarLogitsProcessor cannot be reused. Logits processors must be initialized for each call to generate().
39
- """
40
-
41
- def __init__(self, compiled_grammars: list[xgr.CompiledGrammar]):
42
- self.compiled_grammars = compiled_grammars
43
- self.vocab_size = self.compiled_grammars[0].tokenizer_info.vocab_size
44
- self.batch_size = len(compiled_grammars)
45
-
46
- self.matchers: list[xgr.GrammarMatcher] | None = None
47
- self.token_bitmask: torch.Tensor | None = None
48
- self.prefilled = False
49
-
50
- def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
51
- # lazily initialize GrammarMatchers and bitmask
52
- if self.matchers is None:
53
- self.matchers = [xgr.GrammarMatcher(self.compiled_grammars[i]) for i in range(self.batch_size)]
54
- self.token_bitmask = xgr.allocate_token_bitmask(self.batch_size, self.vocab_size)
55
-
56
- if input_ids.shape[0] != self.batch_size:
57
- raise RuntimeError(
58
- "Expect input_ids.shape[0] to be XGrammarLogitsProcessor.batch_size. "
59
- + f"Got {input_ids.shape[0]} for the former, and {self.batch_size} for the latter."
60
- )
61
-
62
- if not self.prefilled:
63
- # have not sampled a token yet
64
- self.prefilled = True
65
- else:
66
- for i in range(self.batch_size):
67
- if not self.matchers[i].is_terminated():
68
- sampled_token = input_ids[i][-1]
69
- assert self.matchers[i].accept_token(sampled_token)
70
-
71
- for i in range(self.batch_size):
72
- if not self.matchers[i].is_terminated():
73
- self.matchers[i].fill_next_token_bitmask(self.token_bitmask, i)
74
-
75
- device_type = scores.device.type
76
- if device_type != "cuda":
77
- scores = scores.to("cpu")
78
- xgr.apply_token_bitmask_inplace(scores, self.token_bitmask.to(scores.device))
79
- if device_type != "cuda":
80
- scores = scores.to(device_type)
81
- return scores
82
-
83
-
84
34
  class HuggingFaceEngine(LanguageEngine):
85
35
  def __init__(
86
36
  self, model_path: PathLike | str, device: torch.device, max_new_tokens: int, tokenizer_max_length: int
@@ -132,7 +82,7 @@ class HuggingFaceEngine(LanguageEngine):
132
82
  vocab_size=self._model_config.vocab_size,
133
83
  is_peft_adapter=self.is_peft_adapter,
134
84
  )
135
- self._logits_processors = [XGrammarLogitsProcessor(list(compiled_grammars))]
85
+ self._logits_processors = [LogitsProcessor(list(compiled_grammars))]
136
86
 
137
87
  def generate(
138
88
  self, text: list[str], sampling_temperature: float, sampling_top_p: float
@@ -15,24 +15,23 @@
15
15
  import contextlib
16
16
  import importlib
17
17
  import json
18
+ import logging
18
19
  import os
19
20
  import platform
20
- from typing import Any
21
-
22
- import json_repair
23
- import logging
24
21
  import time
25
22
  from pathlib import Path
23
+ from typing import Any
26
24
 
25
+ import json_repair
27
26
  import pandas as pd
28
27
  import torch
29
28
  from transformers import PreTrainedTokenizerBase
30
29
 
31
30
  from mostlyai.engine._common import (
32
- persist_data_part,
33
31
  FixedSizeSampleBuffer,
34
32
  ProgressCallback,
35
33
  ProgressCallbackWrapper,
34
+ persist_data_part,
36
35
  )
37
36
  from mostlyai.engine._encoding_types.language.categorical import decode_language_categorical
38
37
  from mostlyai.engine._encoding_types.language.datetime import decode_language_datetime
@@ -40,9 +39,8 @@ from mostlyai.engine._encoding_types.language.numeric import decode_language_num
40
39
  from mostlyai.engine._encoding_types.language.text import decode_text
41
40
  from mostlyai.engine._language.common import MAX_LENGTH
42
41
  from mostlyai.engine._language.encoding import encode_df
43
- from mostlyai.engine._language.xgrammar_utils import create_schemas
44
- from mostlyai.engine._workspace import ensure_workspace_dir, Workspace, reset_dir
45
- from mostlyai.engine._language.xgrammar_utils import ensure_seed_can_be_tokenized
42
+ from mostlyai.engine._language.xgrammar_utils import create_schemas, ensure_seed_can_be_tokenized
43
+ from mostlyai.engine._workspace import Workspace, ensure_workspace_dir, reset_dir
46
44
  from mostlyai.engine.domain import ModelEncodingType, RareCategoryReplacementMethod
47
45
 
48
46
  INVALID_VALUE = "_INVALID_" # when JSON parsing fails, the values of target columns will be set to this
@@ -181,6 +179,9 @@ def generate(
181
179
  tgt_text_columns = list(tgt_stats["columns"].keys())
182
180
  tgt_context_key = tgt_stats["keys"].get("context_key")
183
181
  has_context = workspace.ctx_stats.path.exists()
182
+ model_configs = workspace.model_configs.read()
183
+ enable_flexible_generation = model_configs.get("enable_flexible_generation", True)
184
+ _LOG.info(f"{enable_flexible_generation=}")
184
185
 
185
186
  # resolve potential conflict between sample_seed and sample_size
186
187
  if seed_data is not None:
@@ -228,6 +229,15 @@ def generate(
228
229
  seed_data = seed_data[[c for c in tgt_text_columns if c in seed_data.columns]]
229
230
  _LOG.info(f"{seed_data.shape=}")
230
231
 
232
+ if not enable_flexible_generation:
233
+ # validate sample_seed maintains the same column order as the one from training
234
+ seed_columns = seed_data.columns.tolist()
235
+ if seed_columns != tgt_text_columns[: len(seed_columns)]:
236
+ raise ValueError(
237
+ "The order of columns in the seed data does not match the order of columns from training. "
238
+ "A change in column order is only permitted for models that were trained with `enable_flexible_generation=True`."
239
+ )
240
+
231
241
  # sanity check: at this point sample seed and context data should have the same number of rows
232
242
  assert len(seed_data) == len(ctx_data)
233
243
 
@@ -15,9 +15,9 @@
15
15
  import logging
16
16
 
17
17
  import torch
18
- from transformers import PreTrainedModel, PretrainedConfig, AutoConfig, AutoModelForCausalLM, AutoModel, GenerationMixin
19
- from transformers.modeling_outputs import CausalLMOutput
20
18
  import torch.nn as nn
19
+ from transformers import AutoConfig, AutoModel, AutoModelForCausalLM, GenerationMixin, PretrainedConfig, PreTrainedModel
20
+ from transformers.modeling_outputs import CausalLMOutput
21
21
 
22
22
  _LOG = logging.getLogger(__name__)
23
23
 
@@ -12,16 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from collections.abc import Iterator, Mapping
15
16
  from dataclasses import dataclass
16
17
  from typing import Any
17
- from collections.abc import Mapping, Iterator
18
18
 
19
- from transformers import DataCollatorForLanguageModeling, BatchEncoding, PreTrainedTokenizerFast, LlamaTokenizerFast
20
- from transformers.data.data_collator import pad_without_fast_tokenizer_warning, _torch_collate_batch
19
+ from transformers import BatchEncoding, DataCollatorForLanguageModeling, LlamaTokenizerFast, PreTrainedTokenizerFast
20
+ from transformers.data.data_collator import _torch_collate_batch, pad_without_fast_tokenizer_warning
21
21
 
22
22
  from mostlyai.engine.domain import ModelEncodingType
23
23
 
24
-
25
24
  #################
26
25
  ### TOKENIZER ###
27
26
  #################
@@ -12,59 +12,58 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import gc
15
16
  import json
16
17
  import logging
17
18
  import math
19
+ import os
18
20
  import time
19
- import gc
21
+ import warnings
22
+ from collections.abc import Callable
20
23
  from contextlib import nullcontext
21
24
  from functools import partial
25
+ from importlib.metadata import version
22
26
  from pathlib import Path
23
- from collections.abc import Callable
24
- import warnings
25
27
 
26
- from importlib.metadata import version
27
- import pandas as pd
28
28
  import numpy as np
29
+ import pandas as pd
29
30
  import torch
31
+ from datasets import Dataset, DatasetDict, disable_progress_bar, load_dataset
32
+ from opacus import GradSampleModule, PrivacyEngine
33
+ from opacus.accountants import GaussianAccountant, PRVAccountant, RDPAccountant
30
34
  from opacus.grad_sample import register_grad_sampler
35
+ from opacus.utils.batch_memory_manager import wrap_data_loader
36
+ from peft import LoraConfig, PeftModel
31
37
  from torch import nn
32
38
  from torch.nn import CrossEntropyLoss
33
39
  from torch.optim.lr_scheduler import LRScheduler
34
-
35
- from opacus import PrivacyEngine, GradSampleModule
36
- from opacus.accountants import PRVAccountant, RDPAccountant, GaussianAccountant
37
- from opacus.utils.batch_memory_manager import wrap_data_loader
38
-
39
40
  from torch.utils.data import DataLoader
41
+ from transformers import (
42
+ AutoTokenizer,
43
+ PreTrainedModel,
44
+ )
40
45
 
41
- from mostlyai.engine._common import ProgressCallback, ProgressCallbackWrapper, TABLE_COLUMN_INFIX
46
+ from mostlyai.engine._common import TABLE_COLUMN_INFIX, ProgressCallback, ProgressCallbackWrapper
42
47
  from mostlyai.engine._language.common import (
48
+ MAX_LENGTH,
43
49
  is_bf16_supported,
44
50
  load_base_model_and_config,
45
- MAX_LENGTH,
46
51
  )
47
52
  from mostlyai.engine._language.encoding import row_to_json
53
+ from mostlyai.engine._language.lstm import LSTMFromScratchConfig, LSTMFromScratchLMHeadModel
48
54
  from mostlyai.engine._language.tokenizer_utils import (
49
- train_tokenizer,
50
55
  MostlyDataCollatorForLanguageModeling,
51
56
  tokenize_fn,
57
+ train_tokenizer,
52
58
  )
53
59
  from mostlyai.engine._training_utils import (
54
- check_early_training_exit,
55
60
  EarlyStopper,
56
61
  ModelCheckpoint,
57
62
  ProgressMessage,
63
+ check_early_training_exit,
58
64
  )
59
- from mostlyai.engine.domain import ModelStateStrategy, DifferentialPrivacyConfig
60
65
  from mostlyai.engine._workspace import Workspace, ensure_workspace_dir
61
- from datasets import load_dataset, DatasetDict, Dataset, disable_progress_bar
62
- from transformers import (
63
- AutoTokenizer,
64
- PreTrainedModel,
65
- )
66
- from mostlyai.engine._language.lstm import LSTMFromScratchLMHeadModel, LSTMFromScratchConfig
67
- from peft import LoraConfig, PeftModel
66
+ from mostlyai.engine.domain import DifferentialPrivacyConfig, ModelStateStrategy
68
67
 
69
68
  _LOG = logging.getLogger(__name__)
70
69
 
@@ -433,6 +432,10 @@ def train(
433
432
  model_config = LSTMFromScratchConfig(vocab_size=len(tokenizer), with_dp=with_dp)
434
433
  model = LSTMFromScratchLMHeadModel(model_config).to(device)
435
434
  else:
435
+ # use MOSTLY_HUGGING_FACE_TOKEN if available
436
+ if os.getenv("MOSTLY_HUGGING_FACE_TOKEN"):
437
+ os.environ["HF_TOKEN"] = os.environ["MOSTLY_HUGGING_FACE_TOKEN"]
438
+
436
439
  model, model_config = load_base_model_and_config(
437
440
  model_id_or_path,
438
441
  device=device,
@@ -471,6 +474,10 @@ def train(
471
474
  )
472
475
  model.add_adapter(peft_config)
473
476
 
477
+ # persist model configs
478
+ model_configs = {"enable_flexible_generation": enable_flexible_generation}
479
+ workspace.model_configs.write(model_configs)
480
+
474
481
  _LOG.info(f"model loading time: {time.time() - t0:.2f}s")
475
482
  model.train()
476
483
  no_of_model_params = model.num_parameters()
@@ -23,16 +23,15 @@ This module provides two models for tabular data:
23
23
  Each model can learn to generate data given some context data, which can either consist of scalar or sequential data.
24
24
  """
25
25
 
26
+ import logging
26
27
  from enum import Enum
27
28
  from functools import partial
28
- import logging
29
29
  from typing import Any, Literal
30
30
 
31
31
  import numpy as np
32
32
  import torch
33
- from torch import nn
34
-
35
33
  from opacus.layers import DPLSTM
34
+ from torch import nn
36
35
 
37
36
  from mostlyai.engine._common import (
38
37
  CTXFLT,
@@ -14,9 +14,10 @@
14
14
 
15
15
  import logging
16
16
  import time
17
- import torch
18
17
  from pathlib import Path
19
18
 
19
+ import torch
20
+
20
21
  _LOG = logging.getLogger(__name__)
21
22
 
22
23
 
@@ -18,23 +18,23 @@ from pathlib import Path
18
18
 
19
19
  import numpy as np
20
20
  import pandas as pd
21
- from joblib import Parallel, delayed, parallel_config, cpu_count
21
+ from joblib import Parallel, cpu_count, delayed, parallel_config
22
22
 
23
23
  from mostlyai.engine._common import (
24
24
  ARGN_COLUMN,
25
25
  ARGN_PROCESSOR,
26
26
  ARGN_TABLE,
27
+ SDEC_SUB_COLUMN_PREFIX,
27
28
  SIDX_SUB_COLUMN_PREFIX,
28
29
  SLEN_SUB_COLUMN_PREFIX,
29
30
  TGT,
31
+ ProgressCallback,
32
+ ProgressCallbackWrapper,
30
33
  encode_slen_sidx_sdec,
31
34
  get_argn_name,
32
35
  get_sequence_length_stats,
33
36
  is_a_list,
34
37
  is_sequential,
35
- SDEC_SUB_COLUMN_PREFIX,
36
- ProgressCallback,
37
- ProgressCallbackWrapper,
38
38
  )
39
39
  from mostlyai.engine._encoding_types.tabular.categorical import encode_categorical
40
40
  from mostlyai.engine._encoding_types.tabular.character import encode_character
@@ -42,8 +42,8 @@ from mostlyai.engine._encoding_types.tabular.datetime import encode_datetime
42
42
  from mostlyai.engine._encoding_types.tabular.itt import encode_itt
43
43
  from mostlyai.engine._encoding_types.tabular.lat_long import encode_latlong
44
44
  from mostlyai.engine._encoding_types.tabular.numeric import encode_numeric
45
- from mostlyai.engine.domain import ModelEncodingType
46
45
  from mostlyai.engine._workspace import Workspace, ensure_workspace_dir, reset_dir
46
+ from mostlyai.engine.domain import ModelEncodingType
47
47
  from mostlyai.engine.random_state import set_random_state
48
48
 
49
49
  _LOG = logging.getLogger(__name__)
@@ -13,24 +13,23 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import logging
16
+ from collections.abc import Callable
16
17
  from functools import partial
18
+ from itertools import product
17
19
  from typing import Any, TypedDict
18
- from collections.abc import Callable
19
20
 
20
- import pandas as pd
21
21
  import numpy as np
22
-
23
- from itertools import product
22
+ import pandas as pd
24
23
  import torch
25
24
 
26
25
  from mostlyai.engine._common import (
27
- get_argn_name,
28
26
  ARGN_COLUMN,
29
27
  ARGN_PROCESSOR,
30
28
  ARGN_TABLE,
29
+ get_argn_name,
31
30
  )
32
31
  from mostlyai.engine._encoding_types.tabular.categorical import CATEGORICAL_SUB_COL_SUFFIX, CATEGORICAL_UNKNOWN_TOKEN
33
- from mostlyai.engine.domain import ModelEncodingType, FairnessConfig
32
+ from mostlyai.engine.domain import FairnessConfig, ModelEncodingType
34
33
 
35
34
  _LOG = logging.getLogger(__name__)
36
35
 
@@ -24,33 +24,19 @@ import numpy as np
24
24
  import pandas as pd
25
25
  import torch
26
26
 
27
- from mostlyai.engine._memory import get_available_ram_for_heuristics, get_available_vram_for_heuristics
28
- from mostlyai.engine.domain import (
29
- ModelEncodingType,
30
- RareCategoryReplacementMethod,
31
- RebalancingConfig,
32
- ImputationConfig,
33
- FairnessConfig,
34
- )
35
- from mostlyai.engine._tabular.common import load_model_weights
36
-
37
- from mostlyai.engine._tabular.fairness import get_fairness_transforms, FairnessTransforms
38
-
39
- from mostlyai.engine._tabular.argn import (
40
- FlatModel,
41
- ModelSize,
42
- SequentialModel,
43
- get_no_of_model_parameters,
44
- )
45
27
  from mostlyai.engine._common import (
46
28
  ARGN_COLUMN,
47
29
  ARGN_PROCESSOR,
48
30
  ARGN_TABLE,
49
31
  CTXFLT,
50
32
  CTXSEQ,
33
+ SDEC_SUB_COLUMN_PREFIX,
51
34
  SIDX_SUB_COLUMN_PREFIX,
52
35
  SLEN_SIDX_SDEC_COLUMN,
53
36
  SLEN_SUB_COLUMN_PREFIX,
37
+ FixedSizeSampleBuffer,
38
+ ProgressCallback,
39
+ ProgressCallbackWrapper,
54
40
  apply_encoding_type_dtypes,
55
41
  decode_slen_sidx_sdec,
56
42
  encode_slen_sidx_sdec,
@@ -60,16 +46,11 @@ from mostlyai.engine._common import (
60
46
  get_ctx_sequence_length,
61
47
  get_sequence_length_stats,
62
48
  get_sub_columns_from_cardinalities,
63
- is_sequential,
64
- trim_sequences,
65
49
  get_sub_columns_nested_from_cardinalities,
50
+ is_sequential,
66
51
  persist_data_part,
67
- FixedSizeSampleBuffer,
68
- SDEC_SUB_COLUMN_PREFIX,
69
- ProgressCallback,
70
- ProgressCallbackWrapper,
52
+ trim_sequences,
71
53
  )
72
- from mostlyai.engine._tabular.encoding import encode_df, pad_horizontally
73
54
  from mostlyai.engine._encoding_types.tabular.categorical import (
74
55
  CATEGORICAL_NULL_TOKEN,
75
56
  CATEGORICAL_SUB_COL_SUFFIX,
@@ -89,7 +70,24 @@ from mostlyai.engine._encoding_types.tabular.numeric import (
89
70
  NUMERIC_DISCRETE_UNKNOWN_TOKEN,
90
71
  decode_numeric,
91
72
  )
73
+ from mostlyai.engine._memory import get_available_ram_for_heuristics, get_available_vram_for_heuristics
74
+ from mostlyai.engine._tabular.argn import (
75
+ FlatModel,
76
+ ModelSize,
77
+ SequentialModel,
78
+ get_no_of_model_parameters,
79
+ )
80
+ from mostlyai.engine._tabular.common import load_model_weights
81
+ from mostlyai.engine._tabular.encoding import encode_df, pad_horizontally
82
+ from mostlyai.engine._tabular.fairness import FairnessTransforms, get_fairness_transforms
92
83
  from mostlyai.engine._workspace import Workspace, ensure_workspace_dir, reset_dir
84
+ from mostlyai.engine.domain import (
85
+ FairnessConfig,
86
+ ImputationConfig,
87
+ ModelEncodingType,
88
+ RareCategoryReplacementMethod,
89
+ RebalancingConfig,
90
+ )
93
91
 
94
92
  _LOG = logging.getLogger(__name__)
95
93
 
@@ -698,7 +696,7 @@ def generate(
698
696
  output_path = workspace.generated_data_path
699
697
  reset_dir(output_path)
700
698
 
701
- model_configs = workspace.model_tabular_configs.read()
699
+ model_configs = workspace.model_configs.read()
702
700
  tgt_stats = workspace.tgt_stats.read()
703
701
  is_sequential = tgt_stats["is_sequential"]
704
702
  _LOG.info(f"{is_sequential=}")
@@ -16,37 +16,31 @@ import logging
16
16
  import math
17
17
  import time
18
18
  import warnings
19
+ from collections.abc import Callable
20
+ from importlib.metadata import version
19
21
  from itertools import zip_longest
20
22
  from pathlib import Path
21
- from collections.abc import Callable
22
23
 
23
- from importlib.metadata import version
24
24
  import numpy as np
25
25
  import pandas as pd
26
26
  import torch
27
- from datasets import load_dataset, disable_progress_bar
28
- from torch.utils.data import DataLoader
29
- from torch.optim.lr_scheduler import LRScheduler
30
-
31
- from torch import nn
32
-
33
- from opacus import PrivacyEngine, GradSampleModule
34
- from opacus.accountants import PRVAccountant, RDPAccountant, GaussianAccountant
27
+ from datasets import disable_progress_bar, load_dataset
28
+ from opacus import GradSampleModule, PrivacyEngine
29
+ from opacus.accountants import GaussianAccountant, PRVAccountant, RDPAccountant
35
30
  from opacus.utils.batch_memory_manager import wrap_data_loader
31
+ from torch import nn
32
+ from torch.optim.lr_scheduler import LRScheduler
33
+ from torch.utils.data import DataLoader
36
34
 
37
- from mostlyai.engine._memory import get_available_ram_for_heuristics
38
- from mostlyai.engine.domain import ModelStateStrategy, DifferentialPrivacyConfig
39
- from mostlyai.engine._tabular.argn import (
40
- FlatModel,
41
- ModelSize,
42
- SequentialModel,
43
- get_model_units,
44
- get_no_of_model_parameters,
45
- )
46
35
  from mostlyai.engine._common import (
47
36
  CTXFLT,
48
37
  CTXSEQ,
38
+ SDEC_SUB_COLUMN_PREFIX,
39
+ SIDX_SUB_COLUMN_PREFIX,
40
+ SLEN_SUB_COLUMN_PREFIX,
49
41
  TGT,
42
+ ProgressCallback,
43
+ ProgressCallbackWrapper,
50
44
  get_cardinalities,
51
45
  get_columns_from_cardinalities,
52
46
  get_ctx_sequence_length,
@@ -54,20 +48,24 @@ from mostlyai.engine._common import (
54
48
  get_sequence_length_stats,
55
49
  get_sub_columns_from_cardinalities,
56
50
  get_sub_columns_nested_from_cardinalities,
57
- SIDX_SUB_COLUMN_PREFIX,
58
- SLEN_SUB_COLUMN_PREFIX,
59
- SDEC_SUB_COLUMN_PREFIX,
60
- ProgressCallback,
61
- ProgressCallbackWrapper,
51
+ )
52
+ from mostlyai.engine._memory import get_available_ram_for_heuristics
53
+ from mostlyai.engine._tabular.argn import (
54
+ FlatModel,
55
+ ModelSize,
56
+ SequentialModel,
57
+ get_model_units,
58
+ get_no_of_model_parameters,
62
59
  )
63
60
  from mostlyai.engine._tabular.common import load_model_weights
64
61
  from mostlyai.engine._training_utils import (
65
- check_early_training_exit,
66
62
  EarlyStopper,
67
63
  ModelCheckpoint,
68
64
  ProgressMessage,
65
+ check_early_training_exit,
69
66
  )
70
67
  from mostlyai.engine._workspace import Workspace, ensure_workspace_dir
68
+ from mostlyai.engine.domain import DifferentialPrivacyConfig, ModelStateStrategy
71
69
 
72
70
  _LOG = logging.getLogger(__name__)
73
71
 
@@ -504,7 +502,7 @@ def train(
504
502
  "model_units": model_units,
505
503
  "enable_flexible_generation": enable_flexible_generation,
506
504
  }
507
- workspace.model_tabular_configs.write(model_configs)
505
+ workspace.model_configs.write(model_configs)
508
506
 
509
507
  # heuristics for batch_size and for initial learn_rate
510
508
  mem_available_gb = get_available_ram_for_heuristics() / 1024**3
@@ -14,10 +14,10 @@
14
14
 
15
15
  import logging
16
16
  import os
17
+ from collections.abc import Callable
17
18
  from dataclasses import dataclass
18
19
  from pathlib import Path
19
20
  from typing import Any
20
- from collections.abc import Callable
21
21
 
22
22
  from mostlyai.engine._common import read_json, write_json
23
23
  from mostlyai.engine.domain import ModelType
@@ -161,7 +161,7 @@ class Workspace:
161
161
  self.model_dp_accountant_path: Path = self.model_path / "dp-accountant.pt"
162
162
  self.model_tabular_weights_path: Path = self.model_path / "model-weights.pt"
163
163
  self.model_progress_messages_path: Path = self.model_path / "progress-messages.csv"
164
- self.model_tabular_configs = make_json_path_desc(parts=model_data + ["model-configs.json"])
164
+ self.model_configs = make_json_path_desc(parts=model_data + ["model-configs.json"])
165
165
 
166
166
  # Generate-related
167
167
  generated_data = ["SyntheticData"]
@@ -18,13 +18,13 @@ Provides analysis functionality of the engine
18
18
 
19
19
  import logging
20
20
  import time
21
+ from collections.abc import Iterable
21
22
  from pathlib import Path
22
23
  from typing import Any, Literal
23
- from collections.abc import Iterable
24
24
 
25
25
  import numpy as np
26
26
  import pandas as pd
27
- from joblib import Parallel, delayed, parallel_config, cpu_count
27
+ from joblib import Parallel, cpu_count, delayed, parallel_config
28
28
 
29
29
  from mostlyai.engine._common import (
30
30
  ANALYZE_REDUCE_MIN_MAX_N,
@@ -33,22 +33,30 @@ from mostlyai.engine._common import (
33
33
  ARGN_TABLE,
34
34
  CTXFLT,
35
35
  CTXSEQ,
36
+ TABLE_COLUMN_INFIX,
36
37
  TGT,
38
+ ProgressCallback,
39
+ ProgressCallbackWrapper,
37
40
  dp_quantiles,
38
41
  get_stochastic_rare_threshold,
39
42
  is_a_list,
40
43
  is_sequential,
41
44
  read_json,
42
45
  write_json,
43
- TABLE_COLUMN_INFIX,
44
- ProgressCallback,
45
- ProgressCallbackWrapper,
46
+ )
47
+ from mostlyai.engine._encoding_types.language.categorical import (
48
+ analyze_language_categorical,
49
+ analyze_reduce_language_categorical,
46
50
  )
47
51
  from mostlyai.engine._encoding_types.language.datetime import (
48
- analyze_reduce_language_datetime,
49
52
  analyze_language_datetime,
53
+ analyze_reduce_language_datetime,
50
54
  )
51
55
  from mostlyai.engine._encoding_types.language.numeric import analyze_language_numeric, analyze_reduce_language_numeric
56
+ from mostlyai.engine._encoding_types.language.text import (
57
+ analyze_reduce_text,
58
+ analyze_text,
59
+ )
52
60
  from mostlyai.engine._encoding_types.tabular.categorical import (
53
61
  analyze_categorical,
54
62
  analyze_reduce_categorical,
@@ -70,22 +78,13 @@ from mostlyai.engine._encoding_types.tabular.numeric import (
70
78
  analyze_numeric,
71
79
  analyze_reduce_numeric,
72
80
  )
73
- from mostlyai.engine._encoding_types.language.text import (
74
- analyze_text,
75
- analyze_reduce_text,
76
- )
77
- from mostlyai.engine._encoding_types.language.categorical import (
78
- analyze_language_categorical,
79
- analyze_reduce_language_categorical,
80
- )
81
- from mostlyai.engine.domain import ModelEncodingType, DifferentialPrivacyConfig
82
-
83
81
  from mostlyai.engine._workspace import (
84
82
  PathDesc,
85
83
  Workspace,
86
84
  ensure_workspace_dir,
87
85
  reset_dir,
88
86
  )
87
+ from mostlyai.engine.domain import DifferentialPrivacyConfig, ModelEncodingType
89
88
  from mostlyai.engine.random_state import set_random_state
90
89
 
91
90
  _LOG = logging.getLogger(__name__)
@@ -14,7 +14,7 @@
14
14
 
15
15
  from enum import Enum
16
16
 
17
- from pydantic import BaseModel, Field, ConfigDict, field_validator
17
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
18
18
 
19
19
 
20
20
  class CustomBaseModel(BaseModel):
@@ -13,17 +13,18 @@
13
13
  # limitations under the License.
14
14
 
15
15
  from pathlib import Path
16
+
16
17
  import pandas as pd
17
18
 
18
19
  from mostlyai.engine._common import ProgressCallback
20
+ from mostlyai.engine._workspace import resolve_model_type
19
21
  from mostlyai.engine.domain import (
22
+ FairnessConfig,
23
+ ImputationConfig,
20
24
  ModelType,
21
25
  RareCategoryReplacementMethod,
22
26
  RebalancingConfig,
23
- ImputationConfig,
24
- FairnessConfig,
25
27
  )
26
- from mostlyai.engine._workspace import resolve_model_type
27
28
 
28
29
 
29
30
  def generate(
@@ -16,30 +16,28 @@
16
16
  Split original data for training and validation.
17
17
  """
18
18
 
19
+ import logging
19
20
  import time
20
21
  import warnings
21
22
  from pathlib import Path
22
23
 
23
- from mostlyai.engine._common import ProgressCallbackWrapper, ProgressCallback
24
+ import numpy as np
25
+ import pandas as pd
26
+
27
+ from mostlyai.engine._common import ProgressCallback, ProgressCallbackWrapper
24
28
  from mostlyai.engine._dtypes import (
25
29
  is_date_dtype,
26
30
  is_float_dtype,
27
31
  is_integer_dtype,
28
32
  is_timestamp_dtype,
29
33
  )
30
-
31
- import numpy as np
32
- import logging
33
-
34
- import pandas as pd
35
-
36
- from mostlyai.engine.domain import ModelType, ModelEncodingType
37
34
  from mostlyai.engine._workspace import (
38
35
  PathDesc,
39
36
  Workspace,
40
37
  ensure_workspace_dir,
41
38
  reset_dir,
42
39
  )
40
+ from mostlyai.engine.domain import ModelEncodingType, ModelType
43
41
 
44
42
  warnings.simplefilter(action="ignore", category=UserWarning)
45
43
 
@@ -13,14 +13,14 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import inspect
16
- from pathlib import Path
17
16
  from collections.abc import Callable
17
+ from pathlib import Path
18
18
 
19
19
  import torch
20
20
 
21
21
  from mostlyai.engine._common import ProgressCallback
22
- from mostlyai.engine.domain import ModelType, ModelStateStrategy, DifferentialPrivacyConfig
23
22
  from mostlyai.engine._workspace import resolve_model_type
23
+ from mostlyai.engine.domain import DifferentialPrivacyConfig, ModelStateStrategy, ModelType
24
24
 
25
25
 
26
26
  def train(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mostlyai-engine"
3
- version = "1.4.2"
3
+ version = "1.4.4"
4
4
  description = "Synthetic Data Engine"
5
5
  authors = [{ name = "MOSTLY AI", email = "dev@mostly.ai" }]
6
6
  requires-python = ">=3.10"
@@ -64,6 +64,7 @@ docs = [
64
64
  "mkdocs>=1.6",
65
65
  "mkdocstrings[crystal, python]>=0.29",
66
66
  "mkdocs-material>=9.0",
67
+ "mkdocs-llmstxt>=0.2",
67
68
  "griffe>=1.0",
68
69
  "pymdown-extensions>=10.0",
69
70
  "griffe-fieldz>=0.2",
@@ -94,3 +95,6 @@ build-backend = "hatchling.build"
94
95
  [tool.ruff]
95
96
  target-version = "py310"
96
97
  line-length = 120
98
+
99
+ [tool.ruff.lint]
100
+ extend-select = ["I"]
File without changes
@@ -12,11 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import logging
15
16
  import os
16
- import psutil
17
17
  import re
18
- import logging
19
18
 
19
+ import psutil
20
20
  import torch
21
21
 
22
22
  _LOG = logging.getLogger(__name__)
@@ -16,9 +16,9 @@ import abc
16
16
  import logging
17
17
  import time
18
18
 
19
- from opacus.accountants import IAccountant
20
19
  import pandas as pd
21
20
  import torch
21
+ from opacus.accountants import IAccountant
22
22
  from pydantic import BaseModel, Field, field_validator
23
23
 
24
24
  from mostlyai.engine._workspace import Workspace
@@ -15,8 +15,8 @@
15
15
  from pathlib import Path
16
16
 
17
17
  from mostlyai.engine._common import ProgressCallback
18
- from mostlyai.engine.domain import ModelType
19
18
  from mostlyai.engine._workspace import resolve_model_type
19
+ from mostlyai.engine.domain import ModelType
20
20
 
21
21
 
22
22
  def encode(
@@ -12,8 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import sys
16
15
  import logging
16
+ import sys
17
17
 
18
18
  _LOG = logging.getLogger(__name__.rsplit(".", 1)[0]) # get the logger with the root module name (mostlyai.engine)
19
19