-
Notifications
You must be signed in to change notification settings - Fork 21
feat: add price estimation #400
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/together/cli/api/finetune.py
Outdated
| "greater than your current credit limit and balance. " | ||
| "It will likely fail due to insufficient funds. " | ||
| "Please consider increasing your credit limit at https://api.together.xyz/settings/profile\n" | ||
| "You can pass `-y` or `--confirm` to your command to skip this message.\n\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also warn that a job will fail anyway? And not like execute with negative balance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdym? There's "It will likely fail due to insufficient funds" is above?
src/together/resources/finetune.py
Outdated
| Returns: | ||
| FinetunePriceEstimationResponse: Object containing the estimated price. | ||
| """ | ||
| training_type_cls: TrainingType | None = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to set them None here, as they're defined below in all branches (or exception). You can keep type definition if you want to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mypy complains
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a bit weird, all the possible branches are covered below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it complain when you don't define the type or when you don't set it to None?
src/together/types/finetune.py
Outdated
| model: str | ||
| n_epochs: int | None = None | ||
| n_evals: int | None = None | ||
| training_type: TrainingType | None = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be none? Same goes for n_epoch and n_evals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be None. If I implement it in any other way, it would be an unrelated change -- I'd just need to change it for all other data types for FT
src/together/resources/finetune.py
Outdated
| self, | ||
| *, | ||
| training_file: str, | ||
| model: str | None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these fields be none?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They can in principle, but the price estimation API doesn't seem to support it. Therefore, we need to fix the API, disable calling the estimation when model is None, but set this field to always be defined (i.e., remove the None option)
mryab
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to supplement the client changes with some simple unit tests!
src/together/resources/finetune.py
Outdated
| "It will likely fail due to insufficient funds. " | ||
| "Please proceed at your own risk." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| "It will likely fail due to insufficient funds. " | |
| "Please proceed at your own risk." | |
| "It will likely get cancelled due to insufficient funds. " | |
| "Proceed at your own risk." |
src/together/resources/finetune.py
Outdated
| Returns: | ||
| FinetunePriceEstimationResponse: Object containing the estimated price. | ||
| """ | ||
| training_type_cls: TrainingType | None = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it complain when you don't define the type or when you don't set it to None?
src/together/resources/finetune.py
Outdated
| hf_api_token=hf_api_token, | ||
| hf_output_repo_name=hf_output_repo_name, | ||
| ) | ||
| if from_checkpoint is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if from_checkpoint is None: | |
| if from_checkpoint is None and from_hf_model is None: |
I don't think you support from_hf_model either (estimated price will be incorect due to wrong parameter count)
nikita-smetanin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
src/together/resources/finetune.py
Outdated
| Estimates the price of a fine-tuning job | ||
| Args: | ||
| request (FinetunePriceEstimationRequest): Request object containing the parameters for the price estimation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring is not consistent with the actual arguments
src/together/resources/finetune.py
Outdated
| Estimates the price of a fine-tuning job | ||
| Args: | ||
| request (FinetunePriceEstimationRequest): Request object containing the parameters for the price estimation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
src/together/resources/finetune.py
Outdated
| # unsupported case | ||
| price_estimation_result = FinetunePriceEstimationResponse( | ||
| estimated_total_price=0.0, | ||
| allowed_to_proceed=True, | ||
| estimated_train_token_count=0, | ||
| estimated_eval_token_count=0, | ||
| user_limit=0.0, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I would create a separate variable price_limit_passed and assign price_limit_passed = price_estimation_result.allowed_to_proceed when there is no CFT but just price_limit_passed = True in the unsupported case. This would prevent creating a dummy object with arbitrary values across the file
| ) | ||
|
|
||
| assert mock_requestor.request.call_count == 3 | ||
| assert response.id == "ft-12345678-1234-1234-1234-1234567890ab" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's extract this into a constant perhaps? It's used 3 times across the file, might easily diverge or not get used in future tests
| else: | ||
| return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to explicitly check that it's equal to /limits (since this is what we return here) and raise ValueError if none of the options would match. A dispatch table pattern is a good option here
| mocker.return_value = ( | ||
| TogetherResponse( | ||
| data={ | ||
| "estimated_total_price": 100, | ||
| "allowed_to_proceed": True, | ||
| "estimated_train_token_count": 1000, | ||
| "estimated_eval_token_count": 100, | ||
| "user_limit": 1000, | ||
| }, | ||
| headers={}, | ||
| ), | ||
| None, | ||
| None, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, it feels weird that we can't reuse mock_request here and have to define the mocking logic once again. I wonder if we can generalize somehow…
…computer/together-python into ruslan/price-estimation
Co-authored-by: Max Ryabinin <mryabinin0@gmail.com>
Have you read the Contributing Guidelines?
Issue #
Describe your changes
This adds the price estimation functionality to the client. This also adds a warning if the estimated price is too high.