together 1.5.21__py3-none-any.whl → 1.5.24__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.
@@ -0,0 +1,379 @@
1
+ import json
2
+ from typing import Optional, Dict, Union, Any
3
+
4
+ import click
5
+ from tabulate import tabulate
6
+
7
+ from together import Together
8
+ from together.utils import convert_unix_timestamp
9
+
10
+
11
+ @click.group()
12
+ @click.pass_context
13
+ def evaluation(ctx: click.Context) -> None:
14
+ """Evaluation API commands"""
15
+ pass
16
+
17
+
18
+ @evaluation.command()
19
+ @click.pass_context
20
+ @click.option(
21
+ "--type",
22
+ type=click.Choice(["classify", "score", "compare"]),
23
+ required=True,
24
+ help="Type of evaluation to create.",
25
+ )
26
+ @click.option(
27
+ "--judge-model-name",
28
+ type=str,
29
+ required=True,
30
+ help="Name of the judge model to use for evaluation.",
31
+ )
32
+ @click.option(
33
+ "--judge-system-template",
34
+ type=str,
35
+ required=True,
36
+ help="System template for the judge model.",
37
+ )
38
+ @click.option(
39
+ "--input-data-file-path",
40
+ type=str,
41
+ required=True,
42
+ help="Path to the input data file.",
43
+ )
44
+ @click.option(
45
+ "--model-field",
46
+ type=str,
47
+ help="Name of the field in the input file contaning text generated by the model."
48
+ "Can not be used when model-a-name and other model config parameters are specified",
49
+ )
50
+ @click.option(
51
+ "--model-to-evaluate-name",
52
+ type=str,
53
+ help="Model name when using the detailed config",
54
+ )
55
+ @click.option(
56
+ "--model-to-evaluate-max-tokens",
57
+ type=int,
58
+ help="Max tokens for model-to-evaluate",
59
+ )
60
+ @click.option(
61
+ "--model-to-evaluate-temperature",
62
+ type=float,
63
+ help="Temperature for model-to-evaluate",
64
+ )
65
+ @click.option(
66
+ "--model-to-evaluate-system-template",
67
+ type=str,
68
+ help="System template for model-to-evaluate",
69
+ )
70
+ @click.option(
71
+ "--model-to-evaluate-input-template",
72
+ type=str,
73
+ help="Input template for model-to-evaluate",
74
+ )
75
+ @click.option(
76
+ "--labels",
77
+ type=str,
78
+ help="Classification labels - comma-separated list",
79
+ )
80
+ @click.option(
81
+ "--pass-labels",
82
+ type=str,
83
+ help="Labels considered as passing (required for classify type). A comma-separated list.",
84
+ )
85
+ @click.option(
86
+ "--min-score",
87
+ type=float,
88
+ help="Minimum score value (required for score type).",
89
+ )
90
+ @click.option(
91
+ "--max-score",
92
+ type=float,
93
+ help="Maximum score value (required for score type).",
94
+ )
95
+ @click.option(
96
+ "--pass-threshold",
97
+ type=float,
98
+ help="Threshold score for passing (required for score type).",
99
+ )
100
+ @click.option(
101
+ "--model-a-field",
102
+ type=str,
103
+ help="Name of the field in the input file containing text generated by Model A. \
104
+ Can not be used when model-a-name and other model config parameters are specified",
105
+ )
106
+ @click.option(
107
+ "--model-a-name",
108
+ type=str,
109
+ help="Model name for model A when using detailed config.",
110
+ )
111
+ @click.option(
112
+ "--model-a-max-tokens",
113
+ type=int,
114
+ help="Max tokens for model A.",
115
+ )
116
+ @click.option(
117
+ "--model-a-temperature",
118
+ type=float,
119
+ help="Temperature for model A.",
120
+ )
121
+ @click.option(
122
+ "--model-a-system-template",
123
+ type=str,
124
+ help="System template for model A.",
125
+ )
126
+ @click.option(
127
+ "--model-a-input-template",
128
+ type=str,
129
+ help="Input template for model A.",
130
+ )
131
+ @click.option(
132
+ "--model-b-field",
133
+ type=str,
134
+ help="Name of the field in the input file containing text generated by Model B.\
135
+ Can not be used when model-b-name and other model config parameters are specified",
136
+ )
137
+ @click.option(
138
+ "--model-b-name",
139
+ type=str,
140
+ help="Model name for model B when using detailed config.",
141
+ )
142
+ @click.option(
143
+ "--model-b-max-tokens",
144
+ type=int,
145
+ help="Max tokens for model B.",
146
+ )
147
+ @click.option(
148
+ "--model-b-temperature",
149
+ type=float,
150
+ help="Temperature for model B.",
151
+ )
152
+ @click.option(
153
+ "--model-b-system-template",
154
+ type=str,
155
+ help="System template for model B.",
156
+ )
157
+ @click.option(
158
+ "--model-b-input-template",
159
+ type=str,
160
+ help="Input template for model B.",
161
+ )
162
+ def create(
163
+ ctx: click.Context,
164
+ type: str,
165
+ judge_model_name: str,
166
+ judge_system_template: str,
167
+ input_data_file_path: str,
168
+ model_field: Optional[str],
169
+ model_to_evaluate_name: Optional[str],
170
+ model_to_evaluate_max_tokens: Optional[int],
171
+ model_to_evaluate_temperature: Optional[float],
172
+ model_to_evaluate_system_template: Optional[str],
173
+ model_to_evaluate_input_template: Optional[str],
174
+ labels: str,
175
+ pass_labels: str,
176
+ min_score: Optional[float],
177
+ max_score: Optional[float],
178
+ pass_threshold: Optional[float],
179
+ model_a_field: Optional[str],
180
+ model_a_name: Optional[str],
181
+ model_a_max_tokens: Optional[int],
182
+ model_a_temperature: Optional[float],
183
+ model_a_system_template: Optional[str],
184
+ model_a_input_template: Optional[str],
185
+ model_b_field: Optional[str],
186
+ model_b_name: Optional[str],
187
+ model_b_max_tokens: Optional[int],
188
+ model_b_temperature: Optional[float],
189
+ model_b_system_template: Optional[str],
190
+ model_b_input_template: Optional[str],
191
+ ) -> None:
192
+ """Create a new evaluation job"""
193
+
194
+ client: Together = ctx.obj
195
+
196
+ # Convert strings to lists for labels
197
+ labels_list = labels.split(",") if labels else None
198
+ pass_labels_list = pass_labels.split(",") if pass_labels else None
199
+
200
+ # Build model configurations
201
+ model_to_evaluate_final: Union[Dict[str, Any], None, str] = None
202
+
203
+ # Check if any config parameters are provided
204
+ config_params_provided = any(
205
+ [
206
+ model_to_evaluate_name,
207
+ model_to_evaluate_max_tokens,
208
+ model_to_evaluate_temperature,
209
+ model_to_evaluate_system_template,
210
+ model_to_evaluate_input_template,
211
+ ]
212
+ )
213
+
214
+ if model_field:
215
+ # Simple mode: model_field is provided
216
+ if config_params_provided:
217
+ raise click.BadParameter(
218
+ "Cannot specify both --model-field and --model-to-evaluate-* parameters. "
219
+ "Use either --model-field alone if your input file has pre-generated responses, "
220
+ "or config parameters if you want to generate it on our end"
221
+ )
222
+ model_to_evaluate_final = model_field
223
+ elif config_params_provided:
224
+ # Config mode: config parameters are provided
225
+ model_to_evaluate_final = {
226
+ "model_name": model_to_evaluate_name,
227
+ "max_tokens": model_to_evaluate_max_tokens,
228
+ "temperature": model_to_evaluate_temperature,
229
+ "system_template": model_to_evaluate_system_template,
230
+ "input_template": model_to_evaluate_input_template,
231
+ }
232
+
233
+ # Build model-a configuration
234
+ model_a_final: Union[Dict[str, Any], None, str] = None
235
+ model_a_config_params = [
236
+ model_a_name,
237
+ model_a_max_tokens,
238
+ model_a_temperature,
239
+ model_a_system_template,
240
+ model_a_input_template,
241
+ ]
242
+
243
+ if model_a_field is not None:
244
+ # Simple mode: model_a_field is provided
245
+ if any(model_a_config_params):
246
+ raise click.BadParameter(
247
+ "Cannot specify both --model-a-field and config parameters (--model-a-name, etc.). "
248
+ "Use either --model-a-field alone if your input file has pre-generated responses, "
249
+ "or config parameters if you want to generate it on our end"
250
+ )
251
+ model_a_final = model_a_field
252
+ elif any(model_a_config_params):
253
+ # Config mode: config parameters are provided
254
+ model_a_final = {
255
+ "model_name": model_a_name,
256
+ "max_tokens": model_a_max_tokens,
257
+ "temperature": model_a_temperature,
258
+ "system_template": model_a_system_template,
259
+ "input_template": model_a_input_template,
260
+ }
261
+
262
+ # Build model-b configuration
263
+ model_b_final: Union[Dict[str, Any], None, str] = None
264
+ model_b_config_params = [
265
+ model_b_name,
266
+ model_b_max_tokens,
267
+ model_b_temperature,
268
+ model_b_system_template,
269
+ model_b_input_template,
270
+ ]
271
+
272
+ if model_b_field is not None:
273
+ # Simple mode: model_b_field is provided
274
+ if any(model_b_config_params):
275
+ raise click.BadParameter(
276
+ "Cannot specify both --model-b-field and config parameters (--model-b-name, etc.). "
277
+ "Use either --model-b-field alone if your input file has pre-generated responses, "
278
+ "or config parameters if you want to generate it on our end"
279
+ )
280
+ model_b_final = model_b_field
281
+ elif any(model_b_config_params):
282
+ # Config mode: config parameters are provided
283
+ model_b_final = {
284
+ "model_name": model_b_name,
285
+ "max_tokens": model_b_max_tokens,
286
+ "temperature": model_b_temperature,
287
+ "system_template": model_b_system_template,
288
+ "input_template": model_b_input_template,
289
+ }
290
+
291
+ try:
292
+ response = client.evaluation.create(
293
+ type=type,
294
+ judge_model_name=judge_model_name,
295
+ judge_system_template=judge_system_template,
296
+ input_data_file_path=input_data_file_path,
297
+ model_to_evaluate=model_to_evaluate_final,
298
+ labels=labels_list,
299
+ pass_labels=pass_labels_list,
300
+ min_score=min_score,
301
+ max_score=max_score,
302
+ pass_threshold=pass_threshold,
303
+ model_a=model_a_final,
304
+ model_b=model_b_final,
305
+ )
306
+ except ValueError as e:
307
+ raise click.BadParameter(str(e))
308
+
309
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
310
+
311
+
312
+ @evaluation.command()
313
+ @click.pass_context
314
+ @click.option(
315
+ "--status",
316
+ type=str,
317
+ help="Filter by job status.",
318
+ )
319
+ @click.option(
320
+ "--limit",
321
+ type=int,
322
+ help="Limit number of results (max 100).",
323
+ )
324
+ def list(ctx: click.Context, status: Optional[str], limit: Optional[int]) -> None:
325
+ """List evaluation jobs"""
326
+
327
+ client: Together = ctx.obj
328
+
329
+ response = client.evaluation.list(status=status, limit=limit)
330
+
331
+ display_list = []
332
+ for job in response:
333
+ if job.parameters:
334
+ model = job.parameters.get("model_to_evaluate", "")
335
+ model_a = job.parameters.get("model_a", "")
336
+ model_b = job.parameters.get("model_b", "")
337
+ else:
338
+ model = ""
339
+
340
+ display_list.append(
341
+ {
342
+ "Workflow ID": job.workflow_id or "",
343
+ "Type": job.type,
344
+ "Status": job.status,
345
+ "Created At": job.created_at or 0,
346
+ "Model": model,
347
+ "Model A": model_a,
348
+ "Model B": model_b,
349
+ }
350
+ )
351
+
352
+ table = tabulate(display_list, headers="keys", tablefmt="grid", showindex=True)
353
+ click.echo(table)
354
+
355
+
356
+ @evaluation.command()
357
+ @click.pass_context
358
+ @click.argument("evaluation_id", type=str, required=True)
359
+ def retrieve(ctx: click.Context, evaluation_id: str) -> None:
360
+ """Get details of a specific evaluation job"""
361
+
362
+ client: Together = ctx.obj
363
+
364
+ response = client.evaluation.retrieve(evaluation_id=evaluation_id)
365
+
366
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
367
+
368
+
369
+ @evaluation.command()
370
+ @click.pass_context
371
+ @click.argument("evaluation_id", type=str, required=True)
372
+ def status(ctx: click.Context, evaluation_id: str) -> None:
373
+ """Get the status and results of a specific evaluation job"""
374
+
375
+ client: Together = ctx.obj
376
+
377
+ response = client.evaluation.status(evaluation_id=evaluation_id)
378
+
379
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -200,6 +200,20 @@ def fine_tuning(ctx: click.Context) -> None:
200
200
  "The format: {$JOB_ID/$OUTPUT_MODEL_NAME}:{$STEP}. "
