chore(components/pytorch): Samples Unit tests and lint fixes (#6288)
* Applying yapf on all the python files in samples Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Test compile yaml fixes Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Remove unused file Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Lint fixes: generate_templates.py Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Lint fixes: gen_image_timestamp.py Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Lint fixes Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Cifar10 handler lint fixes Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com> * Lint fixes for the remaining files Signed-off-by: Shrinath Suresh <shrinath@ideas2it.com>
This commit is contained in:
parent
6f4a4f1f83
commit
b4ad3d1488
|
|
@ -34,7 +34,7 @@ implementation:
|
|||
# For GPU use
|
||||
# image: public.ecr.aws/pytorch-samples/kfp_samples:latest-gpu
|
||||
image: "docker image name" # Ex: public.ecr.aws/pytorch-samples/kfp_samples:latest
|
||||
command: "command to execute" # Ex: ['python3', 'cifar10/cifar10_pytorch.py']
|
||||
command: ["command to execute"] # Ex: ['python3', 'cifar10/cifar10_pytorch.py']
|
||||
args:
|
||||
- --dataset_path
|
||||
- {inputPath: input_data}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ implementation:
|
|||
# For GPU use
|
||||
# image: public.ecr.aws/pytorch-samples/kfp_samples:latest-gpu
|
||||
image: public.ecr.aws/pytorch-samples/kfp_samples:latest
|
||||
command: "command to execute. Ex: ['python3', 'bert/bert_pre_process.py']"
|
||||
command: ["command to execute"] #Ex: ['python3', 'bert/bert_pre_process.py']
|
||||
args:
|
||||
- --output_path
|
||||
- {outputPath: output_data}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ implementation:
|
|||
# For GPU use
|
||||
# image: public.ecr.aws/pytorch-samples/kfp_samples:latest-gpu
|
||||
image: public.ecr.aws/pytorch-samples/kfp_samples:latest
|
||||
command: "command to execute. Ex: ['python3', 'bert/agnews_classification_pytorch.py']"
|
||||
command: ["command to execute"] #Ex: ['python3', 'bert/agnews_classification_pytorch.py']
|
||||
args:
|
||||
- --dataset_path
|
||||
- {inputPath: input_data}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
#pylint: disable=not-callable,unused-variable
|
||||
"""Test for component compilation."""
|
||||
import os
|
||||
import unittest
|
||||
import json
|
||||
import pytest
|
||||
|
|
@ -22,27 +23,36 @@ from kfp.components import load_component_from_file
|
|||
from kfp import dsl
|
||||
from kfp import compiler
|
||||
|
||||
tests_dir, _ = os.path.split(os.path.abspath(__file__))
|
||||
|
||||
templates_dir = os.path.join(os.path.dirname(tests_dir), "templates")
|
||||
|
||||
BERT_COMPONENTS = {
|
||||
"component_bert_prep":
|
||||
components.
|
||||
load_component_from_file("bert/yaml/pre_process/component.yaml"),
|
||||
load_component_from_file(f"{templates_dir}/preprocess_component.yaml"),
|
||||
"component_bert_train":
|
||||
components.load_component_from_file("bert/yaml/train/component.yaml"),
|
||||
components.
|
||||
load_component_from_file(f"{templates_dir}/train_component.yaml"),
|
||||
}
|
||||
CIFAR_COMPONENTS = {
|
||||
"component_cifar10_prep":
|
||||
components.
|
||||
load_component_from_file("./cifar10/yaml/pre_process/component.yaml"),
|
||||
load_component_from_file(f"{templates_dir}/preprocess_component.yaml"),
|
||||
"component_cifar10_train":
|
||||
components.
|
||||
load_component_from_file("./cifar10/yaml/train/component.yaml"),
|
||||
load_component_from_file(f"{templates_dir}/train_component.yaml"),
|
||||
}
|
||||
COMPONENT_TB = load_component_from_file("common/tensorboard/component.yaml")
|
||||
COMPONENT_DEPLOY = load_component_from_file("common/deploy/component.yaml")
|
||||
COMPONENT_MNIO = components.load_component_from_file(
|
||||
"./common/minio/component.yaml"
|
||||
COMPONENT_TB = load_component_from_file(
|
||||
f"{templates_dir}/tensorboard_component.yaml"
|
||||
)
|
||||
PRED_OP = load_component_from_file("./common/prediction/component.yaml")
|
||||
COMPONENT_DEPLOY = load_component_from_file(
|
||||
f"{templates_dir}/deploy_component.yaml"
|
||||
)
|
||||
COMPONENT_MNIO = components.load_component_from_file(
|
||||
f"{templates_dir}/minio_component.yaml"
|
||||
)
|
||||
PRED_OP = load_component_from_file(f"{templates_dir}/prediction_component.yaml")
|
||||
|
||||
|
||||
class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instance-attributes
|
||||
|
|
@ -50,7 +60,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
|
||||
def setUp(self):
|
||||
"""Set up."""
|
||||
super(ComponentCompileTest, self).setUp()
|
||||
super().setUp()
|
||||
self.input_request = "./compile_test.json"
|
||||
self.deploy_name_bert = "bertserve"
|
||||
self.namespace = "kubeflow-user-example-com"
|
||||
|
|
@ -76,18 +86,18 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
description="Cifar 10 dataset pipeline",
|
||||
) #pylint: disable=too-many-arguments,too-many-locals
|
||||
def pytorch_cifar10(
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_cifar,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix"
|
||||
f"/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
checkpoint_dir=f"checkpoint_dir/cifar10",
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_cifar,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix"
|
||||
f"/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
checkpoint_dir="checkpoint_dir/cifar10",
|
||||
):
|
||||
"""Cifar10 pipelines."""
|
||||
pod_template_spec = json.dumps({
|
||||
|
|
@ -145,15 +155,20 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
)
|
||||
component_cifar10_train = CIFAR_COMPONENTS["component_cifar10_train"
|
||||
]
|
||||
confusion_matrix_url = \
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}"
|
||||
script_args = f"model_name=resnet.pth," \
|
||||
f"confusion_matrix_url={confusion_matrix_url}"
|
||||
# For gpus, set number of gpus and accelerator type
|
||||
ptl_args = "max_epochs=1, " \
|
||||
"gpus=0, " \
|
||||
"accelerator=None, " \
|
||||
"profiler=pytorch"
|
||||
train_task = (
|
||||
component_cifar10_train(
|
||||
input_data=prep_task.outputs["output_data"],
|
||||
profiler="pytorch",
|
||||
confusion_matrix_url=
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}",
|
||||
# For GPU set gpu count and accelerator type
|
||||
gpus=0,
|
||||
accelerator="None",
|
||||
script_args=script_args,
|
||||
ptl_arguments=ptl_args
|
||||
).after(prep_task).set_display_name("Training")
|
||||
)
|
||||
|
||||
|
|
@ -270,17 +285,19 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
name="Training pipeline", description="Sample training job test"
|
||||
) #pylint: disable=too-many-arguments,too-many-locals
|
||||
def pytorch_bert(
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_bert,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
num_samples=1000,
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_bert,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=
|
||||
f"confusion_matrix/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
num_samples=1000,
|
||||
max_epochs=1
|
||||
):
|
||||
"""Bert Pipeline."""
|
||||
prepare_tb_task = COMPONENT_TB(
|
||||
|
|
@ -335,16 +352,21 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
set_display_name("Preprocess & Transform")
|
||||
)
|
||||
component_bert_train = BERT_COMPONENTS["component_bert_train"]
|
||||
confusion_matrix_url = \
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}"
|
||||
script_args = f"model_name=bert.pth," \
|
||||
f"num_samples={num_samples}," \
|
||||
f"confusion_matrix_url={confusion_matrix_url}"
|
||||
# For gpus, set number of gpus and accelerator type
|
||||
ptl_args = f"max_epochs={max_epochs}," \
|
||||
"profiler=pytorch," \
|
||||
"gpus=0," \
|
||||
"accelerator=None"
|
||||
train_task = (
|
||||
component_bert_train(
|
||||
input_data=prep_task.outputs["output_data"],
|
||||
profiler="pytorch",
|
||||
confusion_matrix_url=
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}",
|
||||
num_samples=num_samples,
|
||||
# For GPU set gpu count and accelerator type
|
||||
gpus=0,
|
||||
accelerator="None",
|
||||
script_args=script_args,
|
||||
ptl_arguments=ptl_args
|
||||
).after(prep_task).set_display_name("Training")
|
||||
)
|
||||
|
||||
|
|
@ -388,7 +410,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
storageUri: {}
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
memory: 4Gi
|
||||
""".format(deploy, namespace, model_uri)
|
||||
|
||||
# For GPU inference use below yaml with gpu count and accelerator
|
||||
|
|
@ -407,7 +429,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
storageUri: {}
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
memory: 4Gi
|
||||
nvidia.com/gpu: {}
|
||||
nodeSelector:
|
||||
cloud.google.com/gke-accelerator: {}
|
||||
|
|
@ -431,18 +453,18 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
description="Cifar 10 dataset pipeline",
|
||||
) #pylint: disable=too-many-arguments,too-many-locals
|
||||
def pytorch_cifar10(
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_cifar,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix"
|
||||
f"/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
checkpoint_dir=f"checkpoint_dir/cifar10",
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_cifar,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix"
|
||||
f"/{dsl.RUN_ID_PLACEHOLDER}/", #pylint: disable=f-string-without-interpolation
|
||||
checkpoint_dir=f"checkpoint_dir/cifar10",
|
||||
):
|
||||
"""Cifar10 pipelines."""
|
||||
pod_template_spec = json.dumps({
|
||||
|
|
@ -498,16 +520,21 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
component_cifar10_prep().after(prepare_tb_task).
|
||||
set_display_name("Preprocess & Transform")
|
||||
)
|
||||
confusion_matrix_url = \
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}"
|
||||
script_args = f"model_name=resnet.pth," \
|
||||
f"confusion_matrix_url={confusion_matrix_url}"
|
||||
# For gpus, set number of gpus and accelerator type
|
||||
ptl_args = "max_epochs=1, " \
|
||||
"gpus=0, " \
|
||||
"accelerator=None, " \
|
||||
"profiler=pytorch"
|
||||
component_cifar10_train = ""
|
||||
train_task = (
|
||||
component_cifar10_train(
|
||||
input_data=prep_task.outputs["output_data"],
|
||||
profiler="pytorch",
|
||||
confusion_matrix_url=
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}",
|
||||
# For GPU set gpu count and accelerator type
|
||||
gpus=0,
|
||||
accelerator="None",
|
||||
script_args=script_args,
|
||||
ptl_arguments=ptl_args
|
||||
).after(prep_task).set_display_name("Training")
|
||||
)
|
||||
|
||||
|
|
@ -581,7 +608,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
storageUri: {}
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
memory: 4Gi
|
||||
nvidia.com/gpu: {}
|
||||
nodeSelector:
|
||||
cloud.google.com/gke-accelerator: {}
|
||||
|
|
@ -612,10 +639,12 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
inference_type="explain",
|
||||
).after(pred_task).set_display_name("Explanation")
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
compiler.Compiler().compile(
|
||||
pytorch_cifar10, "pytorch.tar.gz", type_check=True
|
||||
)
|
||||
|
||||
def test_bert_compile_fail(self):
|
||||
"""Test bert yamls compilation."""
|
||||
|
||||
|
|
@ -623,17 +652,19 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
name="Training pipeline", description="Sample training job test"
|
||||
) #pylint: disable=too-many-arguments,too-many-locals
|
||||
def pytorch_bert(
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_bert,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=f"confusion_matrix/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
num_samples=1000,
|
||||
minio_endpoint=self.minio_endpoint,
|
||||
log_bucket=self.log_bucket,
|
||||
log_dir=f"tensorboard/logs/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
mar_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/model-store",
|
||||
config_prop_path=f"mar/{dsl.RUN_ID_PLACEHOLDER}/config",
|
||||
model_uri=f"s3://mlpipeline/mar/{dsl.RUN_ID_PLACEHOLDER}",
|
||||
tf_image=self.tensorboard_image,
|
||||
deploy=self.deploy_name_bert,
|
||||
namespace=self.namespace,
|
||||
confusion_matrix_log_dir=
|
||||
f"confusion_matrix/{dsl.RUN_ID_PLACEHOLDER}/",
|
||||
num_samples=1000,
|
||||
max_epochs=1
|
||||
):
|
||||
"""Bert Pipeline."""
|
||||
prepare_tb_task = COMPONENT_TB(
|
||||
|
|
@ -687,17 +718,22 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
component_bert_prep().after(prepare_tb_task).
|
||||
set_display_name("Preprocess & Transform")
|
||||
)
|
||||
confusion_matrix_url = \
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}"
|
||||
script_args = f"model_name=bert.pth," \
|
||||
f"num_samples={num_samples}," \
|
||||
f"confusion_matrix_url={confusion_matrix_url}"
|
||||
# For gpus, set number of gpus and accelerator type
|
||||
ptl_args = f"max_epochs={max_epochs}," \
|
||||
"profiler=pytorch," \
|
||||
"gpus=0," \
|
||||
"accelerator=None"
|
||||
component_bert_train = ""
|
||||
train_task = (
|
||||
component_bert_train(
|
||||
input_data=prep_task.outputs["output_data"],
|
||||
profiler="pytorch",
|
||||
confusion_matrix_url=
|
||||
f"minio://{log_bucket}/{confusion_matrix_log_dir}",
|
||||
num_samples=num_samples,
|
||||
# For GPU set gpu count and accelerator type
|
||||
gpus=0,
|
||||
accelerator="None",
|
||||
script_args=script_args,
|
||||
ptl_arguments=ptl_args
|
||||
).after(prep_task).set_display_name("Training")
|
||||
)
|
||||
|
||||
|
|
@ -741,7 +777,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
storageUri: {}
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
memory: 4Gi
|
||||
""".format(deploy, namespace, model_uri)
|
||||
|
||||
# For GPU inference use below yaml with gpu count and accelerator
|
||||
|
|
@ -760,7 +796,7 @@ class ComponentCompileTest(unittest.TestCase): #pylint: disable=too-many-instan
|
|||
storageUri: {}
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
memory: 4Gi
|
||||
nvidia.com/gpu: {}
|
||||
nodeSelector:
|
||||
cloud.google.com/gke-accelerator: {}
|
||||
|
|
@ -27,7 +27,7 @@ from pytorch_kfp_components.components.mar.component import MarGeneration
|
|||
from pytorch_kfp_components.components.utils.argument_parsing import parse_input_args
|
||||
# Argument parser for user defined paths
|
||||
import pytorch_lightning
|
||||
print("Using Pytorch Lighting: {}".format(pytorch_lightning.__version__))
|
||||
print("Using Pytorch Lighting: {}".format(pytorch_lightning.__version__)) #pylint: disable=no-member
|
||||
parser = ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
|
|
@ -236,4 +236,3 @@ if trainer.ptl_trainer.global_rank == 0:
|
|||
mlpipeline_metrics=args["mlpipeline_metrics"],
|
||||
markdown=markdown_dict,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class NewsClassifierHandler(BaseHandler): # pylint: disable=too-many-instance-a
|
|||
self.vocab_file
|
||||
)
|
||||
)
|
||||
self.input_ids = torch.tensor( # pylint: disable=attribute-defined-outside-init,not-callable
|
||||
self.input_ids = torch.tensor( # pylint: disable=attribute-defined-outside-init,not-callable,no-member
|
||||
[
|
||||
self.tokenizer.encode(self.text, add_special_tokens=True)
|
||||
]
|
||||
|
|
@ -114,7 +114,8 @@ class NewsClassifierHandler(BaseHandler): # pylint: disable=too-many-instance-a
|
|||
"""Predict the class for a review / sentence whether
|
||||
it is belong to world / sports / business /sci-tech.
|
||||
Args:
|
||||
encoding: Input encoding to be passed through the layers for prediction
|
||||
encoding:
|
||||
Input encoding to be passed through the layers for prediction
|
||||
|
||||
Returns:
|
||||
output - predicted output
|
||||
|
|
@ -197,7 +198,8 @@ class NewsClassifierHandler(BaseHandler): # pylint: disable=too-many-instance-a
|
|||
"""Captum explanations handler.
|
||||
|
||||
Args:
|
||||
data_preprocess (Torch Tensor): Preprocessed data to be used for captum
|
||||
data_preprocess (Torch Tensor):
|
||||
Preprocessed data to be used for captum
|
||||
raw_data (list): The unprocessed data to get target from the request
|
||||
Returns:
|
||||
dict : A dictionary response with the explanations response.
|
||||
|
|
@ -206,7 +208,7 @@ class NewsClassifierHandler(BaseHandler): # pylint: disable=too-many-instance-a
|
|||
tokenizer = BertTokenizer(self.vocab_file)
|
||||
model_wrapper.eval()
|
||||
model_wrapper.zero_grad()
|
||||
input_ids = torch.tensor([
|
||||
input_ids = torch.tensor([ # pylint: disable=no-member
|
||||
tokenizer.encode(self.text, add_special_tokens=True)
|
||||
])
|
||||
input_ids = input_ids.to(self.device)
|
||||
|
|
@ -223,7 +225,9 @@ class NewsClassifierHandler(BaseHandler): # pylint: disable=too-many-instance-a
|
|||
return_convergence_delta=True,
|
||||
target=1,
|
||||
)
|
||||
tokens = tokenizer.convert_ids_to_tokens(input_ids[0].cpu().numpy().tolist())
|
||||
tokens = tokenizer.convert_ids_to_tokens(
|
||||
input_ids[0].cpu().numpy().tolist()
|
||||
)
|
||||
feature_imp_dict = {}
|
||||
feature_imp_dict["words"] = tokens
|
||||
attributions_sum = self.summarize_attributions(attributions)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ if __name__ == "__main__":
|
|||
parser = ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--dataset_url",
|
||||
default="https://kubeflow-dataset.s3.us-east-2.amazonaws.com/ag_news_csv.tar.gz",
|
||||
default=
|
||||
"https://kubeflow-dataset.s3.us-east-2.amazonaws.com/ag_news_csv.tar.gz", #pylint: disable=line-too-long
|
||||
type=str,
|
||||
help="URL to download AG News dataset",
|
||||
)
|
||||
|
|
@ -68,7 +69,9 @@ if __name__ == "__main__":
|
|||
print(run_code.stdout)
|
||||
|
||||
visualization_arguments = {
|
||||
"inputs": {"dataset_url": args["dataset_url"]},
|
||||
"inputs": {
|
||||
"dataset_url": args["dataset_url"]
|
||||
},
|
||||
"output": {
|
||||
"mlpipeline_ui_metadata": args["mlpipeline_ui_metadata"],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ class BertNewsClassifier(pl.LightningModule): #pylint: disable=too-many-ancesto
|
|||
output - Type of news for the given news snippet
|
||||
"""
|
||||
embedding_input = self.bert_model.embeddings(input_ids)
|
||||
# output = self.bert_model(input_ids=input_ids, attention_mask=attention_mask)
|
||||
outputs = self.compute_bert_outputs(self.bert_model, embedding_input)
|
||||
pooled_output = outputs[1]
|
||||
output = F.relu(self.fc1(pooled_output))
|
||||
|
|
@ -169,7 +168,7 @@ class BertNewsClassifier(pl.LightningModule): #pylint: disable=too-many-ancesto
|
|||
self.preds += y_hat.tolist()
|
||||
self.target += targets.tolist()
|
||||
self.log("test_acc", self.test_acc.compute())
|
||||
return {"test_acc": torch.tensor(test_acc)} #pylint: disable=not-callable
|
||||
return {"test_acc": torch.tensor(test_acc)} #pylint: disable=no-member
|
||||
|
||||
def validation_step(self, val_batch, batch_idx):
|
||||
"""Performs validation of data in batches.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ class NewsDataset(Dataset):
|
|||
item: Index of sample review
|
||||
|
||||
Returns:
|
||||
Returns the dictionary of review text, input ids, attention mask, targets
|
||||
Returns the dictionary of review text,
|
||||
input ids, attention mask, targets
|
||||
"""
|
||||
review = str(self.reviews[item])
|
||||
target = self.targets[item]
|
||||
|
|
|
|||
|
|
@ -57,10 +57,8 @@ class AGNewsmodelWrapper(nn.Module):
|
|||
if head_mask is not None:
|
||||
if head_mask.dim() == 1:
|
||||
head_mask = (
|
||||
head_mask.unsqueeze(0)
|
||||
.unsqueeze(0)
|
||||
.unsqueeze(-1)
|
||||
.unsqueeze(-1)
|
||||
head_mask.unsqueeze(0).unsqueeze(0).unsqueeze(-1).
|
||||
unsqueeze(-1)
|
||||
)
|
||||
head_mask = head_mask.expand(
|
||||
model_bert.config.num_hidden_layers, -1, -1, -1, -1
|
||||
|
|
|
|||
|
|
@ -11,29 +11,29 @@
|
|||
# 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.
|
||||
# pylint: disable=no-self-use,too-many-arguments,unused-argument,not-callable
|
||||
# pylint: disable=no-self-use,too-many-arguments,unused-argument,not-callable,no-member,attribute-defined-outside-init
|
||||
""" Cifar10 Custom Handler."""
|
||||
|
||||
from abc import ABC
|
||||
import io
|
||||
import os
|
||||
import base64
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from abc import ABC
|
||||
from base64 import b64encode
|
||||
from io import BytesIO
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
from PIL import Image
|
||||
from matplotlib.colors import LinearSegmentedColormap
|
||||
from captum.attr import visualization as viz
|
||||
from captum.attr import (
|
||||
IntegratedGradients, Occlusion, LayerGradCam, LayerAttribution
|
||||
)
|
||||
from ts.torch_handler.image_classifier import ImageClassifier
|
||||
from captum.attr import visualization as viz
|
||||
from classifier import CIFAR10CLASSIFIER
|
||||
import logging
|
||||
from matplotlib.colors import LinearSegmentedColormap
|
||||
from torchvision import transforms
|
||||
import torch
|
||||
from io import BytesIO
|
||||
from base64 import b64encode
|
||||
from matplotlib import pyplot as plt
|
||||
from ts.torch_handler.image_classifier import ImageClassifier
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ class CIFAR10Classification(ImageClassifier, ABC):
|
|||
Base class for all vision handlers
|
||||
"""
|
||||
|
||||
def initialize(self, ctx):
|
||||
def initialize(self, ctx): # pylint: disable=arguments-differ
|
||||
"""In this initialize function, the CIFAR10 trained model is loaded and
|
||||
the Integrated Gradients,occlusion and layer_gradcam Algorithm for
|
||||
Captum Explanations is initialized here.
|
||||
|
|
@ -73,8 +73,8 @@ class CIFAR10Classification(ImageClassifier, ABC):
|
|||
mapping_file_path = os.path.join(model_dir, "class_mapping.json")
|
||||
if os.path.isfile(mapping_file_path):
|
||||
print("Mapping file present")
|
||||
with open(mapping_file_path) as f:
|
||||
self.mapping = json.load(f)
|
||||
with open(mapping_file_path) as pointer:
|
||||
self.mapping = json.load(pointer)
|
||||
else:
|
||||
print("Mapping file missing")
|
||||
logger.warning("Missing the class_mapping.json file.")
|
||||
|
|
@ -96,8 +96,8 @@ class CIFAR10Classification(ImageClassifier, ABC):
|
|||
|
||||
def _get_img(self, row):
|
||||
"""Compat layer: normally the envelope should just return the data
|
||||
directly, but older version of KFServing envelope and Torchserve in general
|
||||
didn't have things set up right
|
||||
directly, but older version of KFServing envelope and
|
||||
Torchserve in general didn't have things set up right
|
||||
"""
|
||||
|
||||
if isinstance(row, dict):
|
||||
|
|
@ -112,11 +112,13 @@ class CIFAR10Classification(ImageClassifier, ABC):
|
|||
return image
|
||||
|
||||
def preprocess(self, data):
|
||||
"""The preprocess function of cifar10 program converts the input data to a float tensor
|
||||
"""The preprocess function of cifar10 program
|
||||
converts the input data to a float tensor
|
||||
Args:
|
||||
data (List): Input data from the request is in the form of a Tensor
|
||||
Returns:
|
||||
list : The preprocess function returns the input image as a list of float tensors.
|
||||
list : The preprocess function returns
|
||||
the input image as a list of float tensors.
|
||||
"""
|
||||
images = []
|
||||
|
||||
|
|
@ -136,13 +138,15 @@ class CIFAR10Classification(ImageClassifier, ABC):
|
|||
return torch.stack(images).to(self.device)
|
||||
|
||||
def attribute_image_features(self, algorithm, data, **kwargs):
|
||||
"""Calculate tensor attributions"""
|
||||
self.model.zero_grad()
|
||||
tensor_attributions = algorithm.attribute(data, target=0, **kwargs)
|
||||
return tensor_attributions
|
||||
|
||||
def output_bytes(self, fig):
|
||||
"""Convert image to bytes"""
|
||||
fout = BytesIO()
|
||||
fig.savefig(fout, format='png')
|
||||
fig.savefig(fout, format="png")
|
||||
fout.seek(0)
|
||||
return fout.getvalue()
|
||||
|
||||
|
|
|
|||
|
|
@ -281,4 +281,4 @@ if trainer.ptl_trainer.global_rank == 0:
|
|||
)
|
||||
|
||||
checpoint_dir_contents = os.listdir(CHECKPOINT_DIR)
|
||||
print(f"Checkpoint Directory Contents: {checpoint_dir_contents}")
|
||||
print(f"Checkpoint Directory Contents: {checpoint_dir_contents}")
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
import pandas as pd
|
||||
import json
|
||||
import os
|
||||
|
||||
from sklearn.metrics import confusion_matrix
|
||||
from io import StringIO
|
||||
import boto3
|
||||
|
||||
|
||||
class Visualization:
|
||||
def __init__(self):
|
||||
self.parser_args = None
|
||||
|
||||
def _generate_confusion_matrix_metadata(self, confusion_matrix_path, vocab):
|
||||
print("Generating Confusion matrix Metadata")
|
||||
metadata = {
|
||||
"type": "confusion_matrix",
|
||||
"format": "csv",
|
||||
"schema": [
|
||||
{"name": "target", "type": "CATEGORY"},
|
||||
{"name": "predicted", "type": "CATEGORY"},
|
||||
{"name": "count", "type": "NUMBER"},
|
||||
],
|
||||
"source": confusion_matrix_path,
|
||||
# Convert vocab to string because for bealean values we want "True|False" to match csv data.
|
||||
"labels": list(map(str, vocab)),
|
||||
}
|
||||
self._write_ui_metadata(
|
||||
metadata_filepath="/mlpipeline-ui-metadata.json", metadata_dict=metadata
|
||||
)
|
||||
|
||||
def _write_ui_metadata(self, metadata_filepath, metadata_dict, key="outputs"):
|
||||
if not os.path.exists(metadata_filepath):
|
||||
metadata = {key: [metadata_dict]}
|
||||
else:
|
||||
with open(metadata_filepath) as fp:
|
||||
metadata = json.load(fp)
|
||||
metadata_outputs = metadata[key]
|
||||
metadata_outputs.append(metadata_dict)
|
||||
|
||||
print("Writing to file: {}".format(metadata_filepath))
|
||||
with open(metadata_filepath, "w") as fp:
|
||||
json.dump(metadata, fp)
|
||||
|
||||
def _enable_tensorboard_visualization(self, tensorboard_root):
|
||||
print("Enabling Tensorboard Visualization")
|
||||
metadata = {
|
||||
"type": "tensorboard",
|
||||
"source": tensorboard_root,
|
||||
}
|
||||
|
||||
import os
|
||||
|
||||
os.environ["AWS_REGION"] = "us-east-2"
|
||||
|
||||
self._write_ui_metadata(
|
||||
metadata_filepath="/mlpipeline-ui-metadata.json", metadata_dict=metadata
|
||||
)
|
||||
|
||||
def _visualize_accuracy_metric(self, accuracy):
|
||||
metadata = {
|
||||
"name": "accuracy-score",
|
||||
"numberValue": accuracy,
|
||||
"format": "PERCENTAGE",
|
||||
}
|
||||
self._write_ui_metadata(
|
||||
metadata_filepath="/mlpipeline-metrics.json", metadata_dict=metadata, key="metrics"
|
||||
)
|
||||
|
||||
def _generate_confusion_matrix(self, confusion_matrix_dict):
|
||||
actuals = confusion_matrix_dict["actuals"]
|
||||
preds = confusion_matrix_dict["preds"]
|
||||
|
||||
bucket_name = confusion_matrix_dict["bucket_name"]
|
||||
folder_name = confusion_matrix_dict["folder_name"]
|
||||
|
||||
# Generating confusion matrix
|
||||
df = pd.DataFrame(list(zip(actuals, preds)), columns=["target", "predicted"])
|
||||
vocab = list(df["target"].unique())
|
||||
cm = confusion_matrix(df["target"], df["predicted"], labels=vocab)
|
||||
data = []
|
||||
for target_index, target_row in enumerate(cm):
|
||||
for predicted_index, count in enumerate(target_row):
|
||||
data.append((vocab[target_index], vocab[predicted_index], count))
|
||||
|
||||
confusion_matrix_df = pd.DataFrame(data, columns=["target", "predicted", "count"])
|
||||
|
||||
confusion_matrix_key = os.path.join(folder_name, "confusion_df.csv")
|
||||
|
||||
# Logging confusion matrix to ss3
|
||||
csv_buffer = StringIO()
|
||||
confusion_matrix_df.to_csv(csv_buffer, index=False, header=False)
|
||||
s3_resource = boto3.resource("s3")
|
||||
s3_resource.Object(bucket_name, confusion_matrix_key).put(Body=csv_buffer.getvalue())
|
||||
|
||||
# Generating metadata
|
||||
confusion_matrix_s3_path = s3_path = "s3://" + bucket_name + "/" + confusion_matrix_key
|
||||
self._generate_confusion_matrix_metadata(confusion_matrix_s3_path, vocab)
|
||||
|
||||
def generate_visualization(
|
||||
self, tensorboard_root=None, accuracy=None, confusion_matrix_dict=None
|
||||
):
|
||||
print("Tensorboard Root: {}".format(tensorboard_root))
|
||||
print("Accuracy: {}".format(accuracy))
|
||||
|
||||
if tensorboard_root:
|
||||
self._enable_tensorboard_visualization(tensorboard_root)
|
||||
|
||||
if accuracy:
|
||||
self._visualize_accuracy_metric(accuracy=accuracy)
|
||||
|
||||
if confusion_matrix_dict:
|
||||
self._generate_confusion_matrix(confusion_matrix_dict=confusion_matrix_dict)
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Utility to upload files/folders into minio"""
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
from pytorch_kfp_components.components.minio.component import MinIO
|
||||
|
|
@ -72,7 +73,12 @@ print("File to be uploaded: {}".format(input_path))
|
|||
|
||||
print("Uploading file to : {}".format(folder_name))
|
||||
|
||||
MinIO(source=input_path, bucket_name=bucket_name, destination=folder_name, endpoint=endpoint)
|
||||
MinIO(
|
||||
source=input_path,
|
||||
bucket_name=bucket_name,
|
||||
destination=folder_name,
|
||||
endpoint=endpoint
|
||||
)
|
||||
|
||||
inputs = {}
|
||||
|
||||
|
|
@ -88,7 +94,7 @@ if filename:
|
|||
|
||||
outputs["minio_url"] = s3_url
|
||||
|
||||
visualization_arguments = {"inputs" : inputs, "outputs" : outputs}
|
||||
visualization_arguments = {"inputs": inputs, "outputs": outputs}
|
||||
|
||||
markdown_dict = {"storage": "inline", "source": visualization_arguments}
|
||||
|
||||
|
|
@ -96,4 +102,3 @@ visualization = Visualization(
|
|||
mlpipeline_ui_metadata=args["mlpipeline_ui_metadata"],
|
||||
markdown=markdown_dict,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
#!/usr/bin/env/python3
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
# 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.
|
||||
"""Utility to generate timestamp"""
|
||||
from datetime import datetime
|
||||
|
||||
dateTimeObj = datetime.now()
|
||||
timestampStr = dateTimeObj.strftime("%d-%m-%Y-%H-%M-%S.%f")
|
||||
print(timestampStr, end='')
|
||||
print(timestampStr, end="")
|
||||
|
|
|
|||
|
|
@ -1,19 +1,37 @@
|
|||
#!/usr/bin/env/python3
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
# 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.
|
||||
"""Generate component.yaml from templates"""
|
||||
import json
|
||||
import os
|
||||
import yaml
|
||||
import shutil
|
||||
import sys
|
||||
import json
|
||||
|
||||
import yaml
|
||||
|
||||
CURRENT_FOLDER = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
PIPELINES_HOME = os.path.join(CURRENT_FOLDER.split("pipelines")[0], "pipelines")
|
||||
|
||||
TEMPLATE_PATH = os.path.join(PIPELINES_HOME, "components/PyTorch/pytorch-kfp-components/templates")
|
||||
TEMPLATE_PATH = os.path.join(
|
||||
PIPELINES_HOME, "components/PyTorch/pytorch-kfp-components/templates"
|
||||
)
|
||||
|
||||
OUTPUT_YAML_FOLDER = "yaml"
|
||||
|
||||
|
||||
def create_output_folder():
|
||||
"""Removes the `yaml` folder and recreates it"""
|
||||
if os.path.exists(OUTPUT_YAML_FOLDER):
|
||||
shutil.rmtree(OUTPUT_YAML_FOLDER)
|
||||
|
||||
|
|
@ -21,13 +39,15 @@ def create_output_folder():
|
|||
|
||||
|
||||
def get_templates_list():
|
||||
"""Get the list of template files from `templates` directory"""
|
||||
assert os.path.exists(TEMPLATE_PATH)
|
||||
templates_list = os.listdir(TEMPLATE_PATH)
|
||||
return templates_list
|
||||
|
||||
|
||||
def read_template(template_path: str):
|
||||
with open(template_path, 'r') as stream:
|
||||
"""Read the `componanent.yaml` template"""
|
||||
with open(template_path, "r") as stream:
|
||||
try:
|
||||
template_dict = yaml.safe_load(stream)
|
||||
except yaml.YAMLError as exc:
|
||||
|
|
@ -37,6 +57,7 @@ def read_template(template_path: str):
|
|||
|
||||
|
||||
def replace_keys_in_template(template_dict: dict, mapping: dict):
|
||||
"""Replace the keys, values in `component.yaml` based on `mapping` dict"""
|
||||
|
||||
# Sample mapping will be as below
|
||||
# { "implementation.container.image" : "image_name" }
|
||||
|
|
@ -44,7 +65,7 @@ def replace_keys_in_template(template_dict: dict, mapping: dict):
|
|||
|
||||
# parse through each nested key
|
||||
|
||||
keys = nested_key.split('.')
|
||||
keys = nested_key.split(".")
|
||||
accessable = template_dict
|
||||
for k in keys[:-1]:
|
||||
accessable = accessable[k]
|
||||
|
|
@ -54,16 +75,17 @@ def replace_keys_in_template(template_dict: dict, mapping: dict):
|
|||
|
||||
|
||||
def write_to_yaml_file(template_dict: dict, yaml_path: str):
|
||||
with open(yaml_path, 'w') as fp:
|
||||
yaml.dump(template_dict, fp)
|
||||
"""Write yaml output into file"""
|
||||
with open(yaml_path, "w") as pointer:
|
||||
yaml.dump(template_dict, pointer)
|
||||
|
||||
|
||||
def generate_component_yaml(mapping_template_path: str):
|
||||
|
||||
"""Method to generate component.yaml based on the template"""
|
||||
mapping: dict = {}
|
||||
if os.path.exists(mapping_template_path):
|
||||
with open(mapping_template_path) as fp:
|
||||
mapping = json.load(fp)
|
||||
with open(mapping_template_path) as pointer:
|
||||
mapping = json.load(pointer)
|
||||
create_output_folder()
|
||||
template_list = get_templates_list()
|
||||
|
||||
|
|
@ -87,9 +109,12 @@ def generate_component_yaml(mapping_template_path: str):
|
|||
write_to_yaml_file(template_dict=template_dict, yaml_path=dest)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
raise Exception("\n\nUsage: "
|
||||
"python utils/generate_templates.py cifar10/template_mapping.json\n\n")
|
||||
mapping_template_path = sys.argv[1]
|
||||
generate_component_yaml(mapping_template_path=mapping_template_path)
|
||||
raise Exception(
|
||||
"\n\nUsage: "
|
||||
"python utils/generate_templates.py "
|
||||
"cifar10/template_mapping.json\n\n"
|
||||
)
|
||||
input_template_path = sys.argv[1]
|
||||
generate_component_yaml(mapping_template_path=input_template_path)
|
||||
|
|
|
|||
Loading…
Reference in New Issue