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 typing import List, Optional, Tuple, Union

import attrs
import requests

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,
DEFAULT_CREDENTIALS_PATH, Licenses,
ModelVisibility)
from modelscope.hub.deploy import (DeleteServiceParameters,
DeployServiceParameters,
GetServiceParameters, ListServiceParameters,
ServiceParameters, ServiceResourceConfig,
Vendor)
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_response, is_ok, raise_on_error)
from modelscope.hub.git import GitCommandWrapper
@@ -306,6 +312,169 @@ class HubApi:
r.raise_for_status()
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,
use_cookies: Union[bool,
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()


class NotSupportError(Exception):
pass


class NotExistError(Exception):
pass

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




+ 1
- 0
requirements/framework.txt View File

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


Loading…
Cancel
Save