diff --git a/.github/workflows/publish-algorithm-images.yaml b/.github/workflows/publish-algorithm-images.yaml index 0f53ab8e46e..9f5479d460a 100644 --- a/.github/workflows/publish-algorithm-images.yaml +++ b/.github/workflows/publish-algorithm-images.yaml @@ -24,8 +24,6 @@ jobs: include: - component-name: suggestion-hyperopt dockerfile: cmd/suggestion/hyperopt/v1beta1/Dockerfile - - component-name: suggestion-chocolate - dockerfile: cmd/suggestion/chocolate/v1beta1/Dockerfile - component-name: suggestion-hyperband dockerfile: cmd/suggestion/hyperband/v1beta1/Dockerfile - component-name: suggestion-skopt diff --git a/Makefile b/Makefile index 68003332ff6..6b8a665f3ad 100755 --- a/Makefile +++ b/Makefile @@ -151,7 +151,6 @@ update-boilerplate: prepare-pytest: pip install -r test/unit/v1beta1/requirements.txt - pip install -r cmd/suggestion/chocolate/v1beta1/requirements.txt pip install -r cmd/suggestion/hyperopt/v1beta1/requirements.txt pip install -r cmd/suggestion/skopt/v1beta1/requirements.txt pip install -r cmd/suggestion/optuna/v1beta1/requirements.txt diff --git a/README.md b/README.md index b4e416e7c56..add2983b112 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,6 @@ custom algorithm. To perform above algorithms Katib supports the following frameworks: -- [Chocolate](https://github.com/AIworx-Labs/chocolate) - [Goptuna](https://github.com/c-bata/goptuna) - [Hyperopt](https://github.com/hyperopt/hyperopt) - [Optuna](https://github.com/optuna/optuna) diff --git a/cmd/suggestion/chocolate/v1beta1/Dockerfile b/cmd/suggestion/chocolate/v1beta1/Dockerfile deleted file mode 100644 index bff97750af4..00000000000 --- a/cmd/suggestion/chocolate/v1beta1/Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -FROM alpine:3.15 AS downloader - -ARG TARGETARCH -ENV GRPC_HEALTH_PROBE_VERSION v0.4.11 - -RUN wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-${TARGETARCH} \ - && chmod +x /bin/grpc_health_probe - -FROM python:3.9-slim - -ARG TARGETARCH -ENV TARGET_DIR /opt/katib -ENV SUGGESTION_DIR cmd/suggestion/chocolate/v1beta1 -ENV PYTHONPATH ${TARGET_DIR}:${TARGET_DIR}/pkg/apis/manager/v1beta1/python:${TARGET_DIR}/pkg/apis/manager/health/python - -RUN apt-get -y update && \ - apt-get -y install git && \ - if [ "${TARGETARCH}" = "ppc64le" ] || [ "${TARGETARCH}" = "arm64" ]; then \ - apt-get -y install gfortran libopenblas-dev liblapack-dev g++; \ - fi && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -ADD ./pkg/ ${TARGET_DIR}/pkg/ -ADD ./${SUGGESTION_DIR}/ ${TARGET_DIR}/${SUGGESTION_DIR}/ -COPY --from=downloader /bin/grpc_health_probe /bin/grpc_health_probe - -WORKDIR ${TARGET_DIR}/${SUGGESTION_DIR} - -RUN pip install --no-cache-dir -r requirements.txt -RUN chgrp -R 0 ${TARGET_DIR} \ - && chmod -R g+rwX ${TARGET_DIR} - -ENTRYPOINT ["python", "main.py"] diff --git a/cmd/suggestion/chocolate/v1beta1/main.py b/cmd/suggestion/chocolate/v1beta1/main.py deleted file mode 100644 index 37e03467769..00000000000 --- a/cmd/suggestion/chocolate/v1beta1/main.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2022 The Kubeflow Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import grpc -import time -from pkg.apis.manager.v1beta1.python import api_pb2_grpc -from pkg.apis.manager.health.python import health_pb2_grpc -from pkg.suggestion.v1beta1.chocolate.service import ChocolateService -from concurrent import futures - -_ONE_DAY_IN_SECONDS = 60 * 60 * 24 -DEFAULT_PORT = "0.0.0.0:6789" - - -def serve(): - server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) - service = ChocolateService() - api_pb2_grpc.add_SuggestionServicer_to_server(service, server) - health_pb2_grpc.add_HealthServicer_to_server(service, server) - server.add_insecure_port(DEFAULT_PORT) - print("Listening...") - server.start() - try: - while True: - time.sleep(_ONE_DAY_IN_SECONDS) - except KeyboardInterrupt: - server.stop(0) - - -if __name__ == "__main__": - serve() diff --git a/cmd/suggestion/chocolate/v1beta1/requirements.txt b/cmd/suggestion/chocolate/v1beta1/requirements.txt deleted file mode 100644 index 69e9408d121..00000000000 --- a/cmd/suggestion/chocolate/v1beta1/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -grpcio==1.41.1 -cloudpickle==0.5.6 -numpy>=1.20.0 -scikit-learn>=0.24.0 -scipy>=1.5.4 -forestci==0.3 -protobuf==3.19.5 -googleapis-common-protos==1.6.0 -SQLAlchemy==1.4.26 -git+https://github.com/AIworx-Labs/chocolate@master -ghalton>=0.6.2; platform_machine=="x86_64" -git+https://github.com/fmder/ghalton@master; platform_machine=="aarch64" -cython>=0.29.24 diff --git a/docs/images-location.md b/docs/images-location.md index ed01bb15016..ae6321f255d 100644 --- a/docs/images-location.md +++ b/docs/images-location.md @@ -151,17 +151,6 @@ and the [Katib Early Stopping algorithms](https://www.kubeflow.org/docs/componen Dockerfile -
docker.io/kubeflowkatib/suggestion-chocolate
- docker.io/kubeflowkatib/suggestion-skopt
diff --git a/pkg/suggestion/v1beta1/chocolate/__init__.py b/pkg/suggestion/v1beta1/chocolate/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/pkg/suggestion/v1beta1/chocolate/base_service.py b/pkg/suggestion/v1beta1/chocolate/base_service.py
deleted file mode 100644
index 8f9c0613ca9..00000000000
--- a/pkg/suggestion/v1beta1/chocolate/base_service.py
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright 2022 The Kubeflow Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import chocolate as choco
-import logging
-import base64
-import warnings
-
-from pkg.suggestion.v1beta1.internal.constant import MAX_GOAL, INTEGER, DOUBLE, CATEGORICAL, DISCRETE
-from pkg.suggestion.v1beta1.internal.trial import Assignment
-
-logger = logging.getLogger(__name__)
-
-DB_ADDRESS = "sqlite:///my_db.db?check_same_thread=False"
-DB_FIELD_LOSS = "_loss"
-DB_FIELD_CHOCOLATE_ID = "_chocolate_id"
-DB_FIELD_TRIAL_NAME = "_trial_name"
-
-DEPRECATED_ALGORITHM_NAME = {
- "chocolate-random": "random",
- "chocolate-quasirandom": "quasirandom",
- "chocolate-bayesian-optimization": "bayesianoptimization",
- "chocolate-mocmaes": "mocmaes",
-}
-
-
-class BaseChocolateService(object):
- """
- Refer to https://chocolate.readthedocs.io/
- """
-
- def __init__(self, algorithm_name, search_space):
- self.conn = choco.SQLiteConnection(DB_ADDRESS)
- self.search_space = search_space
- self.chocolate_optimizer = None
- self.create_optimizer(algorithm_name)
- # created_trials is the list of dicts with all created trials assignments, loss and trial name
- # _chocolate_id is the ID of the trial, Assignment names are encoded,
- # _loss is the target metric, _trial_name is the Trial name
- # One row example:
- # {'_chocolate_id': 0, 'LS1scg==': 0.001, 'LS1udW0tZXBvY2hz': 1, 'LS1udW0tbGF5ZXJz': 2,
- # "_loss": "0.97", "_trial_name": "grid-hsdvfdwl"}
- self.created_trials = []
- self.recorded_trials_names = []
-
- def create_optimizer(self, algorithm_name):
-
- # Search Space example: {"x" : choco.uniform(-6, 6), "y" : choco.uniform(-6, 6)}
- chocolate_search_space = {}
-
- for param in self.search_space.params:
- key = BaseChocolateService.encode(param.name)
- # Chocolate quantized_uniform distribution uses half-open interval: [low, high).
- if param.type == INTEGER:
- chocolate_search_space[key] = choco.quantized_uniform(
- int(param.min), int(param.max) + int(param.step), int(param.step))
- elif param.type == DOUBLE:
- chocolate_search_space[key] = choco.quantized_uniform(
- float(param.min), float(param.max) + float(param.step), float(param.step))
- # For Categorical and Discrete insert indexes to DB from list of values
- elif param.type == CATEGORICAL or param.type == DISCRETE:
- chocolate_search_space[key] = choco.choice(
- [idx for idx, _ in enumerate(param.list)])
-
- if algorithm_name in DEPRECATED_ALGORITHM_NAME:
- warnings.warn(
- "Algorithm name '{}' is deprecated. Please use '{}'.".format(
- algorithm_name, DEPRECATED_ALGORITHM_NAME[algorithm_name],
- ),
- DeprecationWarning,
- )
- algorithm_name = DEPRECATED_ALGORITHM_NAME[algorithm_name]
-
- # Refer to https://chocolate.readthedocs.io/tutorials/algo.html
- if algorithm_name == "grid":
- self.chocolate_optimizer = choco.Grid(
- self.conn, chocolate_search_space, clear_db=True)
- # hyperopt-random is the default option in katib.
- elif algorithm_name == "random":
- self.chocolate_optimizer = choco.Random(
- self.conn, chocolate_search_space, clear_db=True)
- elif algorithm_name == "quasirandom":
- self.chocolate_optimizer = choco.QuasiRandom(
- self.conn, chocolate_search_space, clear_db=True)
- elif algorithm_name == "bayesianoptimization":
- self.chocolate_optimizer = choco.Bayes(
- self.conn, chocolate_search_space, clear_db=True)
- # elif self.algorithm_name == "chocolate-CMAES":
- # self.chocolate_optimizer = choco.CMAES(self.conn, chocolate_search_space, clear_db=True)
- elif algorithm_name == "mocmaes":
- mu = 1
- self.chocolate_optimizer = choco.MOCMAES(
- self.conn, chocolate_search_space, mu=mu, clear_db=True)
- else:
- raise Exception(
- '"Failed to create Chocolate optimizer for the algorithm: {}'.format(algorithm_name))
-
- def getSuggestions(self, trials, current_request_number, total_request_number):
- """
- Get the new suggested trials with chocolate algorithm.
- """
- logger.info("-" * 100 + "\n")
- logger.info("New GetSuggestions call with total requested {} and currently requesting {} \n".format(
- total_request_number, current_request_number))
- for _, trial in enumerate(trials):
- if trial.name not in self.recorded_trials_names:
- loss_for_choco = float(trial.target_metric.value)
- if self.search_space.goal == MAX_GOAL:
- loss_for_choco = -1 * loss_for_choco
-
- trial_assignments_dict = {}
- for param in self.search_space.params:
- param_assignment = None
- for assignment in trial.assignments:
- if param.name == assignment.name:
- param_assignment = assignment.value
- break
- if param.type == INTEGER:
- param_assignment = int(param_assignment)
- elif param.type == DOUBLE:
- param_assignment = float(param_assignment)
- elif param.type == CATEGORICAL or param.type == DISCRETE:
- param_assignment = param.list.index(param_assignment)
- trial_assignments_dict.update({BaseChocolateService.encode(
- param.name): param_assignment})
-
- # Finding index for the current Trial Assignments in created_trial list without loss
- new_trial_loss_idx = -1
- i = 0
- while new_trial_loss_idx == -1 and i < len(self.created_trials):
- # Created Trial must not include loss and must have the same param assignment
- if ((DB_FIELD_LOSS not in self.created_trials[i] or
- self.created_trials[i][DB_FIELD_LOSS] is None) and
- len(trial_assignments_dict.items() & self.created_trials[i].items()) ==
- len(self.search_space.params)):
- new_trial_loss_idx = i
- i += 1
-
- if new_trial_loss_idx != -1:
- self.created_trials[new_trial_loss_idx][DB_FIELD_LOSS] = loss_for_choco
- self.created_trials[new_trial_loss_idx][DB_FIELD_TRIAL_NAME] = trial.name
-
- # Update sqlite database with new loss and trial assignments
- id_filter = {
- DB_FIELD_CHOCOLATE_ID: self.created_trials[new_trial_loss_idx][DB_FIELD_CHOCOLATE_ID]}
- self.conn.update_result(
- id_filter,
- self.created_trials[new_trial_loss_idx])
-
- self.recorded_trials_names.append(trial.name)
-
- logger.info("New record in sqlite DB is updated")
- logger.info("{}\n".format(
- self.created_trials[new_trial_loss_idx]))
- # Assuming that created_trials are already populated
- # TODO: Handle Restart of algorithm pod
- logger.info("{} Trials created in DB".format(len(self.created_trials)))
- if total_request_number != len(self.created_trials) + current_request_number:
- logger.info("Mismatch in generated trials with k8s suggestions trials")
- new_actual_requested_no = total_request_number - len(self.created_trials)
- prev_generated_no = current_request_number - new_actual_requested_no
- logger.info(
- "In this call, New {} Trials will be generated, {} Trials will be reused from previously generated".format(
- new_actual_requested_no, prev_generated_no))
-
- list_of_assignments = []
- if prev_generated_no > 0:
- for params in self.created_trials[-prev_generated_no:]:
- if DB_FIELD_TRIAL_NAME in params:
- logger.error("Trial already updated in selected assignment {}".format(params))
- new_assignment = BaseChocolateService.convert(
- self.search_space, params)
- list_of_assignments.append(new_assignment)
-
- for i in range(new_actual_requested_no):
- try:
- token, chocolate_params = self.chocolate_optimizer.next()
- new_assignment = BaseChocolateService.convert(
- self.search_space, chocolate_params)
- list_of_assignments.append(new_assignment)
- logger.info("New suggested parameters for Trial with chocolate_id: {}".format(
- token[DB_FIELD_CHOCOLATE_ID]))
- for assignment in new_assignment:
- logger.info("Name = {}, Value = {}".format(
- assignment.name, assignment.value))
- logger.info("-" * 50 + "\n")
- # Add new trial assignment with chocolate_id to created trials
- token.update(chocolate_params)
- new_trial_dict = token
- self.created_trials.append(new_trial_dict)
-
- except StopIteration:
- logger.info(
- "Chocolate db is exhausted, increase Search Space or decrease maxTrialCount!")
-
- if len(list_of_assignments) > 0:
- logger.info("GetSuggestions returns {} Trials from requested {} Trials\n\n".format(
- len(list_of_assignments), current_request_number))
-
- return list_of_assignments
-
- @staticmethod
- def convert(search_space, chocolate_params):
- assignments = []
- for param in search_space.params:
- key = BaseChocolateService.encode(param.name)
- if param.type == INTEGER:
- assignments.append(Assignment(
- param.name, chocolate_params[key]))
- elif param.type == DOUBLE:
- assignments.append(Assignment(
- param.name, chocolate_params[key]))
- elif param.type == CATEGORICAL or param.type == DISCRETE:
- assignments.append(Assignment(
- param.name, param.list[chocolate_params[key]]))
- return assignments
-
- @staticmethod
- def encode(name):
- """Encode the name. Chocolate will check if the name contains hyphens.
- Thus we need to encode it.
- """
- return base64.b64encode(name.encode('utf-8')).decode('utf-8')
diff --git a/pkg/suggestion/v1beta1/chocolate/service.py b/pkg/suggestion/v1beta1/chocolate/service.py
deleted file mode 100644
index 9ab1b77e59d..00000000000
--- a/pkg/suggestion/v1beta1/chocolate/service.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright 2022 The Kubeflow Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import logging
-import grpc
-
-from pkg.apis.manager.v1beta1.python import api_pb2
-from pkg.apis.manager.v1beta1.python import api_pb2_grpc
-
-from pkg.suggestion.v1beta1.internal.constant import INTEGER, DOUBLE, CATEGORICAL, DISCRETE
-from pkg.suggestion.v1beta1.internal.search_space import HyperParameterSearchSpace
-from pkg.suggestion.v1beta1.internal.trial import Trial, Assignment
-from pkg.suggestion.v1beta1.chocolate.base_service import BaseChocolateService
-from pkg.suggestion.v1beta1.internal.base_health_service import HealthServicer
-
-import numpy as np
-import itertools
-
-logger = logging.getLogger(__name__)
-
-
-class ChocolateService(api_pb2_grpc.SuggestionServicer, HealthServicer):
- def __init__(self):
- super(ChocolateService, self).__init__()
- self.base_service = None
- self.is_first_run = True
-
- def ValidateAlgorithmSettings(self, request, context):
- algorithm_name = request.experiment.spec.algorithm.algorithm_name
- if algorithm_name == "grid":
- search_space = HyperParameterSearchSpace.convert(
- request.experiment)
- available_space = {}
- for param in search_space.params:
- if param.type == INTEGER:
- available_space[param.name] = range(int(param.min), int(param.max)+1, int(param.step))
-
- elif param.type == DOUBLE:
- if param.step == "" or param.step is None:
- return self._set_validate_context_error(
- context, "Param: {} step is nil".format(param.name))
- double_list = np.arange(float(param.min), float(param.max)+float(param.step), float(param.step))
- if double_list[-1] > float(param.max):
- double_list = double_list[:-1]
- available_space[param.name] = double_list
-
- elif param.type == CATEGORICAL or param.type == DISCRETE:
- available_space[param.name] = param.list
-
- num_combinations = len(list(itertools.product(*available_space.values())))
- max_trial_count = request.experiment.spec.max_trial_count
-
- if max_trial_count > num_combinations:
- return self._set_validate_context_error(
- context, "Max Trial Count: {} > all possible search space combinations: {}".format(
- max_trial_count, num_combinations)
- )
-
- return api_pb2.ValidateAlgorithmSettingsReply()
-
- def GetSuggestions(self, request, context):
- """
- Main function to provide suggestion.
- """
-
- if self.is_first_run:
- search_space = HyperParameterSearchSpace.convert(
- request.experiment)
- self.base_service = BaseChocolateService(
- algorithm_name=request.experiment.spec.algorithm.algorithm_name,
- search_space=search_space)
- self.is_first_run = False
-
- trials = Trial.convert(request.trials)
- new_assignments = self.base_service.getSuggestions(
- trials, request.current_request_number, request.total_request_number)
- return api_pb2.GetSuggestionsReply(
- parameter_assignments=Assignment.generate(new_assignments)
- )
-
- def _set_validate_context_error(self, context, error_message):
- context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
- context.set_details(error_message)
- logger.info(error_message)
- return api_pb2.ValidateAlgorithmSettingsReply()
diff --git a/scripts/v1beta1/build.sh b/scripts/v1beta1/build.sh
index 5e3c62b0122..3953f49f54d 100755
--- a/scripts/v1beta1/build.sh
+++ b/scripts/v1beta1/build.sh
@@ -84,9 +84,6 @@ echo -e "\nBuilding suggestion images..."
echo -e "\nBuilding hyperopt suggestion...\n"
docker buildx build --platform "linux/${ARCH}" -t "${REGISTRY}/suggestion-hyperopt:${TAG}" -f ${CMD_PREFIX}/suggestion/hyperopt/${VERSION}/Dockerfile .
-echo -e "\nBuilding chocolate suggestion...\n"
-docker buildx build --platform "linux/${ARCH}" -t "${REGISTRY}/suggestion-chocolate:${TAG}" -f ${CMD_PREFIX}/suggestion/chocolate/${VERSION}/Dockerfile .
-
echo -e "\nBuilding hyperband suggestion...\n"
docker buildx build --platform "linux/${ARCH}" -t "${REGISTRY}/suggestion-hyperband:${TAG}" -f ${CMD_PREFIX}/suggestion/hyperband/${VERSION}/Dockerfile .
diff --git a/scripts/v1beta1/push.sh b/scripts/v1beta1/push.sh
index 95f5d3c98eb..6f0627b4081 100755
--- a/scripts/v1beta1/push.sh
+++ b/scripts/v1beta1/push.sh
@@ -59,9 +59,6 @@ echo -e "\nPushing suggestion images..."
echo -e "\nPushing hyperopt suggestion...\n"
docker push "${REGISTRY}/suggestion-hyperopt:${TAG}"
-echo -e "\nPushing chocolate suggestion...\n"
-docker push "${REGISTRY}/suggestion-chocolate:${TAG}"
-
echo -e "\nPushing hyperband suggestion...\n"
docker push "${REGISTRY}/suggestion-hyperband:${TAG}"
diff --git a/test/e2e/v1beta1/hack/aws/argo_workflow.py b/test/e2e/v1beta1/hack/aws/argo_workflow.py
index 7064273ff06..36a403d7d12 100644
--- a/test/e2e/v1beta1/hack/aws/argo_workflow.py
+++ b/test/e2e/v1beta1/hack/aws/argo_workflow.py
@@ -49,7 +49,6 @@
"file-metrics-collector": "cmd/metricscollector/v1beta1/file-metricscollector/Dockerfile",
"tfevent-metrics-collector": "cmd/metricscollector/v1beta1/tfevent-metricscollector/Dockerfile",
"suggestion-hyperopt": "cmd/suggestion/hyperopt/v1beta1/Dockerfile",
- "suggestion-chocolate": "cmd/suggestion/chocolate/v1beta1/Dockerfile",
"suggestion-skopt": "cmd/suggestion/skopt/v1beta1/Dockerfile",
"suggestion-hyperband": "cmd/suggestion/hyperband/v1beta1/Dockerfile",
"suggestion-goptuna": "cmd/suggestion/goptuna/v1beta1/Dockerfile",
diff --git a/test/e2e/v1beta1/scripts/gh-actions/build-load.sh b/test/e2e/v1beta1/scripts/gh-actions/build-load.sh
index 30dc2f2f159..6259d5761dd 100755
--- a/test/e2e/v1beta1/scripts/gh-actions/build-load.sh
+++ b/test/e2e/v1beta1/scripts/gh-actions/build-load.sh
@@ -158,7 +158,6 @@ cleanup_build_cache
# Suggestion images
echo -e "\nBuilding suggestion images..."
run "suggestion-hyperopt" "$CMD_PREFIX/suggestion/hyperopt/$VERSION/Dockerfile"
-run "suggestion-chocolate" "$CMD_PREFIX/suggestion/chocolate/$VERSION/Dockerfile"
run "suggestion-hyperband" "$CMD_PREFIX/suggestion/hyperband/$VERSION/Dockerfile"
run "suggestion-skopt" "$CMD_PREFIX/suggestion/skopt/$VERSION/Dockerfile"
run "suggestion-goptuna" "$CMD_PREFIX/suggestion/goptuna/$VERSION/Dockerfile"
diff --git a/test/unit/v1beta1/suggestion/test_chocolate_service.py b/test/unit/v1beta1/suggestion/test_chocolate_service.py
deleted file mode 100644
index 34809f4863f..00000000000
--- a/test/unit/v1beta1/suggestion/test_chocolate_service.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# Copyright 2022 The Kubeflow Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-
-import grpc
-import grpc_testing
-import unittest
-import pytest
-
-from pkg.apis.manager.v1beta1.python import api_pb2
-
-from pkg.suggestion.v1beta1.chocolate.service import ChocolateService
-
-import utils
-
-
-class TestChocolate(unittest.TestCase):
- def setUp(self):
- servicers = {
- api_pb2.DESCRIPTOR.services_by_name['Suggestion']: ChocolateService(
- )
- }
-
- self.test_server = grpc_testing.server_from_dictionary(
- servicers, grpc_testing.strict_real_time())
-
- def test_get_suggestion(self):
- trials = [
- api_pb2.Trial(
- name="test-asfjh",
- spec=api_pb2.TrialSpec(
- objective=api_pb2.ObjectiveSpec(
- type=api_pb2.MAXIMIZE,
- objective_metric_name="metric-2",
- goal=0.9
- ),
- parameter_assignments=api_pb2.TrialSpec.ParameterAssignments(
- assignments=[
- api_pb2.ParameterAssignment(
- name="param-1",
- value="2",
- ),
- api_pb2.ParameterAssignment(
- name="param-2",
- value="cat1",
- ),
- api_pb2.ParameterAssignment(
- name="param-3",
- value="2",
- ),
- api_pb2.ParameterAssignment(
- name="param-4",
- value="3.44",
- )
- ]
- )
- ),
- status=api_pb2.TrialStatus(
- observation=api_pb2.Observation(
- metrics=[
- api_pb2.Metric(
- name="metric=1",
- value="435"
- ),
- api_pb2.Metric(
- name="metric=2",
- value="5643"
- ),
- ]
- )
- )
- ),
- api_pb2.Trial(
- name="test-234hs",
- spec=api_pb2.TrialSpec(
- objective=api_pb2.ObjectiveSpec(
- type=api_pb2.MAXIMIZE,
- objective_metric_name="metric-2",
- goal=0.9
- ),
- parameter_assignments=api_pb2.TrialSpec.ParameterAssignments(
- assignments=[
- api_pb2.ParameterAssignment(
- name="param-1",
- value="3",
- ),
- api_pb2.ParameterAssignment(
- name="param-2",
- value="cat2",
- ),
- api_pb2.ParameterAssignment(
- name="param-3",
- value="6",
- ),
- api_pb2.ParameterAssignment(
- name="param-4",
- value="4.44",
- )
- ]
- )
- ),
- status=api_pb2.TrialStatus(
- observation=api_pb2.Observation(
- metrics=[
- api_pb2.Metric(
- name="metric=1",
- value="123"
- ),
- api_pb2.Metric(
- name="metric=2",
- value="3028"
- ),
- ]
- )
- )
- )
- ]
- experiment = api_pb2.Experiment(
- name="test",
- spec=api_pb2.ExperimentSpec(
- algorithm=api_pb2.AlgorithmSpec(
- algorithm_name="grid",
- ),
- objective=api_pb2.ObjectiveSpec(
- type=api_pb2.MAXIMIZE,
- goal=0.9
- ),
- parameter_specs=api_pb2.ExperimentSpec.ParameterSpecs(
- parameters=[
- api_pb2.ParameterSpec(
- name="param-1",
- parameter_type=api_pb2.INT,
- feasible_space=api_pb2.FeasibleSpace(
- max="5", min="1", list=[]),
- ),
- api_pb2.ParameterSpec(
- name="param-2",
- parameter_type=api_pb2.CATEGORICAL,
- feasible_space=api_pb2.FeasibleSpace(
- max=None, min=None, list=["cat1", "cat2", "cat3"])
- ),
- api_pb2.ParameterSpec(
- name="param-3",
- parameter_type=api_pb2.DISCRETE,
- feasible_space=api_pb2.FeasibleSpace(
- max=None, min=None, list=["3", "2", "6"])
- ),
- api_pb2.ParameterSpec(
- name="param-4",
- parameter_type=api_pb2.DOUBLE,
- feasible_space=api_pb2.FeasibleSpace(
- max="5", min="1", list=[], step="0.5")
- )
- ]
- )
- )
- )
-
- request = api_pb2.GetSuggestionsRequest(
- experiment=experiment,
- trials=trials,
- current_request_number=2,
- total_request_number=2,
- )
-
- get_suggestion = self.test_server.invoke_unary_unary(
- method_descriptor=(api_pb2.DESCRIPTOR
- .services_by_name['Suggestion']
- .methods_by_name['GetSuggestions']),
- invocation_metadata={},
- request=request, timeout=100)
-
- response, metadata, code, details = get_suggestion.termination()
- print(response.parameter_assignments)
- self.assertEqual(code, grpc.StatusCode.OK)
- self.assertEqual(2, len(response.parameter_assignments))
-
- def test_validate_algorithm_settings(self):
- # Valid case.
- experiment_spec = api_pb2.ExperimentSpec(
- algorithm=api_pb2.AlgorithmSpec(
- algorithm_name="grid",
- ),
- parameter_specs=api_pb2.ExperimentSpec.ParameterSpecs(
- parameters=[
- api_pb2.ParameterSpec(
- name="param-1",
- parameter_type=api_pb2.INT,
- feasible_space=api_pb2.FeasibleSpace(
- max="5", min="1", list=[]),
- ),
- api_pb2.ParameterSpec(
- name="param-2",
- parameter_type=api_pb2.CATEGORICAL,
- feasible_space=api_pb2.FeasibleSpace(
- max=None, min=None, list=["cat1", "cat2", "cat3"])
- ),
- api_pb2.ParameterSpec(
- name="param-3",
- parameter_type=api_pb2.DISCRETE,
- feasible_space=api_pb2.FeasibleSpace(
- max=None, min=None, list=["3", "2", "6"])
- ),
- api_pb2.ParameterSpec(
- name="param-4",
- parameter_type=api_pb2.DOUBLE,
- feasible_space=api_pb2.FeasibleSpace(
- max="2.9", min="1", list=[], step="0.5")
- )
- ]
- ),
- max_trial_count=12,
- parallel_trial_count=3,
- )
-
- _, _, code, _ = utils.call_validate(self.test_server, experiment_spec)
- self.assertEqual(code, grpc.StatusCode.OK)
-
- # Invalid cases.
- # Empty step.
- experiment_spec = api_pb2.ExperimentSpec(
- algorithm=api_pb2.AlgorithmSpec(
- algorithm_name="grid",
- ),
- parameter_specs=api_pb2.ExperimentSpec.ParameterSpecs(
- parameters=[
- api_pb2.ParameterSpec(
- name="param-1",
- parameter_type=api_pb2.DOUBLE,
- feasible_space=api_pb2.FeasibleSpace(
- max="3", min="1", list=[])
- )
- ]
- ),
- )
-
- _, _, code, details = utils.call_validate(self.test_server, experiment_spec)
- self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT)
- self.assertEqual(details, 'Param: param-1 step is nil')
-
- # Max trial count > search space combinations.
- experiment_spec = api_pb2.ExperimentSpec(
- algorithm=api_pb2.AlgorithmSpec(
- algorithm_name="grid",
- ),
- parameter_specs=api_pb2.ExperimentSpec.ParameterSpecs(
- parameters=[
- api_pb2.ParameterSpec(
- name="param-1",
- parameter_type=api_pb2.INT,
- feasible_space=api_pb2.FeasibleSpace(
- max="2", min="1", list=[]),
- ),
- api_pb2.ParameterSpec(
- name="param-2",
- parameter_type=api_pb2.CATEGORICAL,
- feasible_space=api_pb2.FeasibleSpace(
- max=None, min=None, list=["cat1", "cat2"])
- ),
- api_pb2.ParameterSpec(
- name="param-4",
- parameter_type=api_pb2.DOUBLE,
- feasible_space=api_pb2.FeasibleSpace(
- max="2", min="1", list=[], step="0.5")
- )
- ]
- ),
- max_trial_count=15,
- )
-
- _, _, code, details = utils.call_validate(self.test_server, experiment_spec)
- self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT)
- self.assertEqual(details, 'Max Trial Count: 15 > all possible search space combinations: 12')
-
-
-@pytest.fixture(scope='function', autouse=True)
-def tear_down():
- yield
- working_dir = os.getcwd()
- db_file = ["my_db.db", "my_db.db?check_same_thread=False.lock", "my_db.db-shm", "my_db.db-wal"]
- for fname in db_file:
- target_path = os.path.join(working_dir, fname)
- if os.path.isfile(target_path):
- os.remove(target_path)
-
-
-if __name__ == '__main__':
- unittest.main()