mulin.lyh yingda.chen 3 years ago
parent
commit
7257f6c6fb
4 changed files with 366 additions and 2 deletions
  1. +171
    -2
      modelscope/hub/api.py
  2. +189
    -0
      modelscope/hub/deploy.py
  3. +5
    -0
      modelscope/hub/errors.py
  4. +1
    -0
      requirements/framework.txt

+ 171
- 2
modelscope/hub/api.py View File

@@ -12,6 +12,7 @@ from http.cookiejar import CookieJar
from os.path import expanduser from os.path import expanduser
from typing import List, Optional, Tuple, Union from typing import List, Optional, Tuple, Union


import attrs
import requests import requests


from modelscope.hub.constants import (API_RESPONSE_FIELD_DATA, from modelscope.hub.constants import (API_RESPONSE_FIELD_DATA,
@@ -21,9 +22,14 @@ from modelscope.hub.constants import (API_RESPONSE_FIELD_DATA,
API_RESPONSE_FIELD_USERNAME, API_RESPONSE_FIELD_USERNAME,
DEFAULT_CREDENTIALS_PATH, Licenses, DEFAULT_CREDENTIALS_PATH, Licenses,
ModelVisibility) ModelVisibility)
from modelscope.hub.deploy import (DeleteServiceParameters,
DeployServiceParameters,
GetServiceParameters, ListServiceParameters,
ServiceParameters, ServiceResourceConfig,
Vendor)
from modelscope.hub.errors import (InvalidParameter, NotExistError, from modelscope.hub.errors import (InvalidParameter, NotExistError,
NotLoginException, RequestError,
datahub_raise_on_error,
NotLoginException, NotSupportError,
RequestError, datahub_raise_on_error,
handle_http_post_error, handle_http_post_error,
handle_http_response, is_ok, raise_on_error) handle_http_response, is_ok, raise_on_error)
from modelscope.hub.git import GitCommandWrapper from modelscope.hub.git import GitCommandWrapper
@@ -306,6 +312,169 @@ class HubApi:
r.raise_for_status() r.raise_for_status()
return None return None


def deploy_model(self, model_id: str, revision: str, instance_name: str,
resource: ServiceResourceConfig,
provider: ServiceParameters):
"""Deploy model to cloud, current we only support PAI EAS, this is asynchronous
call , please check instance status through the console or query the instance status.
At the same time, this call may take a long time.

Args:
model_id (str): The deployed model id
revision (str): The model revision
instance_name (str): The deployed model instance name.
resource (DeployResource): The resource information.
provider (CreateParameter): The cloud service provider parameter

Raises:
NotLoginException: To use this api, you need login first.
NotSupportError: Not supported platform.
RequestError: The server return error.

Returns:
InstanceInfo: The instance information.
"""
cookies = ModelScopeConfig.get_cookies()
if cookies is None:
raise NotLoginException(
'Token does not exist, please login first.')
if provider.vendor != Vendor.EAS:
raise NotSupportError(
'Not support vendor: %s ,only support EAS current.' %
(provider.vendor))
create_params = DeployServiceParameters(
instance_name=instance_name,
model_id=model_id,
revision=revision,
resource=resource,
provider=provider)
path = f'{self.endpoint}/api/v1/deployer/endpoint'
body = attrs.asdict(create_params)
r = requests.post(
path,
json=body,
cookies=cookies,
)
handle_http_response(r, logger, cookies, 'create_eas_instance')
if r.status_code >= HTTPStatus.OK and r.status_code < HTTPStatus.MULTIPLE_CHOICES:
if is_ok(r.json()):
data = r.json()[API_RESPONSE_FIELD_DATA]
return data
else:
raise RequestError(r.json()[API_RESPONSE_FIELD_MESSAGE])
else:
r.raise_for_status()
return None

def list_deployed_model_instances(self,
provider: ServiceParameters,
skip: int = 0,
limit: int = 100):
"""List deployed model instances.

Args:
provider (ListServiceParameter): The cloud service provider parameter,
for eas, need access_key_id and access_key_secret.
skip: start of the list, current not support.
limit: maximum number of instances return, current not support
Raises:
NotLoginException: To use this api, you need login first.
RequestError: The request is failed from server.

Returns:
List: List of instance information
"""
cookies = ModelScopeConfig.get_cookies()
if cookies is None:
raise NotLoginException(
'Token does not exist, please login first.')
params = ListServiceParameters(
provider=provider, skip=skip, limit=limit)
path = '%s/api/v1/deployer/endpoint?%s' % (self.endpoint,
params.to_query_str())
r = requests.get(path, cookies=cookies)
handle_http_response(r, logger, cookies, 'list_deployed_model')
if r.status_code == HTTPStatus.OK:
if is_ok(r.json()):
data = r.json()[API_RESPONSE_FIELD_DATA]
return data
else:
raise RequestError(r.json()[API_RESPONSE_FIELD_MESSAGE])
else:
r.raise_for_status()
return None

def get_deployed_model_instance(self, instance_name: str,
provider: ServiceParameters):
"""Query the specified instance information.

Args:
instance_name (str): The deployed instance name.
provider (GetParameter): The cloud provider information, for eas
need region(eg: ch-hangzhou), access_key_id and access_key_secret.

Raises:
NotLoginException: To use this api, you need login first.
RequestError: The request is failed from server.

Returns:
Dict: The request instance information
"""
cookies = ModelScopeConfig.get_cookies()
if cookies is None:
raise NotLoginException(
'Token does not exist, please login first.')
params = GetServiceParameters(provider=provider)
path = '%s/api/v1/deployer/endpoint/%s?%s' % (
self.endpoint, instance_name, params.to_query_str())
r = requests.get(path, cookies=cookies)
handle_http_response(r, logger, cookies, 'get_deployed_model')
if r.status_code == HTTPStatus.OK:
if is_ok(r.json()):
data = r.json()[API_RESPONSE_FIELD_DATA]
return data
else:
raise RequestError(r.json()[API_RESPONSE_FIELD_MESSAGE])
else:
r.raise_for_status()
return None

def delete_deployed_model_instance(self, instance_name: str,
provider: ServiceParameters):
"""Delete deployed model, this api send delete command and return, it will take
some to delete, please check through the cloud console.

Args:
instance_name (str): The instance name you want to delete.
provider (DeleteParameter): The cloud provider information, for eas
need region(eg: ch-hangzhou), access_key_id and access_key_secret.

Raises:
NotLoginException: To call this api, you need login first.
RequestError: The request is failed.

Returns:
Dict: The deleted instance information.
"""
cookies = ModelScopeConfig.get_cookies()
if cookies is None:
raise NotLoginException(
'Token does not exist, please login first.')
params = DeleteServiceParameters(provider=provider)
path = '%s/api/v1/deployer/endpoint/%s?%s' % (
self.endpoint, instance_name, params.to_query_str())
r = requests.delete(path, cookies=cookies)
handle_http_response(r, logger, cookies, 'delete_deployed_model')
if r.status_code == HTTPStatus.OK:
if is_ok(r.json()):
data = r.json()[API_RESPONSE_FIELD_DATA]
return data
else:
raise RequestError(r.json()[API_RESPONSE_FIELD_MESSAGE])
else:
r.raise_for_status()
return None

def _check_cookie(self, def _check_cookie(self,
use_cookies: Union[bool, use_cookies: Union[bool,
CookieJar] = False) -> CookieJar: CookieJar] = False) -> CookieJar:


+ 189
- 0
modelscope/hub/deploy.py View File

@@ -0,0 +1,189 @@
import urllib
from abc import ABC, abstractmethod
from typing import Optional, Union

import json
from attr import fields
from attrs import asdict, define, field, validators


class Accelerator(object):
CPU = 'cpu'
GPU = 'gpu'


class Vendor(object):
EAS = 'eas'


class EASRegion(object):
beijing = 'cn-beijing'
hangzhou = 'cn-hangzhou'


class EASCpuInstanceType(object):
"""EAS Cpu Instance TYpe, ref(https://help.aliyun.com/document_detail/144261.html)
"""
tiny = 'ecs.c6.2xlarge'
small = 'ecs.c6.4xlarge'
medium = 'ecs.c6.6xlarge'
large = 'ecs.c6.8xlarge'


class EASGpuInstanceType(object):
"""EAS Cpu Instance TYpe, ref(https://help.aliyun.com/document_detail/144261.html)
"""
tiny = 'ecs.gn5-c28g1.7xlarge'
small = 'ecs.gn5-c8g1.4xlarge'
medium = 'ecs.gn6i-c24g1.12xlarge'
large = 'ecs.gn6e-c12g1.3xlarge'


def min_smaller_than_max(instance, attribute, value):
if value > instance.max_replica:
raise ValueError(
"'min_replica' value: %s has to be smaller than 'max_replica' value: %s!"
% (value, instance.max_replica))


@define
class ServiceScalingConfig(object):
"""Resource scaling config
Currently we ignore max_replica
Args:
max_replica: maximum replica
min_replica: minimum replica
"""
max_replica: int = field(default=1, validator=validators.ge(1))
min_replica: int = field(
default=1, validator=[validators.ge(1), min_smaller_than_max])


@define
class ServiceResourceConfig(object):
"""Eas Resource request.

Args:
accelerator: the accelerator(cpu|gpu)
instance_type: the instance type.
scaling: The instance scaling config.
"""
instance_type: str
scaling: ServiceScalingConfig
accelerator: str = field(
default=Accelerator.CPU,
validator=validators.in_([Accelerator.CPU, Accelerator.GPU]))


@define
class ServiceParameters(ABC):
pass


@define
class EASDeployParameters(ServiceParameters):
"""Parameters for EAS Deployment.

Args:
resource_group: the resource group to deploy, current default.
region: The eas instance region(eg: cn-hangzhou).
access_key_id: The eas account access key id.
access_key_secret: The eas account access key secret.
vendor: must be 'eas'
"""
region: str
access_key_id: str
access_key_secret: str
resource_group: Optional[str] = None
vendor: str = field(
default=Vendor.EAS, validator=validators.in_([Vendor.EAS]))
"""
def __init__(self,
instance_name: str,
access_key_id: str,
access_key_secret: str,
region = EASRegion.beijing,
instance_type: str = EASCpuInstances.small,
accelerator: str = Accelerator.CPU,
resource_group: Optional[str] = None,
scaling: Optional[str] = None):
self.instance_name=instance_name
self.access_key_id=self.access_key_id
self.access_key_secret = access_key_secret
self.region = region
self.instance_type = instance_type
self.accelerator = accelerator
self.resource_group = resource_group
self.scaling = scaling
"""


@define
class EASListParameters(ServiceParameters):
"""EAS instance list parameters.

Args:
resource_group: the resource group to deploy, current default.
region: The eas instance region(eg: cn-hangzhou).
access_key_id: The eas account access key id.
access_key_secret: The eas account access key secret.
vendor: must be 'eas'
"""
access_key_id: str
access_key_secret: str
region: str = None
resource_group: str = None
vendor: str = field(
default=Vendor.EAS, validator=validators.in_([Vendor.EAS]))


@define
class DeployServiceParameters(object):
"""Deploy service parameters

Args:
instance_name: the name of the service.
model_id: the modelscope model_id
revision: the modelscope model revision
resource: the resource requirement.
provider: the cloud service provider.
"""
instance_name: str
model_id: str
revision: str
resource: ServiceResourceConfig
provider: ServiceParameters


class AttrsToQueryString(ABC):
"""Convert the attrs class to json string.

Args:
"""

def to_query_str(self):
self_dict = asdict(
self.provider, filter=lambda attr, value: value is not None)
json_str = json.dumps(self_dict)
print(json_str)
safe_str = urllib.parse.quote_plus(json_str)
print(safe_str)
query_param = 'provider=%s' % safe_str
return query_param


@define
class ListServiceParameters(AttrsToQueryString):
provider: ServiceParameters
skip: int = 0
limit: int = 100


@define
class GetServiceParameters(AttrsToQueryString):
provider: ServiceParameters


@define
class DeleteServiceParameters(AttrsToQueryString):
provider: ServiceParameters

+ 5
- 0
modelscope/hub/errors.py View File

@@ -9,6 +9,10 @@ from modelscope.utils.logger import get_logger
logger = get_logger() logger = get_logger()




class NotSupportError(Exception):
pass


class NotExistError(Exception): class NotExistError(Exception):
pass pass


@@ -66,6 +70,7 @@ def handle_http_response(response, logger, cookies, model_id):
logger.error( logger.error(
f'Authentication token does not exist, failed to access model {model_id} which may not exist or may be \ f'Authentication token does not exist, failed to access model {model_id} which may not exist or may be \
private. Please login first.') private. Please login first.')
logger.error('Response details: %s' % response.content)
raise error raise error






+ 1
- 0
requirements/framework.txt View File

@@ -1,4 +1,5 @@
addict addict
attrs
datasets datasets
easydict easydict
einops einops


Loading…
Cancel
Save