together 1.2.13__tar.gz → 1.3.0__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 (58) hide show
  1. {together-1.2.13 → together-1.3.0}/PKG-INFO +2 -2
  2. {together-1.2.13 → together-1.3.0}/README.md +1 -1
  3. {together-1.2.13 → together-1.3.0}/pyproject.toml +1 -1
  4. {together-1.2.13 → together-1.3.0}/src/together/cli/api/finetune.py +55 -9
  5. together-1.3.0/src/together/cli/api/utils.py +21 -0
  6. {together-1.2.13 → together-1.3.0}/src/together/legacy/finetune.py +2 -2
  7. {together-1.2.13 → together-1.3.0}/src/together/resources/finetune.py +99 -11
  8. {together-1.2.13 → together-1.3.0}/src/together/types/__init__.py +2 -0
  9. {together-1.2.13 → together-1.3.0}/src/together/types/finetune.py +18 -0
  10. {together-1.2.13 → together-1.3.0}/src/together/utils/__init__.py +2 -1
  11. {together-1.2.13 → together-1.3.0}/src/together/utils/_log.py +10 -0
  12. {together-1.2.13 → together-1.3.0}/LICENSE +0 -0
  13. {together-1.2.13 → together-1.3.0}/src/together/__init__.py +0 -0
  14. {together-1.2.13 → together-1.3.0}/src/together/abstract/__init__.py +0 -0
  15. {together-1.2.13 → together-1.3.0}/src/together/abstract/api_requestor.py +0 -0
  16. {together-1.2.13 → together-1.3.0}/src/together/cli/__init__.py +0 -0
  17. {together-1.2.13 → together-1.3.0}/src/together/cli/api/__init__.py +0 -0
  18. {together-1.2.13 → together-1.3.0}/src/together/cli/api/chat.py +0 -0
  19. {together-1.2.13 → together-1.3.0}/src/together/cli/api/completions.py +0 -0
  20. {together-1.2.13 → together-1.3.0}/src/together/cli/api/files.py +0 -0
  21. {together-1.2.13 → together-1.3.0}/src/together/cli/api/images.py +0 -0
  22. {together-1.2.13 → together-1.3.0}/src/together/cli/api/models.py +0 -0
  23. {together-1.2.13 → together-1.3.0}/src/together/cli/cli.py +0 -0
  24. {together-1.2.13 → together-1.3.0}/src/together/client.py +0 -0
  25. {together-1.2.13 → together-1.3.0}/src/together/constants.py +0 -0
  26. {together-1.2.13 → together-1.3.0}/src/together/error.py +0 -0
  27. {together-1.2.13 → together-1.3.0}/src/together/filemanager.py +0 -0
  28. {together-1.2.13 → together-1.3.0}/src/together/legacy/__init__.py +0 -0
  29. {together-1.2.13 → together-1.3.0}/src/together/legacy/base.py +0 -0
  30. {together-1.2.13 → together-1.3.0}/src/together/legacy/complete.py +0 -0
  31. {together-1.2.13 → together-1.3.0}/src/together/legacy/embeddings.py +0 -0
  32. {together-1.2.13 → together-1.3.0}/src/together/legacy/files.py +0 -0
  33. {together-1.2.13 → together-1.3.0}/src/together/legacy/images.py +0 -0
  34. {together-1.2.13 → together-1.3.0}/src/together/legacy/models.py +0 -0
  35. {together-1.2.13 → together-1.3.0}/src/together/resources/__init__.py +0 -0
  36. {together-1.2.13 → together-1.3.0}/src/together/resources/chat/__init__.py +0 -0
  37. {together-1.2.13 → together-1.3.0}/src/together/resources/chat/completions.py +0 -0
  38. {together-1.2.13 → together-1.3.0}/src/together/resources/completions.py +0 -0
  39. {together-1.2.13 → together-1.3.0}/src/together/resources/embeddings.py +0 -0
  40. {together-1.2.13 → together-1.3.0}/src/together/resources/files.py +0 -0
  41. {together-1.2.13 → together-1.3.0}/src/together/resources/images.py +0 -0
  42. {together-1.2.13 → together-1.3.0}/src/together/resources/models.py +0 -0
  43. {together-1.2.13 → together-1.3.0}/src/together/resources/rerank.py +0 -0
  44. {together-1.2.13 → together-1.3.0}/src/together/together_response.py +0 -0
  45. {together-1.2.13 → together-1.3.0}/src/together/types/abstract.py +0 -0
  46. {together-1.2.13 → together-1.3.0}/src/together/types/chat_completions.py +0 -0
  47. {together-1.2.13 → together-1.3.0}/src/together/types/common.py +0 -0
  48. {together-1.2.13 → together-1.3.0}/src/together/types/completions.py +0 -0
  49. {together-1.2.13 → together-1.3.0}/src/together/types/embeddings.py +0 -0
  50. {together-1.2.13 → together-1.3.0}/src/together/types/error.py +0 -0
  51. {together-1.2.13 → together-1.3.0}/src/together/types/files.py +0 -0
  52. {together-1.2.13 → together-1.3.0}/src/together/types/images.py +0 -0
  53. {together-1.2.13 → together-1.3.0}/src/together/types/models.py +0 -0
  54. {together-1.2.13 → together-1.3.0}/src/together/types/rerank.py +0 -0
  55. {together-1.2.13 → together-1.3.0}/src/together/utils/api_helpers.py +0 -0
  56. {together-1.2.13 → together-1.3.0}/src/together/utils/files.py +0 -0
  57. {together-1.2.13 → together-1.3.0}/src/together/utils/tools.py +0 -0
  58. {together-1.2.13 → together-1.3.0}/src/together/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: together
