together 0.2.5__py3-none-any.whl → 0.2.7__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 +16 -0
- together/cli/cli.py +2 -1
- together/commands/chat.py +20 -12
- together/commands/complete.py +34 -26
- together/commands/embeddings.py +48 -0
- together/commands/files.py +75 -9
- together/commands/finetune.py +132 -117
- together/commands/image.py +14 -11
- together/commands/models.py +81 -16
- together/complete.py +2 -4
- together/embeddings.py +35 -0
- together/error.py +4 -0
- together/files.py +12 -9
- together/finetune.py +23 -48
- together/image.py +1 -2
- together/models.py +5 -10
- together/utils.py +35 -23
- together/version.py +6 -1
- {together-0.2.5.dist-info → together-0.2.7.dist-info}/METADATA +68 -225
- together-0.2.7.dist-info/RECORD +27 -0
- {together-0.2.5.dist-info → together-0.2.7.dist-info}/WHEEL +1 -1
- together-0.2.7.dist-info/entry_points.txt +3 -0
- together-0.2.5.dist-info/RECORD +0 -25
- together-0.2.5.dist-info/entry_points.txt +0 -2
- {together-0.2.5.dist-info/licenses → together-0.2.7.dist-info}/LICENSE +0 -0
together/finetune.py
CHANGED
|
@@ -4,7 +4,9 @@ import urllib.parse
|
|
|
4
4
|
from typing import Any, Dict, List, Optional, Union
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
+
from requests.adapters import HTTPAdapter
|
|
7
8
|
from tqdm import tqdm
|
|
9
|
+
from urllib3.util import Retry
|
|
8
10
|
|
|
9
11
|
import together
|
|
10
12
|
from together import Files
|
|
@@ -28,24 +30,17 @@ class Finetune:
|
|
|
28
30
|
def create(
|
|
29
31
|
self,
|
|
30
32
|
training_file: str, # training file_id
|
|
31
|
-
# validation_file: Optional[str] = None, # validation file_id
|
|
32
33
|
model: str,
|
|
33
34
|
n_epochs: int = 1,
|
|
34
35
|
n_checkpoints: Optional[int] = 1,
|
|
35
36
|
batch_size: Optional[int] = 32,
|
|
36
37
|
learning_rate: Optional[float] = 0.00001,
|
|
37
|
-
# warmup_steps: Optional[int] = 0,
|
|
38
|
-
# train_warmup_steps: Optional[int] = 0,
|
|
39
|
-
# seq_length: Optional[int] = 2048,
|
|
40
|
-
# seed: Optional[int] = 42,
|
|
41
|
-
# fp16: Optional[bool] = True,
|
|
42
|
-
# checkpoint_steps: Optional[int] = None,
|
|
43
38
|
suffix: Optional[
|
|
44
39
|
str
|
|
45
40
|
] = None, # resulting finetuned model name will include the suffix
|
|
46
41
|
estimate_price: bool = False,
|
|
47
42
|
wandb_api_key: Optional[str] = None,
|
|
48
|
-
confirm_inputs: bool =
|
|
43
|
+
confirm_inputs: bool = False,
|
|
49
44
|
) -> Dict[Any, Any]:
|
|
50
45
|
adjusted_inputs = False
|
|
51
46
|
|
|
@@ -175,24 +170,21 @@ class Finetune:
|
|
|
175
170
|
response = create_post_request(
|
|
176
171
|
together.api_base_finetune, json=parameter_payload
|
|
177
172
|
)
|
|
178
|
-
|
|
179
|
-
return {}
|
|
173
|
+
|
|
180
174
|
return response_to_dict(response)
|
|
181
175
|
|
|
182
176
|
@classmethod
|
|
183
|
-
def list(self) -> Dict[
|
|
177
|
+
def list(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
184
178
|
# send request
|
|
185
179
|
response = create_get_request(together.api_base_finetune)
|
|
186
|
-
|
|
187
|
-
return {}
|
|
180
|
+
|
|
188
181
|
return response_to_dict(response)
|
|
189
182
|
|
|
190
183
|
@classmethod
|
|
191
|
-
def retrieve(self, fine_tune_id: str) -> Dict[
|
|
184
|
+
def retrieve(self, fine_tune_id: str) -> Dict[str, Any]:
|
|
192
185
|
retrieve_url = urllib.parse.urljoin(together.api_base_finetune, fine_tune_id)
|
|
193
186
|
response = create_get_request(retrieve_url)
|
|
194
|
-
|
|
195
|
-
return {}
|
|
187
|
+
|
|
196
188
|
return response_to_dict(response)
|
|
197
189
|
|
|
198
190
|
@classmethod
|
|
@@ -200,8 +192,7 @@ class Finetune:
|
|
|
200
192
|
relative_path = posixpath.join(fine_tune_id, "cancel")
|
|
201
193
|
retrieve_url = urllib.parse.urljoin(together.api_base_finetune, relative_path)
|
|
202
194
|
response = create_post_request(retrieve_url)
|
|
203
|
-
|
|
204
|
-
return {}
|
|
195
|
+
|
|
205
196
|
return response_to_dict(response)
|
|
206
197
|
|
|
207
198
|
@classmethod
|
|
@@ -210,8 +201,7 @@ class Finetune:
|
|
|
210
201
|
relative_path = posixpath.join(fine_tune_id, "events")
|
|
211
202
|
retrieve_url = urllib.parse.urljoin(together.api_base_finetune, relative_path)
|
|
212
203
|
response = create_get_request(retrieve_url)
|
|
213
|
-
|
|
214
|
-
return {}
|
|
204
|
+
|
|
215
205
|
return response_to_dict(response)
|
|
216
206
|
|
|
217
207
|
@classmethod
|
|
@@ -274,16 +264,23 @@ class Finetune:
|
|
|
274
264
|
"User-Agent": together.user_agent,
|
|
275
265
|
}
|
|
276
266
|
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
session = requests.Session()
|
|
268
|
+
|
|
269
|
+
retry_strategy = Retry(
|
|
270
|
+
total=together.MAX_CONNECTION_RETRIES,
|
|
271
|
+
backoff_factor=together.BACKOFF_FACTOR,
|
|
272
|
+
)
|
|
273
|
+
retry_adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
274
|
+
session.mount("https://", retry_adapter)
|
|
279
275
|
|
|
276
|
+
try:
|
|
280
277
|
response = session.get(model_file_path, headers=headers, stream=True)
|
|
281
278
|
response.raise_for_status()
|
|
282
279
|
|
|
283
280
|
if output is None:
|
|
284
281
|
content_type = str(response.headers.get("content-type"))
|
|
285
282
|
|
|
286
|
-
output = self.retrieve(fine_tune_id)["
|
|
283
|
+
output = self.retrieve(fine_tune_id)["model_output_name"].split("/")[-1]
|
|
287
284
|
|
|
288
285
|
if step != -1:
|
|
289
286
|
output += f"-checkpoint-{step}"
|
|
@@ -311,30 +308,8 @@ class Finetune:
|
|
|
311
308
|
"Caution: Downloaded file size does not match remote file size."
|
|
312
309
|
)
|
|
313
310
|
except requests.exceptions.RequestException as e: # This is the correct syntax
|
|
314
|
-
logger.critical(f"Response error raised: {e}")
|
|
315
311
|
raise together.ResponseError(e)
|
|
312
|
+
finally:
|
|
313
|
+
session.close()
|
|
316
314
|
|
|
317
|
-
return output # this should be
|
|
318
|
-
|
|
319
|
-
# def delete_finetune_model(self, model: str) -> Dict[Any, Any]:
|
|
320
|
-
# model_url = "https://api.together.xyz/api/models"
|
|
321
|
-
# delete_url = urllib.parse.urljoin(model_url, model)
|
|
322
|
-
|
|
323
|
-
# headers = {
|
|
324
|
-
# "Authorization": f"Bearer {together.api_key}",
|
|
325
|
-
# }
|
|
326
|
-
|
|
327
|
-
# # send request
|
|
328
|
-
# try:
|
|
329
|
-
# response = requests.delete(delete_url, headers=headers)
|
|
330
|
-
# except requests.exceptions.RequestException as e:
|
|
331
|
-
# raise ValueError(f"Error raised by finetune endpoint: {e}")
|
|
332
|
-
|
|
333
|
-
# try:
|
|
334
|
-
# response_json = dict(response.json())
|
|
335
|
-
# except Exception as e:
|
|
336
|
-
# raise ValueError(
|
|
337
|
-
# f"JSON Error raised. \nResponse status code: {str(response.status_code)}"
|
|
338
|
-
# )
|
|
339
|
-
|
|
340
|
-
# return response_json
|
|
315
|
+
return output # this should be output file name
|
together/image.py
CHANGED
together/models.py
CHANGED
|
@@ -18,8 +18,7 @@ class Models:
|
|
|
18
18
|
def list(self) -> List[Any]:
|
|
19
19
|
model_url = urllib.parse.urljoin(together.api_base, "models/info?=")
|
|
20
20
|
response = create_get_request(model_url)
|
|
21
|
-
|
|
22
|
-
return []
|
|
21
|
+
|
|
23
22
|
try:
|
|
24
23
|
response_list = list(response.json())
|
|
25
24
|
except Exception as e:
|
|
@@ -46,8 +45,7 @@ class Models:
|
|
|
46
45
|
@classmethod
|
|
47
46
|
def instances(self) -> Dict[str, bool]:
|
|
48
47
|
response = create_get_request(together.api_base_instances)
|
|
49
|
-
|
|
50
|
-
return {}
|
|
48
|
+
|
|
51
49
|
return response_to_dict(response)
|
|
52
50
|
|
|
53
51
|
@classmethod
|
|
@@ -56,8 +54,7 @@ class Models:
|
|
|
56
54
|
together.api_base_instances, f"start?model={model}"
|
|
57
55
|
)
|
|
58
56
|
response = create_post_request(model_url)
|
|
59
|
-
|
|
60
|
-
return {}
|
|
57
|
+
|
|
61
58
|
return response_to_dict(response)
|
|
62
59
|
|
|
63
60
|
@classmethod
|
|
@@ -66,16 +63,14 @@ class Models:
|
|
|
66
63
|
together.api_base_instances, f"stop?model={model}"
|
|
67
64
|
)
|
|
68
65
|
response = create_post_request(model_url)
|
|
69
|
-
|
|
70
|
-
return {}
|
|
66
|
+
|
|
71
67
|
return response_to_dict(response)
|
|
72
68
|
|
|
73
69
|
@classmethod
|
|
74
70
|
def ready(self, model: str) -> List[Any]:
|
|
75
71
|
ready_url = urllib.parse.urljoin(together.api_base, "models/info?name=" + model)
|
|
76
72
|
response = create_get_request(ready_url)
|
|
77
|
-
|
|
78
|
-
return []
|
|
73
|
+
|
|
79
74
|
try:
|
|
80
75
|
response_list = list(response.json())
|
|
81
76
|
except Exception as e:
|
together/utils.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import sys
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Any, Dict, Optional
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
-
import sseclient
|
|
7
|
+
import sseclient
|
|
8
8
|
|
|
9
9
|
import together
|
|
10
10
|
|
|
@@ -53,19 +53,9 @@ def get_logger(
|
|
|
53
53
|
return logger
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
def verify_api_key(
|
|
57
|
-
if logger is None:
|
|
58
|
-
logger = get_logger(str(__name__), log_level=together.log_level)
|
|
56
|
+
def verify_api_key() -> None:
|
|
59
57
|
if together.api_key is None:
|
|
60
|
-
|
|
61
|
-
"TOGETHER_API_KEY not found \n"
|
|
62
|
-
"Please set it as an environment variable or set it as together.api_key \n"
|
|
63
|
-
"Find your TOGETHER_API_KEY at https://api.together.xyz/settings/api-keys"
|
|
64
|
-
)
|
|
65
|
-
print(msg)
|
|
66
|
-
return False
|
|
67
|
-
else:
|
|
68
|
-
return True
|
|
58
|
+
raise together.AuthenticationError(together.MISSING_API_KEY_MESSAGE)
|
|
69
59
|
|
|
70
60
|
|
|
71
61
|
def extract_time(json_obj: Dict[str, Any]) -> int:
|
|
@@ -91,10 +81,9 @@ def create_post_request(
|
|
|
91
81
|
json: Optional[Dict[Any, Any]] = None,
|
|
92
82
|
stream: Optional[bool] = False,
|
|
93
83
|
check_auth: Optional[bool] = True,
|
|
94
|
-
) ->
|
|
84
|
+
) -> requests.Response:
|
|
95
85
|
if check_auth:
|
|
96
|
-
|
|
97
|
-
return None
|
|
86
|
+
verify_api_key()
|
|
98
87
|
|
|
99
88
|
if not headers:
|
|
100
89
|
headers = {
|
|
@@ -110,16 +99,20 @@ def create_post_request(
|
|
|
110
99
|
raise together.ResponseError(e)
|
|
111
100
|
|
|
112
101
|
if response.status_code == 429:
|
|
113
|
-
raise together.
|
|
102
|
+
raise together.RateLimitError(
|
|
103
|
+
message="Too many requests received. Please pace your requests."
|
|
104
|
+
)
|
|
114
105
|
elif response.status_code == 500:
|
|
115
106
|
raise Exception("Invalid API key supplied.")
|
|
107
|
+
elif response.status_code == 401:
|
|
108
|
+
raise Exception("API Key not supplied")
|
|
116
109
|
response.raise_for_status()
|
|
117
110
|
|
|
118
111
|
return response
|
|
119
112
|
|
|
120
113
|
|
|
121
114
|
def sse_client(response: requests.Response) -> sseclient.SSEClient:
|
|
122
|
-
return sseclient.SSEClient(response)
|
|
115
|
+
return sseclient.SSEClient(response) # type: ignore
|
|
123
116
|
|
|
124
117
|
|
|
125
118
|
def create_get_request(
|
|
@@ -128,10 +121,9 @@ def create_get_request(
|
|
|
128
121
|
json: Optional[Dict[Any, Any]] = None,
|
|
129
122
|
stream: Optional[bool] = False,
|
|
130
123
|
check_auth: Optional[bool] = True,
|
|
131
|
-
) ->
|
|
124
|
+
) -> requests.Response:
|
|
132
125
|
if check_auth:
|
|
133
|
-
|
|
134
|
-
return None
|
|
126
|
+
verify_api_key()
|
|
135
127
|
|
|
136
128
|
if not headers:
|
|
137
129
|
headers = {
|
|
@@ -147,9 +139,13 @@ def create_get_request(
|
|
|
147
139
|
raise together.ResponseError(e)
|
|
148
140
|
|
|
149
141
|
if response.status_code == 429:
|
|
150
|
-
raise together.
|
|
142
|
+
raise together.RateLimitError(
|
|
143
|
+
message="Too many requests received. Please pace your requests."
|
|
144
|
+
)
|
|
151
145
|
elif response.status_code == 500:
|
|
152
146
|
raise Exception("Invalid API key supplied.")
|
|
147
|
+
elif response.status_code == 401:
|
|
148
|
+
raise Exception("API Key not supplied")
|
|
153
149
|
response.raise_for_status()
|
|
154
150
|
|
|
155
151
|
return response
|
|
@@ -173,3 +169,19 @@ def round_to_closest_multiple_of_32(batch_size: Optional[int]) -> int:
|
|
|
173
169
|
elif batch_size > 256:
|
|
174
170
|
return 256
|
|
175
171
|
return 32 * ((batch_size + 31) // 32)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def bytes_to_human_readable(num: float, suffix: Optional[str] = "B") -> str:
|
|
175
|
+
for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
|
|
176
|
+
if abs(num) < 1024.0:
|
|
177
|
+
return f"{num:3.1f}{unit}{suffix}"
|
|
178
|
+
num /= 1024.0
|
|
179
|
+
return f"{num:.1f}Yi{suffix}"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def finetune_price_to_dollars(price: float) -> float:
|
|
183
|
+
return price / 1000000000
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def nanodollars_to_dollars(price: int) -> float:
|
|
187
|
+
return (price * 4000) / 1000000000
|