together 1.5.35__py3-none-any.whl → 2.0.0a6__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.
- together/__init__.py +101 -114
- together/_base_client.py +1995 -0
- together/_client.py +1033 -0
- together/_compat.py +219 -0
- together/_constants.py +14 -0
- together/_exceptions.py +108 -0
- together/_files.py +123 -0
- together/_models.py +857 -0
- together/_qs.py +150 -0
- together/_resource.py +43 -0
- together/_response.py +830 -0
- together/_streaming.py +370 -0
- together/_types.py +260 -0
- together/_utils/__init__.py +64 -0
- together/_utils/_compat.py +45 -0
- together/_utils/_datetime_parse.py +136 -0
- together/_utils/_logs.py +25 -0
- together/_utils/_proxy.py +65 -0
- together/_utils/_reflection.py +42 -0
- together/_utils/_resources_proxy.py +24 -0
- together/_utils/_streams.py +12 -0
- together/_utils/_sync.py +58 -0
- together/_utils/_transform.py +457 -0
- together/_utils/_typing.py +156 -0
- together/_utils/_utils.py +421 -0
- together/_version.py +4 -0
- together/lib/.keep +4 -0
- together/lib/__init__.py +23 -0
- together/{cli → lib/cli}/api/endpoints.py +66 -84
- together/{cli/api/evaluation.py → lib/cli/api/evals.py} +152 -43
- together/{cli → lib/cli}/api/files.py +20 -17
- together/{cli/api/finetune.py → lib/cli/api/fine_tuning.py} +116 -172
- together/{cli → lib/cli}/api/models.py +34 -27
- together/lib/cli/api/utils.py +50 -0
- together/{cli → lib/cli}/cli.py +16 -26
- together/{constants.py → lib/constants.py} +11 -24
- together/lib/resources/__init__.py +11 -0
- together/lib/resources/files.py +999 -0
- together/lib/resources/fine_tuning.py +280 -0
- together/lib/resources/models.py +35 -0
- together/lib/types/__init__.py +13 -0
- together/lib/types/error.py +9 -0
- together/lib/types/fine_tuning.py +397 -0
- together/{utils → lib/utils}/__init__.py +6 -14
- together/{utils → lib/utils}/_log.py +11 -16
- together/{utils → lib/utils}/files.py +90 -288
- together/lib/utils/serializer.py +10 -0
- together/{utils → lib/utils}/tools.py +19 -55
- together/resources/__init__.py +225 -39
- together/resources/audio/__init__.py +72 -48
- together/resources/audio/audio.py +198 -0
- together/resources/audio/speech.py +574 -128
- together/resources/audio/transcriptions.py +247 -261
- together/resources/audio/translations.py +221 -241
- together/resources/audio/voices.py +111 -41
- together/resources/batches.py +417 -0
- together/resources/chat/__init__.py +30 -21
- together/resources/chat/chat.py +102 -0
- together/resources/chat/completions.py +1063 -263
- together/resources/code_interpreter/__init__.py +33 -0
- together/resources/code_interpreter/code_interpreter.py +258 -0
- together/resources/code_interpreter/sessions.py +135 -0
- together/resources/completions.py +884 -225
- together/resources/embeddings.py +172 -68
- together/resources/endpoints.py +589 -490
- together/resources/evals.py +452 -0
- together/resources/files.py +397 -129
- together/resources/fine_tuning.py +1033 -0
- together/resources/hardware.py +181 -0
- together/resources/images.py +258 -104
- together/resources/jobs.py +214 -0
- together/resources/models.py +223 -193
- together/resources/rerank.py +190 -92
- together/resources/videos.py +286 -214
- together/types/__init__.py +66 -167
- together/types/audio/__init__.py +10 -0
- together/types/audio/speech_create_params.py +75 -0
- together/types/audio/transcription_create_params.py +54 -0
- together/types/audio/transcription_create_response.py +111 -0
- together/types/audio/translation_create_params.py +40 -0
- together/types/audio/translation_create_response.py +70 -0
- together/types/audio/voice_list_response.py +23 -0
- together/types/audio_speech_stream_chunk.py +16 -0
- together/types/autoscaling.py +13 -0
- together/types/autoscaling_param.py +15 -0
- together/types/batch_create_params.py +24 -0
- together/types/batch_create_response.py +14 -0
- together/types/batch_job.py +45 -0
- together/types/batch_list_response.py +10 -0
- together/types/chat/__init__.py +18 -0
- together/types/chat/chat_completion.py +60 -0
- together/types/chat/chat_completion_chunk.py +61 -0
- together/types/chat/chat_completion_structured_message_image_url_param.py +18 -0
- together/types/chat/chat_completion_structured_message_text_param.py +13 -0
- together/types/chat/chat_completion_structured_message_video_url_param.py +18 -0
- together/types/chat/chat_completion_usage.py +13 -0
- together/types/chat/chat_completion_warning.py +9 -0
- together/types/chat/completion_create_params.py +329 -0
- together/types/code_interpreter/__init__.py +5 -0
- together/types/code_interpreter/session_list_response.py +31 -0
- together/types/code_interpreter_execute_params.py +45 -0
- together/types/completion.py +42 -0
- together/types/completion_chunk.py +66 -0
- together/types/completion_create_params.py +138 -0
- together/types/dedicated_endpoint.py +44 -0
- together/types/embedding.py +24 -0
- together/types/embedding_create_params.py +31 -0
- together/types/endpoint_create_params.py +43 -0
- together/types/endpoint_list_avzones_response.py +11 -0
- together/types/endpoint_list_params.py +18 -0
- together/types/endpoint_list_response.py +41 -0
- together/types/endpoint_update_params.py +27 -0
- together/types/eval_create_params.py +263 -0
- together/types/eval_create_response.py +16 -0
- together/types/eval_list_params.py +21 -0
- together/types/eval_list_response.py +10 -0
- together/types/eval_status_response.py +100 -0
- together/types/evaluation_job.py +139 -0
- together/types/execute_response.py +108 -0
- together/types/file_delete_response.py +13 -0
- together/types/file_list.py +12 -0
- together/types/file_purpose.py +9 -0
- together/types/file_response.py +31 -0
- together/types/file_type.py +7 -0
- together/types/fine_tuning_cancel_response.py +194 -0
- together/types/fine_tuning_content_params.py +24 -0
- together/types/fine_tuning_delete_params.py +11 -0
- together/types/fine_tuning_delete_response.py +12 -0
- together/types/fine_tuning_list_checkpoints_response.py +21 -0
- together/types/fine_tuning_list_events_response.py +12 -0
- together/types/fine_tuning_list_response.py +199 -0
- together/types/finetune_event.py +41 -0
- together/types/finetune_event_type.py +33 -0
- together/types/finetune_response.py +177 -0
- together/types/hardware_list_params.py +16 -0
- together/types/hardware_list_response.py +58 -0
- together/types/image_data_b64.py +15 -0
- together/types/image_data_url.py +15 -0
- together/types/image_file.py +23 -0
- together/types/image_generate_params.py +85 -0
- together/types/job_list_response.py +47 -0
- together/types/job_retrieve_response.py +43 -0
- together/types/log_probs.py +18 -0
- together/types/model_list_response.py +10 -0
- together/types/model_object.py +42 -0
- together/types/model_upload_params.py +36 -0
- together/types/model_upload_response.py +23 -0
- together/types/rerank_create_params.py +36 -0
- together/types/rerank_create_response.py +36 -0
- together/types/tool_choice.py +23 -0
- together/types/tool_choice_param.py +23 -0
- together/types/tools_param.py +23 -0
- together/types/training_method_dpo.py +22 -0
- together/types/training_method_sft.py +18 -0
- together/types/video_create_params.py +86 -0
- together/types/video_create_response.py +10 -0
- together/types/video_job.py +57 -0
- together-2.0.0a6.dist-info/METADATA +729 -0
- together-2.0.0a6.dist-info/RECORD +165 -0
- {together-1.5.35.dist-info → together-2.0.0a6.dist-info}/WHEEL +1 -1
- together-2.0.0a6.dist-info/entry_points.txt +2 -0
- {together-1.5.35.dist-info → together-2.0.0a6.dist-info}/licenses/LICENSE +1 -1
- together/abstract/api_requestor.py +0 -770
- together/cli/api/chat.py +0 -298
- together/cli/api/completions.py +0 -119
- together/cli/api/images.py +0 -93
- together/cli/api/utils.py +0 -139
- together/client.py +0 -186
- together/error.py +0 -194
- together/filemanager.py +0 -635
- together/legacy/__init__.py +0 -0
- together/legacy/base.py +0 -27
- together/legacy/complete.py +0 -93
- together/legacy/embeddings.py +0 -27
- together/legacy/files.py +0 -146
- together/legacy/finetune.py +0 -177
- together/legacy/images.py +0 -27
- together/legacy/models.py +0 -44
- together/resources/batch.py +0 -165
- together/resources/code_interpreter.py +0 -82
- together/resources/evaluation.py +0 -808
- together/resources/finetune.py +0 -1388
- together/together_response.py +0 -50
- together/types/abstract.py +0 -26
- together/types/audio_speech.py +0 -311
- together/types/batch.py +0 -54
- together/types/chat_completions.py +0 -210
- together/types/code_interpreter.py +0 -57
- together/types/common.py +0 -67
- together/types/completions.py +0 -107
- together/types/embeddings.py +0 -35
- together/types/endpoints.py +0 -123
- together/types/error.py +0 -16
- together/types/evaluation.py +0 -93
- together/types/files.py +0 -93
- together/types/finetune.py +0 -465
- together/types/images.py +0 -42
- together/types/models.py +0 -96
- together/types/rerank.py +0 -43
- together/types/videos.py +0 -69
- together/utils/api_helpers.py +0 -124
- together/version.py +0 -6
- together-1.5.35.dist-info/METADATA +0 -583
- together-1.5.35.dist-info/RECORD +0 -77
- together-1.5.35.dist-info/entry_points.txt +0 -3
- /together/{abstract → lib/cli}/__init__.py +0 -0
- /together/{cli → lib/cli/api}/__init__.py +0 -0
- /together/{cli/api/__init__.py → py.typed} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import pathlib
|
|
3
|
+
from typing import Any, Dict, List, get_args
|
|
3
4
|
from textwrap import wrap
|
|
4
5
|
|
|
5
6
|
import click
|
|
@@ -7,7 +8,9 @@ from tabulate import tabulate
|
|
|
7
8
|
|
|
8
9
|
from together import Together
|
|
9
10
|
from together.types import FilePurpose
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
# from together.utils import check_file, convert_bytes, convert_unix_timestamp
|
|
13
|
+
from ...utils import check_file, convert_bytes, convert_unix_timestamp
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
@click.group()
|
|
@@ -21,15 +24,13 @@ def files(ctx: click.Context) -> None:
|
|
|
21
24
|
@click.pass_context
|
|
22
25
|
@click.argument(
|
|
23
26
|
"file",
|
|
24
|
-
type=click.Path(
|
|
25
|
-
exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False
|
|
26
|
-
),
|
|
27
|
+
type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
|
|
27
28
|
required=True,
|
|
28
29
|
)
|
|
29
30
|
@click.option(
|
|
30
31
|
"--purpose",
|
|
31
|
-
type=
|
|
32
|
-
default=
|
|
32
|
+
type=click.Choice(get_args(FilePurpose)),
|
|
33
|
+
default="fine-tune",
|
|
33
34
|
help="Purpose of file upload. Acceptable values in enum `together.types.FilePurpose`. Defaults to `fine-tunes`.",
|
|
34
35
|
)
|
|
35
36
|
@click.option(
|
|
@@ -37,7 +38,7 @@ def files(ctx: click.Context) -> None:
|
|
|
37
38
|
default=True,
|
|
38
39
|
help="Whether to check the file before uploading.",
|
|
39
40
|
)
|
|
40
|
-
def upload(ctx: click.Context, file: pathlib.Path, purpose:
|
|
41
|
+
def upload(ctx: click.Context, file: pathlib.Path, purpose: FilePurpose, check: bool) -> None:
|
|
41
42
|
"""Upload file"""
|
|
42
43
|
|
|
43
44
|
client: Together = ctx.obj
|
|
@@ -55,15 +56,13 @@ def list(ctx: click.Context) -> None:
|
|
|
55
56
|
|
|
56
57
|
response = client.files.list()
|
|
57
58
|
|
|
58
|
-
display_list = []
|
|
59
|
+
display_list: List[Dict[str, Any]] = []
|
|
59
60
|
for i in response.data or []:
|
|
60
61
|
display_list.append(
|
|
61
62
|
{
|
|
62
63
|
"File name": "\n".join(wrap(i.filename or "", width=30)),
|
|
63
64
|
"File ID": i.id,
|
|
64
|
-
"Size": convert_bytes(
|
|
65
|
-
float(str(i.bytes))
|
|
66
|
-
), # convert to string for mypy typing
|
|
65
|
+
"Size": convert_bytes(float(str(i.bytes))), # convert to string for mypy typing
|
|
67
66
|
"Created At": convert_unix_timestamp(i.created_at or 0),
|
|
68
67
|
"Line Count": i.line_count,
|
|
69
68
|
}
|
|
@@ -95,9 +94,15 @@ def retrieve_content(ctx: click.Context, id: str, output: str) -> None:
|
|
|
95
94
|
|
|
96
95
|
client: Together = ctx.obj
|
|
97
96
|
|
|
98
|
-
response = client.files.
|
|
97
|
+
response = client.files.content(id=id)
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
if output:
|
|
100
|
+
with open(output, "wb") as f:
|
|
101
|
+
f.write(response.read())
|
|
102
|
+
click.echo(f"File saved to {output}")
|
|
103
|
+
|
|
104
|
+
else:
|
|
105
|
+
click.echo(response.read().decode("utf-8"))
|
|
101
106
|
|
|
102
107
|
|
|
103
108
|
@files.command()
|
|
@@ -117,12 +122,10 @@ def delete(ctx: click.Context, id: str) -> None:
|
|
|
117
122
|
@click.pass_context
|
|
118
123
|
@click.argument(
|
|
119
124
|
"file",
|
|
120
|
-
type=click.Path(
|
|
121
|
-
exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False
|
|
122
|
-
),
|
|
125
|
+
type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
|
|
123
126
|
required=True,
|
|
124
127
|
)
|
|
125
|
-
def check(
|
|
128
|
+
def check(_ctx: click.Context, file: pathlib.Path) -> None:
|
|
126
129
|
"""Check file for issues"""
|
|
127
130
|
|
|
128
131
|
report = check_file(file)
|
|
@@ -1,54 +1,37 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
import json
|
|
5
|
+
from typing import Any, Dict, List, Union, Literal
|
|
6
|
+
from pathlib import Path
|
|
4
7
|
from datetime import datetime, timezone
|
|
5
8
|
from textwrap import wrap
|
|
6
|
-
from typing import Any, Literal
|
|
7
9
|
|
|
8
10
|
import click
|
|
9
|
-
from click.core import ParameterSource # type: ignore[attr-defined]
|
|
10
11
|
from rich import print as rprint
|
|
11
|
-
from rich.json import JSON
|
|
12
12
|
from tabulate import tabulate
|
|
13
|
+
from click.core import ParameterSource # type: ignore[attr-defined]
|
|
13
14
|
|
|
14
15
|
from together import Together
|
|
15
|
-
from together.
|
|
16
|
-
from together.
|
|
17
|
-
from together.utils import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
from together._types import NOT_GIVEN, NotGiven
|
|
17
|
+
from together.lib.utils import log_warn
|
|
18
|
+
from together.lib.utils.tools import format_timestamp, finetune_price_to_dollars
|
|
19
|
+
from together.lib.cli.api.utils import INT_WITH_MAX, BOOL_WITH_AUTO
|
|
20
|
+
from together.lib.resources.files import DownloadManager
|
|
21
|
+
from together.lib.utils.serializer import datetime_serializer
|
|
22
|
+
from together.types.finetune_response import TrainingTypeFullTrainingType, TrainingTypeLoRaTrainingType
|
|
23
|
+
from together.lib.resources.fine_tuning import get_model_limits
|
|
24
24
|
|
|
25
25
|
_CONFIRMATION_MESSAGE = (
|
|
26
26
|
"You are about to create a fine-tuning job. "
|
|
27
|
-
"The
|
|
28
|
-
"The actual cost of your job will be determined by the model size, the number of tokens "
|
|
27
|
+
"The cost of your job will be determined by the model size, the number of tokens "
|
|
29
28
|
"in the training file, the number of tokens in the validation file, the number of epochs, and "
|
|
30
|
-
"the number of evaluations. Visit https://www.together.ai/pricing to
|
|
31
|
-
"{warning}"
|
|
29
|
+
"the number of evaluations. Visit https://www.together.ai/pricing to get a price estimate.\n"
|
|
32
30
|
"You can pass `-y` or `--confirm` to your command to skip this message.\n\n"
|
|
33
31
|
"Do you want to proceed?"
|
|
34
32
|
)
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
"The estimated price of this job is significantly greater than your current credit limit and balance combined. "
|
|
38
|
-
"It will likely get cancelled due to insufficient funds. "
|
|
39
|
-
"Consider increasing your credit limit at https://api.together.xyz/settings/profile\n"
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class DownloadCheckpointTypeChoice(click.Choice):
|
|
44
|
-
def __init__(self) -> None:
|
|
45
|
-
super().__init__([ct.value for ct in DownloadCheckpointType])
|
|
46
|
-
|
|
47
|
-
def convert(
|
|
48
|
-
self, value: str, param: click.Parameter | None, ctx: click.Context | None
|
|
49
|
-
) -> DownloadCheckpointType:
|
|
50
|
-
value = super().convert(value, param, ctx)
|
|
51
|
-
return DownloadCheckpointType(value)
|
|
34
|
+
_FT_JOB_WITH_STEP_REGEX = r"^ft-[\dabcdef-]+:\d+$"
|
|
52
35
|
|
|
53
36
|
|
|
54
37
|
@click.group(name="fine-tuning")
|
|
@@ -68,19 +51,11 @@ def fine_tuning(ctx: click.Context) -> None:
|
|
|
68
51
|
help="Training file ID from Files API",
|
|
69
52
|
)
|
|
70
53
|
@click.option("--model", "-m", type=str, help="Base model name")
|
|
71
|
-
@click.option(
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
@click.option(
|
|
75
|
-
"--validation-file", type=str, default="", help="Validation file ID from Files API"
|
|
76
|
-
)
|
|
54
|
+
@click.option("--n-epochs", "-ne", type=int, default=1, help="Number of epochs to train for")
|
|
55
|
+
@click.option("--validation-file", type=str, default="", help="Validation file ID from Files API")
|
|
77
56
|
@click.option("--n-evals", type=int, default=0, help="Number of evaluation loops")
|
|
78
|
-
@click.option(
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
@click.option(
|
|
82
|
-
"--batch-size", "-b", type=INT_WITH_MAX, default="max", help="Train batch size"
|
|
83
|
-
)
|
|
57
|
+
@click.option("--n-checkpoints", "-c", type=int, default=1, help="Number of checkpoints to save")
|
|
58
|
+
@click.option("--batch-size", "-b", type=INT_WITH_MAX, default="max", help="Train batch size")
|
|
84
59
|
@click.option("--learning-rate", "-lr", type=float, default=1e-5, help="Learning rate")
|
|
85
60
|
@click.option(
|
|
86
61
|
"--lr-scheduler-type",
|
|
@@ -149,18 +124,14 @@ def fine_tuning(ctx: click.Context) -> None:
|
|
|
149
124
|
"--dpo-normalize-logratios-by-length",
|
|
150
125
|
type=bool,
|
|
151
126
|
default=False,
|
|
152
|
-
help=(
|
|
153
|
-
"Whether to normalize logratios by sample length "
|
|
154
|
-
"(only used when '--training-method' is 'dpo')"
|
|
155
|
-
),
|
|
127
|
+
help=("Whether to normalize logratios by sample length (only used when '--training-method' is 'dpo')"),
|
|
156
128
|
)
|
|
157
129
|
@click.option(
|
|
158
130
|
"--rpo-alpha",
|
|
159
131
|
type=float,
|
|
160
132
|
default=None,
|
|
161
133
|
help=(
|
|
162
|
-
"RPO alpha parameter of DPO training to include NLL in the loss "
|
|
163
|
-
"(only used when '--training-method' is 'dpo')"
|
|
134
|
+
"RPO alpha parameter of DPO training to include NLL in the loss (only used when '--training-method' is 'dpo')"
|
|
164
135
|
),
|
|
165
136
|
)
|
|
166
137
|
@click.option(
|
|
@@ -195,12 +166,6 @@ def fine_tuning(ctx: click.Context) -> None:
|
|
|
195
166
|
help="Whether to mask the user messages in conversational data or prompts in instruction data. "
|
|
196
167
|
"`auto` will automatically determine whether to mask the inputs based on the data format.",
|
|
197
168
|
)
|
|
198
|
-
@click.option(
|
|
199
|
-
"--train-vision",
|
|
200
|
-
type=bool,
|
|
201
|
-
default=False,
|
|
202
|
-
help="Whether to train the vision encoder. Only supported for multimodal models.",
|
|
203
|
-
)
|
|
204
169
|
@click.option(
|
|
205
170
|
"--from-checkpoint",
|
|
206
171
|
type=str,
|
|
@@ -239,7 +204,7 @@ def create(
|
|
|
239
204
|
ctx: click.Context,
|
|
240
205
|
training_file: str,
|
|
241
206
|
validation_file: str,
|
|
242
|
-
model: str,
|
|
207
|
+
model: str | None,
|
|
243
208
|
n_epochs: int,
|
|
244
209
|
n_evals: int,
|
|
245
210
|
n_checkpoints: int,
|
|
@@ -251,27 +216,26 @@ def create(
|
|
|
251
216
|
warmup_ratio: float,
|
|
252
217
|
max_grad_norm: float,
|
|
253
218
|
weight_decay: float,
|
|
254
|
-
lora: bool,
|
|
255
|
-
lora_r: int,
|
|
256
|
-
lora_dropout: float,
|
|
257
|
-
lora_alpha: float,
|
|
258
|
-
lora_trainable_modules: str,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
training_method: str,
|
|
219
|
+
lora: bool | None,
|
|
220
|
+
lora_r: int | None,
|
|
221
|
+
lora_dropout: float | None,
|
|
222
|
+
lora_alpha: float | None,
|
|
223
|
+
lora_trainable_modules: str | None,
|
|
224
|
+
suffix: str | None,
|
|
225
|
+
wandb_api_key: str | None,
|
|
226
|
+
wandb_base_url: str | None,
|
|
227
|
+
wandb_project_name: str | None,
|
|
228
|
+
wandb_name: str | None,
|
|
229
|
+
confirm: bool | None,
|
|
230
|
+
train_on_inputs: bool | Literal["auto"] | None,
|
|
231
|
+
training_method: str | None,
|
|
268
232
|
dpo_beta: float | None,
|
|
269
|
-
dpo_normalize_logratios_by_length: bool,
|
|
233
|
+
dpo_normalize_logratios_by_length: bool | None,
|
|
270
234
|
rpo_alpha: float | None,
|
|
271
235
|
simpo_gamma: float | None,
|
|
272
|
-
from_checkpoint: str,
|
|
273
|
-
from_hf_model: str,
|
|
274
|
-
hf_model_revision: str,
|
|
236
|
+
from_checkpoint: str | None,
|
|
237
|
+
from_hf_model: str | None,
|
|
238
|
+
hf_model_revision: str | None,
|
|
275
239
|
hf_api_token: str | None,
|
|
276
240
|
hf_output_repo_name: str | None,
|
|
277
241
|
) -> None:
|
|
@@ -298,7 +262,6 @@ def create(
|
|
|
298
262
|
lora_dropout=lora_dropout,
|
|
299
263
|
lora_alpha=lora_alpha,
|
|
300
264
|
lora_trainable_modules=lora_trainable_modules,
|
|
301
|
-
train_vision=train_vision,
|
|
302
265
|
suffix=suffix,
|
|
303
266
|
wandb_api_key=wandb_api_key,
|
|
304
267
|
wandb_base_url=wandb_base_url,
|
|
@@ -324,15 +287,11 @@ def create(
|
|
|
324
287
|
if from_checkpoint is not None:
|
|
325
288
|
model_name = from_checkpoint.split(":")[0]
|
|
326
289
|
|
|
327
|
-
model_limits
|
|
328
|
-
model=model_name,
|
|
329
|
-
)
|
|
290
|
+
model_limits = get_model_limits(client, str(model_name))
|
|
330
291
|
|
|
331
292
|
if lora:
|
|
332
293
|
if model_limits.lora_training is None:
|
|
333
|
-
raise click.BadParameter(
|
|
334
|
-
f"LoRA fine-tuning is not supported for the model `{model}`"
|
|
335
|
-
)
|
|
294
|
+
raise click.BadParameter(f"LoRA fine-tuning is not supported for the model `{model}`")
|
|
336
295
|
default_values = {
|
|
337
296
|
"lora_r": model_limits.lora_training.max_rank,
|
|
338
297
|
"learning_rate": 1e-3,
|
|
@@ -341,15 +300,13 @@ def create(
|
|
|
341
300
|
for arg in default_values:
|
|
342
301
|
arg_source = ctx.get_parameter_source("arg") # type: ignore[attr-defined]
|
|
343
302
|
if arg_source == ParameterSource.DEFAULT:
|
|
344
|
-
training_args[arg] = default_values[arg_source]
|
|
303
|
+
training_args[arg] = default_values[str(arg_source)]
|
|
345
304
|
|
|
346
305
|
if ctx.get_parameter_source("lora_alpha") == ParameterSource.DEFAULT: # type: ignore[attr-defined]
|
|
347
306
|
training_args["lora_alpha"] = training_args["lora_r"] * 2
|
|
348
307
|
else:
|
|
349
308
|
if model_limits.full_training is None:
|
|
350
|
-
raise click.BadParameter(
|
|
351
|
-
f"Full fine-tuning is not supported for the model `{model}`"
|
|
352
|
-
)
|
|
309
|
+
raise click.BadParameter(f"Full fine-tuning is not supported for the model `{model}`")
|
|
353
310
|
|
|
354
311
|
for param in ["lora_r", "lora_dropout", "lora_alpha", "lora_trainable_modules"]:
|
|
355
312
|
param_source = ctx.get_parameter_source(param) # type: ignore[attr-defined]
|
|
@@ -364,52 +321,18 @@ def create(
|
|
|
364
321
|
"Warning: You have specified a validation file but the number of evaluation loops is set to 0. No evaluations will be performed."
|
|
365
322
|
)
|
|
366
323
|
elif n_evals > 0 and not validation_file:
|
|
367
|
-
raise click.BadParameter(
|
|
368
|
-
"You have specified a number of evaluation loops but no validation file."
|
|
369
|
-
)
|
|
324
|
+
raise click.BadParameter("You have specified a number of evaluation loops but no validation file.")
|
|
370
325
|
|
|
371
|
-
if
|
|
372
|
-
# Don't show price estimation for multimodal models yet
|
|
373
|
-
confirm = True
|
|
374
|
-
|
|
375
|
-
finetune_price_estimation_result = client.fine_tuning.estimate_price(
|
|
376
|
-
training_file=training_file,
|
|
377
|
-
validation_file=validation_file,
|
|
378
|
-
model=model,
|
|
379
|
-
n_epochs=n_epochs,
|
|
380
|
-
n_evals=n_evals,
|
|
381
|
-
training_type="lora" if lora else "full",
|
|
382
|
-
training_method=training_method,
|
|
383
|
-
)
|
|
384
|
-
|
|
385
|
-
price = click.style(
|
|
386
|
-
f"${finetune_price_estimation_result.estimated_total_price:.2f}",
|
|
387
|
-
bold=True,
|
|
388
|
-
)
|
|
389
|
-
|
|
390
|
-
if not finetune_price_estimation_result.allowed_to_proceed:
|
|
391
|
-
warning = click.style(_WARNING_MESSAGE_INSUFFICIENT_FUNDS, fg="red", bold=True)
|
|
392
|
-
else:
|
|
393
|
-
warning = ""
|
|
394
|
-
|
|
395
|
-
confirmation_message = _CONFIRMATION_MESSAGE.format(
|
|
396
|
-
price=price,
|
|
397
|
-
warning=warning,
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
if confirm or click.confirm(confirmation_message, default=True, show_default=True):
|
|
326
|
+
if confirm or click.confirm(_CONFIRMATION_MESSAGE, default=True, show_default=True):
|
|
401
327
|
response = client.fine_tuning.create(
|
|
402
328
|
**training_args,
|
|
403
329
|
verbose=True,
|
|
404
330
|
)
|
|
331
|
+
|
|
405
332
|
report_string = f"Successfully submitted a fine-tuning job {response.id}"
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
)
|
|
410
|
-
# created_at reports UTC time, we use .astimezone() to convert to local time
|
|
411
|
-
formatted_time = created_time.astimezone().strftime("%m/%d/%Y, %H:%M:%S")
|
|
412
|
-
report_string += f" at {formatted_time}"
|
|
333
|
+
# created_at reports UTC time, we use .astimezone() to convert to local time
|
|
334
|
+
formatted_time = response.created_at.astimezone().strftime("%m/%d/%Y, %H:%M:%S")
|
|
335
|
+
report_string += f" at {formatted_time}"
|
|
413
336
|
rprint(report_string)
|
|
414
337
|
else:
|
|
415
338
|
click.echo("No confirmation received, stopping job launch")
|
|
@@ -427,22 +350,19 @@ def list(ctx: click.Context) -> None:
|
|
|
427
350
|
|
|
428
351
|
# Use a default datetime for None values to make sure the key function always returns a comparable value
|
|
429
352
|
epoch_start = datetime.fromtimestamp(0, tz=timezone.utc)
|
|
430
|
-
response.data.sort(key=lambda x:
|
|
353
|
+
response.data.sort(key=lambda x: x.created_at or epoch_start)
|
|
431
354
|
|
|
432
|
-
display_list = []
|
|
355
|
+
display_list: List[Dict[str, Any]] = []
|
|
433
356
|
for i in response.data:
|
|
434
357
|
display_list.append(
|
|
435
358
|
{
|
|
436
359
|
"Fine-tune ID": i.id,
|
|
437
|
-
"Model Output Name": "\n".join(wrap(i.
|
|
360
|
+
"Model Output Name": "\n".join(wrap(i.x_model_output_name or "", width=30)),
|
|
438
361
|
"Status": i.status,
|
|
439
362
|
"Created At": i.created_at,
|
|
440
363
|
"Price": f"""${
|
|
441
364
|
finetune_price_to_dollars(float(str(i.total_price)))
|
|
442
365
|
}""", # convert to string for mypy typing
|
|
443
|
-
"Progress": generate_progress_bar(
|
|
444
|
-
i, datetime.now().astimezone(), use_rich=False
|
|
445
|
-
),
|
|
446
366
|
}
|
|
447
367
|
)
|
|
448
368
|
table = tabulate(display_list, headers="keys", tablefmt="grid", showindex=True)
|
|
@@ -462,23 +382,13 @@ def retrieve(ctx: click.Context, fine_tune_id: str) -> None:
|
|
|
462
382
|
# remove events from response for cleaner output
|
|
463
383
|
response.events = None
|
|
464
384
|
|
|
465
|
-
|
|
466
|
-
progress_text = generate_progress_bar(
|
|
467
|
-
response, datetime.now().astimezone(), use_rich=True
|
|
468
|
-
)
|
|
469
|
-
status = "Unknown"
|
|
470
|
-
if response.status is not None:
|
|
471
|
-
status = response.status.value
|
|
472
|
-
prefix = f"Status: [bold]{status}[/bold],"
|
|
473
|
-
rprint(f"{prefix} {progress_text}")
|
|
385
|
+
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
474
386
|
|
|
475
387
|
|
|
476
388
|
@fine_tuning.command()
|
|
477
389
|
@click.pass_context
|
|
478
390
|
@click.argument("fine_tune_id", type=str, required=True)
|
|
479
|
-
@click.option(
|
|
480
|
-
"--quiet", is_flag=True, help="Do not prompt for confirmation before cancelling job"
|
|
481
|
-
)
|
|
391
|
+
@click.option("--quiet", is_flag=True, help="Do not prompt for confirmation before cancelling job")
|
|
482
392
|
def cancel(ctx: click.Context, fine_tune_id: str, quiet: bool = False) -> None:
|
|
483
393
|
"""Cancel fine-tuning job"""
|
|
484
394
|
client: Together = ctx.obj
|
|
@@ -492,7 +402,7 @@ def cancel(ctx: click.Context, fine_tune_id: str, quiet: bool = False) -> None:
|
|
|
492
402
|
return
|
|
493
403
|
response = client.fine_tuning.cancel(fine_tune_id)
|
|
494
404
|
|
|
495
|
-
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
405
|
+
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4, default=datetime_serializer))
|
|
496
406
|
|
|
497
407
|
|
|
498
408
|
@fine_tuning.command()
|
|
@@ -506,13 +416,13 @@ def list_events(ctx: click.Context, fine_tune_id: str) -> None:
|
|
|
506
416
|
|
|
507
417
|
response.data = response.data or []
|
|
508
418
|
|
|
509
|
-
display_list = []
|
|
419
|
+
display_list: List[Dict[str, Any]] = []
|
|
510
420
|
for i in response.data:
|
|
511
421
|
display_list.append(
|
|
512
422
|
{
|
|
513
423
|
"Message": "\n".join(wrap(i.message or "", width=50)),
|
|
514
424
|
"Type": i.type,
|
|
515
|
-
"Created At":
|
|
425
|
+
"Created At": i.created_at,
|
|
516
426
|
"Hash": i.hash,
|
|
517
427
|
}
|
|
518
428
|
)
|
|
@@ -530,13 +440,18 @@ def list_checkpoints(ctx: click.Context, fine_tune_id: str) -> None:
|
|
|
530
440
|
|
|
531
441
|
checkpoints = client.fine_tuning.list_checkpoints(fine_tune_id)
|
|
532
442
|
|
|
533
|
-
display_list = []
|
|
534
|
-
for checkpoint in checkpoints:
|
|
443
|
+
display_list: List[Dict[str, Any]] = []
|
|
444
|
+
for checkpoint in checkpoints.data:
|
|
445
|
+
name = (
|
|
446
|
+
f"{fine_tune_id}:{checkpoint.step}"
|
|
447
|
+
if "intermediate" in checkpoint.checkpoint_type.lower()
|
|
448
|
+
else fine_tune_id
|
|
449
|
+
)
|
|
535
450
|
display_list.append(
|
|
536
451
|
{
|
|
537
|
-
"Type": checkpoint.
|
|
538
|
-
"Timestamp": format_timestamp(checkpoint.
|
|
539
|
-
"Name":
|
|
452
|
+
"Type": checkpoint.checkpoint_type,
|
|
453
|
+
"Timestamp": format_timestamp(checkpoint.created_at),
|
|
454
|
+
"Name": name,
|
|
540
455
|
}
|
|
541
456
|
)
|
|
542
457
|
|
|
@@ -549,7 +464,7 @@ def list_checkpoints(ctx: click.Context, fine_tune_id: str) -> None:
|
|
|
549
464
|
click.echo(f"No checkpoints found for job {fine_tune_id}")
|
|
550
465
|
|
|
551
466
|
|
|
552
|
-
@fine_tuning.command()
|
|
467
|
+
@fine_tuning.command(name="download")
|
|
553
468
|
@click.pass_context
|
|
554
469
|
@click.argument("fine_tune_id", type=str, required=True)
|
|
555
470
|
@click.option(
|
|
@@ -570,48 +485,77 @@ def list_checkpoints(ctx: click.Context, fine_tune_id: str) -> None:
|
|
|
570
485
|
)
|
|
571
486
|
@click.option(
|
|
572
487
|
"--checkpoint-type",
|
|
573
|
-
type=
|
|
488
|
+
type=click.Choice(["merged", "adapter", "default"]),
|
|
574
489
|
required=False,
|
|
575
|
-
default=
|
|
490
|
+
default="merged",
|
|
576
491
|
help="Specifies checkpoint type. 'merged' and 'adapter' options work only for LoRA jobs.",
|
|
577
492
|
)
|
|
578
493
|
def download(
|
|
579
494
|
ctx: click.Context,
|
|
580
495
|
fine_tune_id: str,
|
|
581
|
-
output_dir: str,
|
|
582
|
-
checkpoint_step: int
|
|
583
|
-
checkpoint_type:
|
|
496
|
+
output_dir: str | None = None,
|
|
497
|
+
checkpoint_step: Union[int, NotGiven] = NOT_GIVEN,
|
|
498
|
+
checkpoint_type: Literal["default", "merged", "adapter"] | NotGiven = NOT_GIVEN,
|
|
584
499
|
) -> None:
|
|
585
500
|
"""Download fine-tuning checkpoint"""
|
|
586
501
|
client: Together = ctx.obj
|
|
587
502
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
503
|
+
if re.match(_FT_JOB_WITH_STEP_REGEX, fine_tune_id) is not None:
|
|
504
|
+
if checkpoint_step is NOT_GIVEN:
|
|
505
|
+
checkpoint_step = int(fine_tune_id.split(":")[1])
|
|
506
|
+
fine_tune_id = fine_tune_id.split(":")[0]
|
|
507
|
+
else:
|
|
508
|
+
raise ValueError(
|
|
509
|
+
"Fine-tuning job ID {fine_tune_id} contains a colon to specify the step to download, but `checkpoint_step` "
|
|
510
|
+
"was also set. Remove one of the step specifiers to proceed."
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
ft_job = client.fine_tuning.retrieve(fine_tune_id)
|
|
514
|
+
|
|
515
|
+
loosely_typed_checkpoint_type: str | NotGiven = checkpoint_type
|
|
516
|
+
if isinstance(ft_job.training_type, TrainingTypeFullTrainingType):
|
|
517
|
+
if checkpoint_type != "default":
|
|
518
|
+
raise ValueError("Only DEFAULT checkpoint type is allowed for FullTrainingType")
|
|
519
|
+
loosely_typed_checkpoint_type = "model_output_path"
|
|
520
|
+
elif isinstance(ft_job.training_type, TrainingTypeLoRaTrainingType):
|
|
521
|
+
if checkpoint_type == "default":
|
|
522
|
+
loosely_typed_checkpoint_type = "merged"
|
|
523
|
+
|
|
524
|
+
if checkpoint_type not in {
|
|
525
|
+
"merged",
|
|
526
|
+
"adapter",
|
|
527
|
+
}:
|
|
528
|
+
raise ValueError(f"Invalid checkpoint type for LoRATrainingType: {checkpoint_type}")
|
|
529
|
+
|
|
530
|
+
remote_name = ft_job.x_model_output_name
|
|
531
|
+
|
|
532
|
+
url = f"/finetune/download?ft_id={fine_tune_id}&checkpoint={loosely_typed_checkpoint_type}"
|
|
533
|
+
output: Path | None = None
|
|
534
|
+
if isinstance(output_dir, str):
|
|
535
|
+
output = Path(output_dir)
|
|
536
|
+
|
|
537
|
+
file_path, file_size = DownloadManager(client).download(
|
|
538
|
+
url=url,
|
|
539
|
+
output=output,
|
|
540
|
+
remote_name=remote_name,
|
|
541
|
+
fetch_metadata=True,
|
|
593
542
|
)
|
|
594
543
|
|
|
595
|
-
click.echo(json.dumps(
|
|
544
|
+
click.echo(json.dumps({"object": "local", "id": fine_tune_id, "filename": file_path, "size": file_size}, indent=4))
|
|
596
545
|
|
|
597
546
|
|
|
598
547
|
@fine_tuning.command()
|
|
599
548
|
@click.pass_context
|
|
600
549
|
@click.argument("fine_tune_id", type=str, required=True)
|
|
601
550
|
@click.option("--force", is_flag=True, help="Force deletion without confirmation")
|
|
602
|
-
@click.option(
|
|
603
|
-
|
|
604
|
-
)
|
|
605
|
-
def delete(
|
|
606
|
-
ctx: click.Context, fine_tune_id: str, force: bool = False, quiet: bool = False
|
|
607
|
-
) -> None:
|
|
551
|
+
@click.option("--quiet", is_flag=True, help="Do not prompt for confirmation before deleting job")
|
|
552
|
+
def delete(ctx: click.Context, fine_tune_id: str, force: bool = False, quiet: bool = False) -> None:
|
|
608
553
|
"""Delete fine-tuning job"""
|
|
609
554
|
client: Together = ctx.obj
|
|
610
555
|
|
|
611
556
|
if not quiet:
|
|
612
557
|
confirm_response = input(
|
|
613
|
-
f"Are you sure you want to delete fine-tuning job {fine_tune_id}? "
|
|
614
|
-
"This action cannot be undone. [y/N] "
|
|
558
|
+
f"Are you sure you want to delete fine-tuning job {fine_tune_id}? This action cannot be undone. [y/N] "
|
|
615
559
|
)
|
|
616
560
|
if confirm_response.lower() != "y":
|
|
617
561
|
click.echo("Deletion cancelled")
|