3
- Version: 1.2.13
3
+ Version: 1.3.0
4
4
  Summary: Python client for Together's Cloud Platform!
5
5
  Home-page: https://github.com/togethercomputer/together-python
6
6
  License: Apache-2.0
@@ -277,7 +277,7 @@ client.fine_tuning.create(
277
277
  model = 'mistralai/Mixtral-8x7B-Instruct-v0.1',
278
278
  n_epochs = 3,
279
279
  n_checkpoints = 1,
280
- batch_size = 4,
280
+ batch_size = "max",
281
281
  learning_rate = 1e-5,
282
282
  suffix = 'my-demo-finetune',
283
283
  wandb_api_key = '1a2b3c4d5e.......',
@@ -242,7 +242,7 @@ client.fine_tuning.create(
242
242
  model = 'mistralai/Mixtral-8x7B-Instruct-v0.1',
243
243
  n_epochs = 3,
244
244
  n_checkpoints = 1,
245
- batch_size = 4,
245
+ batch_size = "max",
246
246
  learning_rate = 1e-5,
247
247
  suffix = 'my-demo-finetune',
248
248
  wandb_api_key = '1a2b3c4d5e.......',
@@ -12,7 +12,7 @@ build-backend = "poetry.masonry.api"
12
12
 
13
13
  [tool.poetry]
14
14
  name = "together"
15
- version = "1.2.13"
15
+ version = "1.3.0"
16
16
  authors = [
17
17
  "Together AI <support@together.ai>"
18
18
  ]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  from datetime import datetime
5
5
  from textwrap import wrap
6
+ from typing import Any, Literal
6
7
 
7
8
  import click
8
9
  from click.core import ParameterSource # type: ignore[attr-defined]
@@ -10,8 +11,9 @@ from rich import print as rprint
10
11
  from tabulate import tabulate
11
12
 
12
13
  from together import Together
13
- from together.types.finetune import DownloadCheckpointType
14
+ from together.cli.api.utils import INT_WITH_MAX
14
15
  from together.utils import finetune_price_to_dollars, log_warn, parse_timestamp
16
+ from together.types.finetune import DownloadCheckpointType, FinetuneTrainingLimits
15
17
 
16
18
 
17
19
  _CONFIRMATION_MESSAGE = (
@@ -56,7 +58,7 @@ def fine_tuning(ctx: click.Context) -> None:
56
58
  @click.option(
57
59
  "--n-checkpoints", type=int, default=1, help="Number of checkpoints to save"
58
60
  )
59
- @click.option("--batch-size", type=int, default=16, help="Train batch size")
61
+ @click.option("--batch-size", type=INT_WITH_MAX, default="max", help="Train batch size")
60
62
  @click.option("--learning-rate", type=float, default=1e-5, help="Learning rate")
61
63
  @click.option(
62
64
  "--lora/--no-lora",
@@ -93,7 +95,7 @@ def create(
93
95
  n_epochs: int,
94
96
  n_evals: int,
95
97
  n_checkpoints: int,
96
- batch_size: int,
98
+ batch_size: int | Literal["max"],
97
99
  learning_rate: float,
98
100
  lora: bool,
99
101
  lora_r: int,
@@ -107,20 +109,64 @@ def create(
107
109
  """Start fine-tuning"""
108
110
  client: Together = ctx.obj
109
111
 
112
+ training_args: dict[str, Any] = dict(
113
+ training_file=training_file,
114
+ model=model,
115
+ n_epochs=n_epochs,
116
+ validation_file=validation_file,
117
+ n_evals=n_evals,
118
+ n_checkpoints=n_checkpoints,
119
+ batch_size=batch_size,
120
+ learning_rate=learning_rate,
121
+ lora=lora,
122
+ lora_r=lora_r,
123
+ lora_dropout=lora_dropout,
124
+ lora_alpha=lora_alpha,
125
+ lora_trainable_modules=lora_trainable_modules,
126
+ suffix=suffix,
127
+ wandb_api_key=wandb_api_key,
128
+ )
129
+
130
+ model_limits: FinetuneTrainingLimits = client.fine_tuning.get_model_limits(
131
+ model=model
132
+ )
133
+
110
134
  if lora:
111
- learning_rate_source = click.get_current_context().get_parameter_source( # type: ignore[attr-defined]
112
- "learning_rate"
113
- )
114
- if learning_rate_source == ParameterSource.DEFAULT:
115
- learning_rate = 1e-3
135
+ if model_limits.lora_training is None:
136
+ raise click.BadParameter(
137
+ f"LoRA fine-tuning is not supported for the model `{model}`"
138
+ )
139
+
140
+ default_values = {
141
+ "lora_r": model_limits.lora_training.max_rank,
142
+ "batch_size": model_limits.lora_training.max_batch_size,
143
+ "learning_rate": 1e-3,
144
+ }
145
+ for arg in default_values:
146
+ arg_source = ctx.get_parameter_source("arg") # type: ignore[attr-defined]
147
+ if arg_source == ParameterSource.DEFAULT:
148
+ training_args[arg] = default_values[arg_source]
149
+
150
+ if ctx.get_parameter_source("lora_alpha") == ParameterSource.DEFAULT: # type: ignore[attr-defined]
151
+ training_args["lora_alpha"] = training_args["lora_r"] * 2
116
152
  else:
153
+ if model_limits.full_training is None:
154
+ raise click.BadParameter(
155
+ f"Full fine-tuning is not supported for the model `{model}`"
156
+ )
157
+
117
158
  for param in ["lora_r", "lora_dropout", "lora_alpha", "lora_trainable_modules"]:
118
- param_source = click.get_current_context().get_parameter_source(param) # type: ignore[attr-defined]
159
+ param_source = ctx.get_parameter_source(param) # type: ignore[attr-defined]
119
160
  if param_source != ParameterSource.DEFAULT:
120
161
  raise click.BadParameter(
121
162
  f"You set LoRA parameter `{param}` for a full fine-tuning job. "
122
163
  f"Please change the job type with --lora or remove `{param}` from the arguments"
123
164
  )
165
+
166
+ batch_size_source = ctx.get_parameter_source("batch_size") # type: ignore[attr-defined]
167
+ if batch_size_source == ParameterSource.DEFAULT:
168
+ training_args["batch_size"] = model_limits.full_training.max_batch_size
169
+
124
170
  if n_evals <= 0 and validation_file:
125
171
  log_warn(
126
172
  "Warning: You have specified a validation file but the number of evaluation loops is set to 0. No evaluations will be performed."
@@ -0,0 +1,21 @@
1
+ import click
2
+
3
+ from typing import Literal
4
+
5
+
6
+ class AutoIntParamType(click.ParamType):
7
+ name = "integer"
8
+
9
+ def convert(
10
+ self, value: str, param: click.Parameter | None, ctx: click.Context | None
11
+ ) -> int | Literal["max"] | None:
12
+ if isinstance(value, int):
13
+ return value
14
+
15
+ if value == "max":
16
+ return "max"
17
+
18
+ self.fail("Invalid integer value: {value}")
19
+
20
+
21
+ INT_WITH_MAX = AutoIntParamType()
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import warnings
4
- from typing import Any, Dict, List
4
+ from typing import Any, Dict, List, Literal
5
5
 
6
6
  import together
7
7
  from together.legacy.base import API_KEY_WARNING, deprecated
@@ -43,7 +43,7 @@ class Finetune:
43
43
  model=model,
44
44
  n_epochs=n_epochs,
45
45
  n_checkpoints=n_checkpoints,
46
- batch_size=batch_size,
46
+ batch_size=batch_size if isinstance(batch_size, int) else "max",
47
47
  learning_rate=learning_rate,
48
48
  suffix=suffix,
49
49
  wandb_api_key=wandb_api_key,
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
+ from typing import Literal
4
5
 
5
6
  from rich import print as rprint
6
7
 
@@ -13,6 +14,7 @@ from together.types import (
13
14
  FinetuneListEvents,
14
15
  FinetuneRequest,
15
16
  FinetuneResponse,
17
+ FinetuneTrainingLimits,
16
18
  FullTrainingType,
17
19
  LoRATrainingType,
18
20
  TogetherClient,
@@ -20,7 +22,7 @@ from together.types import (
20
22
  TrainingType,
21
23
  )
22
24
  from together.types.finetune import DownloadCheckpointType
23
- from together.utils import log_warn, normalize_key
25
+ from together.utils import log_warn_once, normalize_key
24
26
 
25
27
 
26
28
  class FineTuning:
@@ -36,16 +38,17 @@ class FineTuning:
36
38
  validation_file: str | None = "",
37
39
  n_evals: int | None = 0,
38
40
  n_checkpoints: int | None = 1,
39
- batch_size: int | None = 16,
41
+ batch_size: int | Literal["max"] = "max",
40
42
  learning_rate: float | None = 0.00001,
41
43
  lora: bool = False,
42
- lora_r: int | None = 8,
44
+ lora_r: int | None = None,
43
45
  lora_dropout: float | None = 0,
44
- lora_alpha: float | None = 8,
46
+ lora_alpha: float | None = None,
45
47
  lora_trainable_modules: str | None = "all-linear",
46
48
  suffix: str | None = None,
47
49
  wandb_api_key: str | None = None,
48
50
  verbose: bool = False,
51
+ model_limits: FinetuneTrainingLimits | None = None,
49
52
  ) -> FinetuneResponse:
50
53
  """
51
54
  Method to initiate a fine-tuning job
@@ -58,7 +61,7 @@ class FineTuning:
58
61
  n_evals (int, optional): Number of evaluation loops to run. Defaults to 0.
59
62
  n_checkpoints (int, optional): Number of checkpoints to save during fine-tuning.
60
63
  Defaults to 1.
61
- batch_size (int, optional): Batch size for fine-tuning. Defaults to 32.
64
+ batch_size (int, optional): Batch size for fine-tuning. Defaults to max.
62
65
  learning_rate (float, optional): Learning rate multiplier to use for training
63
66
  Defaults to 0.00001.
64
67
  lora (bool, optional): Whether to use LoRA adapters. Defaults to True.
@@ -72,17 +75,36 @@ class FineTuning:
72
75
  Defaults to None.
73
76
  verbose (bool, optional): whether to print the job parameters before submitting a request.
74
77
  Defaults to False.
78
+ model_limits (FinetuneTrainingLimits, optional): Limits for the hyperparameters the model in Fine-tuning.
79
+ Defaults to None.
75
80
 
76
81
  Returns:
77
82
  FinetuneResponse: Object containing information about fine-tuning job.
78
83
  """
79
84
 
85
+ if batch_size == "max":
86
+ log_warn_once(
87
+ "Starting from together>=1.3.0, "
88
+ "the default batch size is set to the maximum allowed value for each model."
89
+ )
90
+
80
91
  requestor = api_requestor.APIRequestor(
81
92
  client=self._client,
82
93
  )
83
94
 
95
+ if model_limits is None:
96
+ model_limits = self.get_model_limits(model=model)
97
+
84
98
  training_type: TrainingType = FullTrainingType()
85
99
  if lora:
100
+ if model_limits.lora_training is None:
101
+ raise ValueError(
102
+ "LoRA adapters are not supported for the selected model."
103
+ )
104
+ lora_r = (
105
+ lora_r if lora_r is not None else model_limits.lora_training.max_rank
106
+ )
107
+ lora_alpha = lora_alpha if lora_alpha is not None else lora_r * 2
86
108
  training_type = LoRATrainingType(
87
109
  lora_r=lora_r,
88
110
  lora_alpha=lora_alpha,
@@ -90,6 +112,22 @@ class FineTuning:
90
112
  lora_trainable_modules=lora_trainable_modules,
91
113
  )
92
114
 
115
+ batch_size = (
116
+ batch_size
117
+ if batch_size != "max"
118
+ else model_limits.lora_training.max_batch_size
119
+ )
120
+ else:
121
+ if model_limits.full_training is None:
122
+ raise ValueError(
123
+ "Full training is not supported for the selected model."
124
+ )
125
+ batch_size = (
126
+ batch_size
127
+ if batch_size != "max"
128
+ else model_limits.full_training.max_batch_size
129
+ )
130
+
93
131
  finetune_request = FinetuneRequest(
94
132
  model=model,
95
133
  training_file=training_file,
@@ -121,12 +159,6 @@ class FineTuning:
121
159
 
122
160
  assert isinstance(response, TogetherResponse)
123
161
 
124
- # TODO: Remove after next LoRA default change
125
- log_warn(
126
- "Some of the jobs run _directly_ from the together-python library might be trained using LoRA adapters. "
127
- "The version range when this change occurred is from 1.2.3 to 1.2.6."
128
- )
129
-
130
162
  return FinetuneResponse(**response.data)
131
163
 
132
164
  def list(self) -> FinetuneList:
@@ -305,6 +337,34 @@ class FineTuning:
305
337
  size=file_size,
306
338
  )
307
339
 
340
+ def get_model_limits(self, *, model: str) -> FinetuneTrainingLimits:
341
+ """
342
+ Requests training limits for a specific model
343
+
344
+ Args:
345
+ model_name (str): Name of the model to get limits for
346
+
347
+ Returns:
348
+ FinetuneTrainingLimits: Object containing training limits for the model
349
+ """
350
+
351
+ requestor = api_requestor.APIRequestor(
352
+ client=self._client,
353
+ )
354
+
355
+ model_limits_response, _, _ = requestor.request(
356
+ options=TogetherRequest(
357
+ method="GET",
358
+ url="fine-tunes/models/limits",
359
+ params={"model_name": model},
360
+ ),
361
+ stream=False,
362
+ )
363
+
364
+ model_limits = FinetuneTrainingLimits(**model_limits_response.data)
365
+
366
+ return model_limits
367
+
308
368
 
309
369
  class AsyncFineTuning:
310
370
  def __init__(self, client: TogetherClient) -> None:
@@ -493,3 +553,31 @@ class AsyncFineTuning:
493
553
  "AsyncFineTuning.download not implemented. "
494
554
  "Please use FineTuning.download function instead."
495
555
  )
556
+
557
+ async def get_model_limits(self, *, model: str) -> FinetuneTrainingLimits:
558
+ """
559
+ Requests training limits for a specific model
560
+
561
+ Args:
562
+ model_name (str): Name of the model to get limits for
563
+
564
+ Returns:
565
+ FinetuneTrainingLimits: Object containing training limits for the model
566
+ """
567
+
568
+ requestor = api_requestor.APIRequestor(
569
+ client=self._client,
570
+ )
571
+
572
+ model_limits_response, _, _ = await requestor.arequest(
573
+ options=TogetherRequest(
574
+ method="GET",
575
+ url="fine-tunes/models/limits",
576
+ params={"model": model},
577
+ ),
578
+ stream=False,
579
+ )
580
+
581
+ model_limits = FinetuneTrainingLimits(**model_limits_response.data)
582
+
583
+ return model_limits
@@ -29,6 +29,7 @@ from together.types.finetune import (
29
29
  FullTrainingType,
30
30
  LoRATrainingType,
31
31
  TrainingType,
32
+ FinetuneTrainingLimits,
32
33
  )
33
34
  from together.types.images import (
34
35
  ImageRequest,
@@ -71,4 +72,5 @@ __all__ = [
71
72
  "LoRATrainingType",
72
73
  "RerankRequest",
73
74
  "RerankResponse",
75
+ "FinetuneTrainingLimits",
74
76
  ]
@@ -263,3 +263,21 @@ class FinetuneDownloadResult(BaseModel):
263
263
  filename: str | None = None
264
264
  # size in bytes
265
265
  size: int | None = None
266
+
267
+
268
+ class FinetuneFullTrainingLimits(BaseModel):
269
+ max_batch_size: int
270
+ min_batch_size: int
271
+
272
+
273
+ class FinetuneLoraTrainingLimits(FinetuneFullTrainingLimits):
274
+ max_rank: int
275
+ target_modules: List[str]
276
+
277
+
278
+ class FinetuneTrainingLimits(BaseModel):
279
+ max_num_epochs: int
280
+ max_learning_rate: float
281
+ min_learning_rate: float
282
+ full_training: FinetuneFullTrainingLimits | None = None
283
+ lora_training: FinetuneLoraTrainingLimits | None = None
@@ -1,4 +1,4 @@
1
- from together.utils._log import log_debug, log_info, log_warn, logfmt
1
+ from together.utils._log import log_debug, log_info, log_warn, log_warn_once, logfmt
2
2
  from together.utils.api_helpers import default_api_key, get_headers
3
3
  from together.utils.files import check_file
4
4
  from together.utils.tools import (
@@ -18,6 +18,7 @@ __all__ = [
18
18
  "log_debug",
19
19
  "log_info",
20
20
  "log_warn",
21
+ "log_warn_once",
21
22
  "logfmt",
22
23
  "enforce_trailing_slash",
23
24
  "normalize_key",
@@ -13,6 +13,8 @@ logger = logging.getLogger("together")
13
13
 
14
14
  TOGETHER_LOG = os.environ.get("TOGETHER_LOG")
15
15
 
16
+ WARNING_MESSAGES_ONCE = set()
17
+
16
18
 
17
19
  def _console_log_level() -> str | None:
18
20
  if together.log in ["debug", "info"]:
@@ -59,3 +61,11 @@ def log_warn(message: str | Any, **params: Any) -> None:
59
61
  msg = logfmt(dict(message=message, **params))
60
62
  print(msg, file=sys.stderr)
61
63
  logger.warn(msg)
64
+
65
+
66
+ def log_warn_once(message: str | Any, **params: Any) -> None:
67
+ msg = logfmt(dict(message=message, **params))
68
+ if msg not in WARNING_MESSAGES_ONCE:
69
+ print(msg, file=sys.stderr)
70
+ logger.warn(msg)
71
+ WARNING_MESSAGES_ONCE.add(msg)
File without changes