201
201
  "The step value is optional, without it the final checkpoint will be used.",
202
202
  )
203
+ @click.option(
204
+ "--from-hf-model",
205
+ type=str,
206
+ help="The Hugging Face Hub repo to start training from. "
207
+ "Should be as close as possible to the base model (specified by the `model` argument) "
208
+ "in terms of architecture and size",
209
+ )
210
+ @click.option(
211
+ "--hf-model-revision",
212
+ type=str,
213
+ help="The revision of the Hugging Face Hub model to continue training from. "
214
+ "Example: hf_model_revision=None (defaults to the latest revision in `main`) "
215
+ "or hf_model_revision='607a30d783dfa663caf39e06633721c8d4cfcd7e' (specific commit).",
216
+ )
203
217
  @click.option(
204
218
  "--hf-api-token",
205
219
  type=str,
@@ -246,6 +260,8 @@ def create(
246
260
  rpo_alpha: float | None,
247
261
  simpo_gamma: float | None,
248
262
  from_checkpoint: str,
263
+ from_hf_model: str,
264
+ hf_model_revision: str,
249
265
  hf_api_token: str | None,
250
266
  hf_output_repo_name: str | None,
251
267
  ) -> None:
@@ -284,6 +300,8 @@ def create(
284
300
  rpo_alpha=rpo_alpha,
285
301
  simpo_gamma=simpo_gamma,
286
302
  from_checkpoint=from_checkpoint,
303
+ from_hf_model=from_hf_model,
304
+ hf_model_revision=hf_model_revision,
287
305
  hf_api_token=hf_api_token,
288
306
  hf_output_repo_name=hf_output_repo_name,
289
307
  )
@@ -304,13 +322,8 @@ def create(
304
322
  raise click.BadParameter(
305
323
  f"LoRA fine-tuning is not supported for the model `{model}`"
306
324
  )
307
- if training_method == "dpo":
308
- default_batch_size = model_limits.lora_training.max_batch_size_dpo
309
- else:
310
- default_batch_size = model_limits.lora_training.max_batch_size
311
325
  default_values = {
312
326
  "lora_r": model_limits.lora_training.max_rank,
313
- "batch_size": default_batch_size,
314
327
  "learning_rate": 1e-3,
315
328
  }
316
329
 
@@ -335,15 +348,6 @@ def create(
335
348
  f"Please change the job type with --lora or remove `{param}` from the arguments"
336
349
  )
337
350
 
338
- batch_size_source = ctx.get_parameter_source("batch_size") # type: ignore[attr-defined]
339
- if batch_size_source == ParameterSource.DEFAULT:
340
- if training_method == "dpo":
341
- training_args["batch_size"] = (
342
- model_limits.full_training.max_batch_size_dpo
343
- )
344
- else:
345
- training_args["batch_size"] = model_limits.full_training.max_batch_size
346
-
347
351
  if n_evals <= 0 and validation_file:
348
352
  log_warn(
349
353
  "Warning: You have specified a validation file but the number of evaluation loops is set to 0. No evaluations will be performed."
together/cli/cli.py CHANGED
@@ -9,6 +9,7 @@ import together
9
9
  from together.cli.api.chat import chat, interactive
10
10
  from together.cli.api.completions import completions
11
11
  from together.cli.api.endpoints import endpoints
12
+ from together.cli.api.evaluation import evaluation
12
13
  from together.cli.api.files import files
13
14
  from together.cli.api.finetune import fine_tuning
14
15
  from together.cli.api.images import images
@@ -74,6 +75,7 @@ main.add_command(files)
74
75
  main.add_command(fine_tuning)
75
76
  main.add_command(models)
76
77
  main.add_command(endpoints)
78
+ main.add_command(evaluation)
77
79
 
78
80
  if __name__ == "__main__":
79
81
  main()
together/client.py CHANGED
@@ -25,6 +25,7 @@ class Together:
25
25
  audio: resources.Audio
26
26
  batches: resources.Batches
27
27
  code_interpreter: CodeInterpreter
28
+ evaluation: resources.Evaluation
28
29
 
29
30
  # client options
30
31
  client: TogetherClient
@@ -92,6 +93,7 @@ class Together:
92
93
  self.endpoints = resources.Endpoints(self.client)
93
94
  self.code_interpreter = CodeInterpreter(self.client)
94
95
  self.batches = resources.Batches(self.client)
96
+ self.evaluation = resources.Evaluation(self.client)
95
97
 
96
98
 
97
99
  class AsyncTogether:
@@ -106,6 +108,7 @@ class AsyncTogether:
106
108
  audio: resources.AsyncAudio
107
109
  code_interpreter: CodeInterpreter
108
110
  batches: resources.AsyncBatches
111
+ evaluation: resources.AsyncEvaluation
109
112
  # client options
110
113
  client: TogetherClient
111
114
 
@@ -171,6 +174,7 @@ class AsyncTogether:
171
174
  self.audio = resources.AsyncAudio(self.client)
172
175
  self.code_interpreter = CodeInterpreter(self.client)
173
176
  self.batches = resources.AsyncBatches(self.client)
177
+ self.evaluation = resources.AsyncEvaluation(self.client)
174
178
 
175
179
 
176
180
  Client = Together
together/filemanager.py CHANGED
@@ -73,8 +73,6 @@ def _get_file_size(
73
73
  if len(range_parts) == 2:
74
74
  total_size_in_bytes = int(range_parts[1])
75
75
 
76
- assert total_size_in_bytes != 0, "Unable to retrieve remote file."
77
-
78
76
  return total_size_in_bytes
79
77
 
80
78
 
@@ -213,8 +211,6 @@ class DownloadManager:
213
211
  if not fetch_metadata:
214
212
  file_size = int(response.headers.get("content-length", 0))
215
213
 
216
- assert file_size != 0, "Unable to retrieve remote file."
217
-
218
214
  with tqdm(
219
215
  total=file_size,
220
216
  unit="B",
@@ -334,6 +330,8 @@ class UploadManager:
334
330
  filetype = FileType.jsonl
335
331
  elif file.suffix == ".parquet":
336
332
  filetype = FileType.parquet
333
+ elif file.suffix == ".csv":
334
+ filetype = FileType.csv
337
335
  else:
338
336
  raise FileTypeError(
339
337
  f"Unknown extension of file {file}. "
@@ -16,7 +16,7 @@ class Finetune:
16
16
  model: str,
17
17
  n_epochs: int = 1,
18
18
  n_checkpoints: int | None = 1,
19
- batch_size: int | None = 32,
19
+ batch_size: int | Literal["max"] = "max",
20
20
  learning_rate: float = 0.00001,
21
21
  suffix: (
22
22
  str | None
@@ -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 if isinstance(batch_size, int) else "max",
46
+ batch_size=batch_size,
47
47
  learning_rate=learning_rate,
48
48
  suffix=suffix,
49
49
  wandb_api_key=wandb_api_key,
@@ -9,6 +9,7 @@ from together.resources.images import AsyncImages, Images
9
9
  from together.resources.models import AsyncModels, Models
10
10
  from together.resources.rerank import AsyncRerank, Rerank
11
11
  from together.resources.batch import Batches, AsyncBatches
12
+ from together.resources.evaluation import Evaluation, AsyncEvaluation
12
13
 
13
14
 
14
15
  __all__ = [
@@ -34,4 +35,6 @@ __all__ = [
34
35
  "Endpoints",
35
36
  "Batches",
36
37
  "AsyncBatches",
38
+ "Evaluation",
39
+ "AsyncEvaluation",
37
40
  ]
@@ -16,7 +16,6 @@ class Batches:
16
16
  self._client = client
17
17
 
18
18
  def create_batch(self, file_id: str, endpoint: str) -> BatchJob:
19
-
20
19
  requestor = api_requestor.APIRequestor(
21
20
  client=self._client,
22
21
  )