diff --git a/build/kb/Dockerfile b/build/kb/Dockerfile index 1a6f973c..c3f62970 100644 --- a/build/kb/Dockerfile +++ b/build/kb/Dockerfile @@ -12,15 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM python:3.6-slim +FROM python:3.9-slim RUN pip install colorlog~=4.7.2 RUN pip install PyYAML~=5.4.1 RUN pip install fastapi~=0.63.0 RUN pip install starlette~=0.13.6 RUN pip install pydantic~=1.8.1 -RUN pip install joblib~=1.0.1 -RUN pip install pandas~=1.1.5 +RUN pip install joblib~=1.2.0 +RUN pip install pandas RUN pip install uvicorn~=0.14.0 RUN pip install python-multipart~=0.0.5 RUN pip install SQLAlchemy~=1.4.7 diff --git a/examples/lifelong-learning-atcii-classifier.Dockerfile b/examples/lifelong-learning-atcii-classifier.Dockerfile index a1d672bc..727aa115 100644 --- a/examples/lifelong-learning-atcii-classifier.Dockerfile +++ b/examples/lifelong-learning-atcii-classifier.Dockerfile @@ -2,9 +2,9 @@ FROM python:3.6-slim COPY ./lib/requirements.txt /home # install requirements of sedna lib +RUN pip install --upgrade pip RUN pip install -r /home/requirements.txt RUN pip install joblib~=1.0.1 -RUN pip install pandas~=1.1.5 RUN pip install scikit-learn~=0.24.1 RUN pip install xgboost~=1.3.3 diff --git a/examples/lifelong-learning-robo-rfnet.Dockerfile b/examples/lifelong-learning-cityscapes-segmentation.Dockerfile similarity index 74% rename from examples/lifelong-learning-robo-rfnet.Dockerfile rename to examples/lifelong-learning-cityscapes-segmentation.Dockerfile index 1d784dae..e8557d6b 100644 --- a/examples/lifelong-learning-robo-rfnet.Dockerfile +++ b/examples/lifelong-learning-cityscapes-segmentation.Dockerfile @@ -10,16 +10,11 @@ COPY ./lib/requirements.dev.txt /home # install requirements of sedna lib RUN pip install -r /home/requirements.txt RUN pip install -r /home/requirements.dev.txt -RUN pip install joblib~=1.2.0 -RUN pip install pandas -RUN pip install scikit-learn~=0.23.2 RUN pip install torchvision~=0.13.0 RUN pip install Pillow RUN pip install tqdm -RUN pip install minio RUN pip install protobuf~=3.20.1 RUN pip install matplotlib -RUN pip install opencv-python RUN pip install python-multipart RUN pip install tensorboard RUN pip install watchdog @@ -29,7 +24,7 @@ ENV PYTHONPATH "/home/lib" WORKDIR /home/work COPY ./lib /home/lib -COPY ./examples/lifelong_learning/robot_dog_delivery /home/work/ +COPY ./examples/lifelong_learning/cityscapes /home/work/ WORKDIR /home/work/RFNet ENTRYPOINT ["python"] \ No newline at end of file diff --git a/examples/lifelong_learning/cityscapes/README.md b/examples/lifelong_learning/cityscapes/README.md new file mode 100644 index 00000000..465d0419 --- /dev/null +++ b/examples/lifelong_learning/cityscapes/README.md @@ -0,0 +1,266 @@ +# Using Lifelong Learning in Campus Robot Delivery Scenario + +## Introduction +This example introduces how to use Sedna lifelong learning to implement the lifelong learning delivery task of the robot in a campus. Based on open source project [RFNet](https://github.com/AHupuJR/RFNet) as base model, we realize intelligent perception of environment with Sedna lifelong learning in this example. + +The demo mainly shows: +1. Lifelong learning unseen task recognition algorithm (prediction) can identify and collect unseen task samples. +2. Lifelong learning unseen task recognition algorithm (detection) can trigger alarms to remind robot admin that emergency response is required. +3. Lifelong learning unseen task training algorithm improves the inference accuracy of known categories and the ability to identify new categories. + +### Install Sedna +Follow the [Sedna installation document](/docs/setup/install.md) to install Sedna. + +### Configurations + +#### Prepare Images +This example uses the following images: +- Training worker: kubeedge/sedna-example-lifelong-learning-cityscapes-segmentation:v0.6.0 +- Evaluation worker: kubeedge/sedna-example-lifelong-learning-cityscapes-segmentation:v0.6.0 +- Inference worker: kubeedge/sedna-example-lifelong-learning-cityscapes-segmentation:v0.6.0 + +These images are generated by the script [build_images.sh](/examples/build_image.sh). + +Users can also generate customized images for different workers and config them in yaml which will be presented in the following steps. + +#### Prepare user nodes +``` +WORKER_NODE=sedna-mini-control-plane + +DATA_NODE=$WORKER_NODE +TRAIN_NODE=$WORKER_NODE +EVAL_NODE=$WORKER_NODE +INFER_NODE=$WORKER_NODE +``` + +Particularly, data node, train node, eval node and infer node are custom codes which can be specified by users for actual running. Here, for simplicity, we use the same node to demonstrate. + +#### Prepare Dataset + +Step 1: Users can use semantic segmentation datasets from [CITYSCAPES](https://www.cityscapes-dataset.com/). While we also provide a re-organized [dataset segmentation_data.zip](https://kubeedge.obs.cn-north-1.myhuaweicloud.com/examples/robo_dog_delivery/segmentation_data.zip) of CITYSCAPES as an example for training and evaluation. + +Download and unzip segmentation_data.zip. Put it into /data of ```$DATA_NODE```. Or you can use ```docker exec``` to get into ```$DATA_NODE``` and then execute the following commands. +``` +mkdir /data +cd /data +wget https://kubeedge.obs.cn-north-1.myhuaweicloud.com/examples/robo_dog_delivery/segmentation_data.zip +unzip segmentation_data.zip +``` + +Step 2: download [test data](https://kubeedge.obs.cn-north-1.myhuaweicloud.com/examples/robo_dog_delivery/test_data.zip) which is for demonstration at the inference stage, unzip test_data.zip and put it into /data of ```$INFER_NODE```. Or you can use ```docker exec``` to get into ```$INFER_NODE``` and then execute the following commands. +``` +mkdir /data +cd /data +wget https://kubeedge.obs.cn-north-1.myhuaweicloud.com/examples/robo_dog_delivery/test_data.zip +unzip test_data.zip +``` + +After finishing the above preparations, execute the following commands to config. +``` +local_prefix=/data +cloud_image=kubeedge/sedna-example-lifelong-learning-cityscapes-segmentation:v0.6.0 +edge_image=kubeedge/sedna-example-lifelong-learning-cityscapes-segmentation:v0.6.0 +data_url=$local_prefix/segmentation_data/data.txt +OUTPUT=$local_prefix/lifelonglearningjob/output +job_name=robo-demo +``` + +### Create Lifelong Learning Job + +#### Create Initial Dataset Resource +``` +kubectl create -f - <" + threshold: 100 + metric: num_of_samples + evalSpec: + template: + spec: + nodeName: $EVAL_NODE + dnsPolicy: ClusterFirstWithHostNet + containers: + - image: $cloud_image + name: eval-worker + imagePullPolicy: IfNotPresent + args: ["evaluate.py"] + env: + - name: "operator" + value: "<" + - name: "model_threshold" + value: "0" + - name: "num_class" + value: "24" + - name: "BACKEND_TYPE" + value: "PYTORCH" + resources: + limits: + cpu: 6 + memory: 12Gi + requests: + cpu: 4 + memory: 12Gi + deploySpec: + template: + spec: + nodeName: $INFER_NODE + dnsPolicy: ClusterFirstWithHostNet + hostNetwork: true + containers: + - image: $edge_image + name: infer-worker + imagePullPolicy: IfNotPresent + args: ["predict.py"] + env: + - name: "test_data" + value: "/data/test_data" + - name: "num_class" + value: "24" + - name: "unseen_save_url" + value: "/data/unseen_samples" + - name: "INFERENCE_RESULT_DIR" + value: "/data/infer_results" + - name: "BACKEND_TYPE" + value: "PYTORCH" + volumeMounts: + - name: unseenurl + mountPath: /data/unseen_samples + - name: inferdata + mountPath: /data/infer_results + - name: testdata + mountPath: /data/test_data + resources: + limits: + cpu: 6 + memory: 12Gi + requests: + cpu: 4 + memory: 12Gi + volumes: + - name: unseenurl + hostPath: + path: /data/unseen_samples + type: DirectoryOrCreate + - name: inferdata + hostPath: + path: /data/infer_results + type: DirectoryOrCreate + - name: testdata + hostPath: + path: /data/test_data + type: DirectoryOrCreate + outputDir: $OUTPUT/$job_name +EOF +``` + +### Check Lifelong Learning Status + +``` +kubectl get lifelonglearningjob +``` + +### Effect Display + +#### Evaluation results of two round lifelong learning + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoundsMetrics
Pixel Accuracy Class (CPA)Mean Intersection over Union (mIoU)Frequency Weighted Intersection over Union (FWIoU)
Round 10.3850.3190.648
Round 20.4020.3390.659
+ +#### Segmentation inference display +![Inference sample](./RFNet/images/2086.png) | ![Segementation display](./RFNet/images/2086_color.png)|![Merge](./RFNet/images/2086_merge.png) +---|---|--- + + + + + + + \ No newline at end of file diff --git a/examples/lifelong_learning/cityscapes/RFNet/accuracy.py b/examples/lifelong_learning/cityscapes/RFNet/accuracy.py new file mode 100644 index 00000000..a6666bdc --- /dev/null +++ b/examples/lifelong_learning/cityscapes/RFNet/accuracy.py @@ -0,0 +1,54 @@ +# Copyright 2023 The KubeEdge 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. + +from tqdm import tqdm +from sedna.common.class_factory import ClassType, ClassFactory +from sedna.common.log import LOGGER + +from utils.args import EvaluationArguments +from utils.metrics import Evaluator +from dataloaders import make_data_loader + +__all__ = ('accuracy', ) + + +@ClassFactory.register(ClassType.GENERAL) +def accuracy(y_true, y_pred, **kwargs): + args = EvaluationArguments() + _, _, test_loader = make_data_loader(args, test_data=y_true) + evaluator = Evaluator(args.num_class) + + tbar = tqdm(test_loader, desc='\r') + for i, (sample, _) in enumerate(tbar): + if args.depth: + image, depth, target = sample['image'], sample['depth'], sample['label'] + else: + image, target = sample['image'], sample['label'] + if args.cuda: + image, target = image.cuda(), target.cuda() + if args.depth: + depth = depth.cuda() + + target[target > evaluator.num_class - 1] = 255 + target = target.cpu().numpy() + # Add batch sample into evaluator + evaluator.add_batch(target, y_pred[i]) + + # Test during the training + CPA = evaluator.Pixel_Accuracy_Class() + mIoU = evaluator.Mean_Intersection_over_Union() + FWIoU = evaluator.Frequency_Weighted_Intersection_over_Union() + + LOGGER.info("CPA:{}, mIoU:{}, fwIoU: {}".format(CPA, mIoU, FWIoU)) + return mIoU diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/__init__.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/__init__.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/__init__.py rename to examples/lifelong_learning/cityscapes/RFNet/dataloaders/__init__.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms.py similarity index 87% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms.py rename to examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms.py index d63f200a..56c66729 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms.py +++ b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms.py @@ -1,15 +1,16 @@ import torch import random import numpy as np - from PIL import Image, ImageOps, ImageFilter + class Normalize(object): """Normalize a tensor image with mean and standard deviation. Args: mean (tuple): means for each channel. std (tuple): standard deviations for each channel. """ + def __init__(self, mean=(0., 0., 0.), std=(1., 1., 1.)): self.mean = mean self.std = std @@ -60,10 +61,12 @@ class ToTensor(object): 'depth': depth, 'label': mask} + class CropBlackArea(object): """ crop black area for depth image """ + def __call__(self, sample): img = sample['image'] depth = sample['depth'] @@ -78,12 +81,9 @@ class CropBlackArea(object): depth = depth.crop((left, top, right, bottom)) mask = mask.crop((left, top, right, bottom)) # resize - img = img.resize((width,height), Image.BILINEAR) - depth = depth.resize((width,height), Image.BILINEAR) - mask = mask.resize((width,height), Image.NEAREST) - # img = img.resize((512,1024), Image.BILINEAR) - # depth = depth.resize((512,1024), Image.BILINEAR) - # mask = mask.resize((512,1024), Image.NEAREST) + img = img.resize((width, height), Image.BILINEAR) + depth = depth.resize((width, height), Image.BILINEAR) + mask = mask.resize((width, height), Image.NEAREST) return {'image': img, 'depth': depth, @@ -148,7 +148,8 @@ class RandomScaleCrop(object): depth = sample['depth'] mask = sample['label'] # random scale (short edge) - short_size = random.randint(int(self.base_size * 0.5), int(self.base_size * 2.0)) + short_size = random.randint( + int(self.base_size * 0.5), int(self.base_size * 2.0)) w, h = img.size if h > w: ow = short_size @@ -164,8 +165,10 @@ class RandomScaleCrop(object): padh = self.crop_size - oh if oh < self.crop_size else 0 padw = self.crop_size - ow if ow < self.crop_size else 0 img = ImageOps.expand(img, border=(0, 0, padw, padh), fill=0) - depth = ImageOps.expand(depth, border=(0, 0, padw, padh), fill=0) # depth多余的部分填0 - mask = ImageOps.expand(mask, border=(0, 0, padw, padh), fill=self.fill) + depth = ImageOps.expand(depth, border=( + 0, 0, padw, padh), fill=0) + mask = ImageOps.expand(mask, border=( + 0, 0, padw, padh), fill=self.fill) # random crop crop_size w, h = img.size x1 = random.randint(0, w - self.crop_size) @@ -209,9 +212,11 @@ class FixScaleCrop(object): 'depth': depth, 'label': mask} + class FixedResize(object): def __init__(self, size): - self.size = (size, size) # size: (h, w) + # size: (h, w) + self.size = (size, size) def __call__(self, sample): img = sample['image'] @@ -228,13 +233,13 @@ class FixedResize(object): 'depth': depth, 'label': mask} + class Relabel(object): - def __init__(self, olabel, nlabel): # change trainid label from olabel to nlabel + def __init__(self, olabel, nlabel): + # change trainid label from olabel to nlabel self.olabel = olabel self.nlabel = nlabel def __call__(self, tensor): - # assert (isinstance(tensor, torch.LongTensor) or isinstance(tensor, - # torch.ByteTensor)), 'tensor needs to be LongTensor' tensor[tensor == self.olabel] = self.nlabel - return tensor \ No newline at end of file + return tensor diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms_rgb.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms_rgb.py similarity index 88% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms_rgb.py rename to examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms_rgb.py index e04ef5a3..d7c5d3d3 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/custom_transforms_rgb.py +++ b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/custom_transforms_rgb.py @@ -4,12 +4,14 @@ import numpy as np from PIL import Image, ImageOps, ImageFilter + class Normalize(object): """Normalize a tensor image with mean and standard deviation. Args: mean (tuple): means for each channel. std (tuple): standard deviations for each channel. """ + def __init__(self, mean=(0., 0., 0.), std=(1., 1., 1.)): self.mean = mean self.std = std @@ -60,10 +62,12 @@ class ToTensor(object): return {'image': img, 'label': mask} + class CropBlackArea(object): """ crop black area for depth image """ + def __call__(self, sample): img = sample['image'] mask = sample['label'] @@ -76,15 +80,13 @@ class CropBlackArea(object): img = img.crop((left, top, right, bottom)) mask = mask.crop((left, top, right, bottom)) # resize - img = img.resize((width,height), Image.BILINEAR) - mask = mask.resize((width,height), Image.NEAREST) - # img = img.resize((512,1024), Image.BILINEAR) - # mask = mask.resize((512,1024), Image.NEAREST) - print(img.size) + img = img.resize((width, height), Image.BILINEAR) + mask = mask.resize((width, height), Image.NEAREST) return {'image': img, 'label': mask} + class ToTensor_test(object): """Convert Image object in sample to Tensors.""" @@ -149,7 +151,8 @@ class RandomScaleCrop(object): img = sample['image'] mask = sample['label'] # random scale (short edge) - short_size = random.randint(int(self.base_size * 0.5), int(self.base_size * 2.0)) + short_size = random.randint( + int(self.base_size * 0.5), int(self.base_size * 2.0)) w, h = img.size if h > w: ow = short_size @@ -164,7 +167,8 @@ class RandomScaleCrop(object): padh = self.crop_size - oh if oh < self.crop_size else 0 padw = self.crop_size - ow if ow < self.crop_size else 0 img = ImageOps.expand(img, border=(0, 0, padw, padh), fill=0) - mask = ImageOps.expand(mask, border=(0, 0, padw, padh), fill=self.fill) + mask = ImageOps.expand(mask, border=( + 0, 0, padw, padh), fill=self.fill) # random crop crop_size w, h = img.size x1 = random.randint(0, w - self.crop_size) @@ -202,9 +206,11 @@ class FixScaleCrop(object): return {'image': img, 'label': mask} + class FixedResize(object): def __init__(self, size): - self.size = (size, size) # size: (h, w) + # size: (h, w) + self.size = (size, size) def __call__(self, sample): img = sample['image'] @@ -218,13 +224,13 @@ class FixedResize(object): return {'image': img, 'label': mask} + class Relabel(object): - def __init__(self, olabel, nlabel): # change trainid label from olabel to nlabel + def __init__(self, olabel, nlabel): + # change trainid label from olabel to nlabel self.olabel = olabel self.nlabel = nlabel def __call__(self, tensor): - # assert (isinstance(tensor, torch.LongTensor) or isinstance(tensor, - # torch.ByteTensor)), 'tensor needs to be LongTensor' tensor[tensor == self.olabel] = self.nlabel - return tensor \ No newline at end of file + return tensor diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/datasets/__init__.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/datasets/__init__.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/datasets/__init__.py rename to examples/lifelong_learning/cityscapes/RFNet/dataloaders/datasets/__init__.py diff --git a/examples/lifelong_learning/cityscapes/RFNet/dataloaders/datasets/cityscapes.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/datasets/cityscapes.py new file mode 100644 index 00000000..b9cb65ee --- /dev/null +++ b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/datasets/cityscapes.py @@ -0,0 +1,116 @@ +import os + +from PIL import Image +from torch.utils import data +from torchvision import transforms + +from dataloaders import custom_transforms as tr + + +class CityscapesSegmentation(data.Dataset): + + def __init__(self, args, data=None, split="train"): + + self.split = split + self.args = args + self.images = {} + self.disparities = {} + self.labels = {} + + self.images[split] = [img[0] + for img in data.x] if hasattr(data, "x") else data + + if hasattr(data, "x") and len(data.x[0]) == 1: + self.disparities[split] = self.images[split] + elif hasattr(data, "x") and len(data.x[0]) == 2: + self.disparities[split] = [img[1] for img in data.x] + else: + self.disparities[split] = data + + self.labels[split] = data.y if hasattr(data, "y") else data + + self.ignore_index = 255 + + if len(self.images[split]) == 0: + raise Exception("No RGB images for split=[%s] found in %s" % ( + split, self.images_base)) + if len(self.disparities[split]) == 0: + raise Exception("No depth images for split=[%s] found in %s" % ( + split, self.disparities_base)) + + print("Found %d %s RGB images" % (len(self.images[split]), split)) + print("Found %d %s disparity images" % + (len(self.disparities[split]), split)) + + def __len__(self): + return len(self.images[self.split]) + + def __getitem__(self, index): + img_path = self.images[self.split][index].rstrip() + disp_path = self.disparities[self.split][index].rstrip() + try: + lbl_path = self.labels[self.split][index].rstrip() + _img = Image.open(img_path).convert('RGB').resize( + self.args.image_size, Image.BILINEAR) + _depth = Image.open(disp_path).resize( + self.args.image_size, Image.BILINEAR) + _target = Image.open(lbl_path).resize( + self.args.image_size, Image.BILINEAR) + + sample = {'image': _img, 'depth': _depth, 'label': _target} + except: + _img = Image.open(img_path).convert('RGB').resize( + self.args.image_size, Image.BILINEAR) + _depth = Image.open(disp_path).resize( + self.args.image_size, Image.BILINEAR) + + sample = {'image': _img, 'depth': _depth, 'label': _img} + + if self.split == 'train': + return self.transform_tr(sample) + elif self.split == 'val': + return self.transform_val(sample), img_path + elif self.split == 'test': + return self.transform_ts(sample), img_path + elif self.split == 'custom_resize': + return self.transform_ts(sample), img_path + + def recursive_glob(self, rootdir='.', suffix=''): + """Performs recursive glob with given suffix and rootdir + :param rootdir is the root directory + :param suffix is the suffix to be searched + """ + return [os.path.join(looproot, filename) + for looproot, _, filenames in os.walk(rootdir) + for filename in filenames if filename.endswith(suffix)] + + def transform_tr(self, sample): + composed_transforms = transforms.Compose([ + tr.CropBlackArea(), + tr.RandomHorizontalFlip(), + tr.RandomScaleCrop(base_size=self.args.base_size, + crop_size=self.args.crop_size, fill=255), + tr.Normalize(mean=(0.485, 0.456, 0.406), + std=(0.229, 0.224, 0.225)), + tr.ToTensor()]) + + return composed_transforms(sample) + + def transform_val(self, sample): + + composed_transforms = transforms.Compose([ + tr.CropBlackArea(), + tr.Normalize(mean=(0.485, 0.456, 0.406), + std=(0.229, 0.224, 0.225)), + tr.ToTensor()]) + + return composed_transforms(sample) + + def transform_ts(self, sample): + + composed_transforms = transforms.Compose([ + tr.Normalize(mean=(0.485, 0.456, 0.406), + std=(0.229, 0.224, 0.225)), + tr.ToTensor()]) + + return composed_transforms(sample) diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/utils.py b/examples/lifelong_learning/cityscapes/RFNet/dataloaders/utils.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/utils.py rename to examples/lifelong_learning/cityscapes/RFNet/dataloaders/utils.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/eval.py b/examples/lifelong_learning/cityscapes/RFNet/estimators/eval.py similarity index 94% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/eval.py rename to examples/lifelong_learning/cityscapes/RFNet/estimators/eval.py index 1a5342bd..7f10f510 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/eval.py +++ b/examples/lifelong_learning/cityscapes/RFNet/estimators/eval.py @@ -102,7 +102,7 @@ class Validator(object): self.args.merge_label_save_path, img_name) os.makedirs(os.path.dirname(merge_label_name), exist_ok=True) pre_color_image = ToPILImage()( - pre_colors[i]) # pre_colors.dtype = float64 + pre_colors[i]) image_merge(image[i], pre_color_image, merge_label_name) if not self.args.save_predicted_image: @@ -113,8 +113,6 @@ class Validator(object): os.makedirs(os.path.dirname(color_label_name), exist_ok=True) os.makedirs(os.path.dirname(label_name), exist_ok=True) - # color = paint_trapezoid(np.array(pre_color_image)) - # cv2.imwrite(color_label_name, color) pre_color_image.save(color_label_name) pre_label_image = ToPILImage()(pre_labels[i]) diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/train.py b/examples/lifelong_learning/cityscapes/RFNet/estimators/train.py similarity index 97% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/train.py rename to examples/lifelong_learning/cityscapes/RFNet/estimators/train.py index 85b4489a..ca7f02d5 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/estimators/train.py +++ b/examples/lifelong_learning/cityscapes/RFNet/estimators/train.py @@ -218,3 +218,5 @@ class Trainer(object): 'optimizer': self.optimizer.state_dict(), 'best_pred': self.best_pred, }, is_best) + + return new_pred diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/evaluate.py b/examples/lifelong_learning/cityscapes/RFNet/evaluate.py similarity index 65% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/evaluate.py rename to examples/lifelong_learning/cityscapes/RFNet/evaluate.py index dbcdeda5..95edd90c 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/evaluate.py +++ b/examples/lifelong_learning/cityscapes/RFNet/evaluate.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 from sedna.core.lifelong_learning import LifelongLearning @@ -5,7 +19,7 @@ from sedna.datasources import TxtDataParse from sedna.common.config import Context from accuracy import accuracy -from basemodel import Model +from interface import Estimator def _load_txt_dataset(dataset_url): @@ -20,13 +34,13 @@ def _load_txt_dataset(dataset_url): def eval(): - estimator = Model(num_class=31) + estimator = Estimator(num_class=Context.get_parameters("num_class", 24)) eval_dataset_url = Context.get_parameters("test_dataset_url") eval_data = TxtDataParse(data_type="eval", func=_load_txt_dataset) eval_data.parse(eval_dataset_url, use_raw=False) task_allocation = { - "method": "TaskAllocationSimple" + "method": "TaskAllocationByOrigin" } ll_job = LifelongLearning(estimator, diff --git a/examples/lifelong_learning/cityscapes/RFNet/images/2086.png b/examples/lifelong_learning/cityscapes/RFNet/images/2086.png new file mode 100644 index 00000000..d8ebf284 Binary files /dev/null and b/examples/lifelong_learning/cityscapes/RFNet/images/2086.png differ diff --git a/examples/lifelong_learning/cityscapes/RFNet/images/2086_color.png b/examples/lifelong_learning/cityscapes/RFNet/images/2086_color.png new file mode 100644 index 00000000..9d30ce98 Binary files /dev/null and b/examples/lifelong_learning/cityscapes/RFNet/images/2086_color.png differ diff --git a/examples/lifelong_learning/cityscapes/RFNet/images/2086_merge.png b/examples/lifelong_learning/cityscapes/RFNet/images/2086_merge.png new file mode 100644 index 00000000..697cf3f7 Binary files /dev/null and b/examples/lifelong_learning/cityscapes/RFNet/images/2086_merge.png differ diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/basemodel.py b/examples/lifelong_learning/cityscapes/RFNet/interface.py similarity index 56% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/basemodel.py rename to examples/lifelong_learning/cityscapes/RFNet/interface.py index 4db22181..09e80752 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/basemodel.py +++ b/examples/lifelong_learning/cityscapes/RFNet/interface.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 cv2 @@ -8,7 +22,6 @@ from torchvision import transforms from torch.utils.data import DataLoader from torchvision import transforms from sedna.common.config import Context -from sedna.datasources import TxtDataParse from sedna.common.file_ops import FileOps from sedna.common.log import LOGGER from sedna.common.config import BaseConfig @@ -17,9 +30,7 @@ from dataloaders import custom_transforms as tr from utils.args import TrainingArguments, EvaluationArguments from estimators.train import Trainer from estimators.eval import Validator, load_my_state_dict -from accuracy import robo_accuracy - -os.environ["BACKEND_TYPE"] = '' +from accuracy import accuracy def preprocess_url(image_urls): @@ -39,8 +50,6 @@ def preprocess_url(image_urls): sample = {'image': _img, 'depth': _depth, 'label': _img} composed_transforms = transforms.Compose([ - # tr.CropBlackArea(), - # tr.FixedResize(size=self.args.crop_size), tr.Normalize( mean=( 0.485, 0.456, 0.406), std=( @@ -69,18 +78,7 @@ def preprocess_frames(frames): return trainsformed_frames -def _load_txt_dataset(dataset_url): - # use original dataset url - original_dataset_url = Context.get_parameters('original_dataset_url', "") - dataset_urls = dataset_url.split() - dataset_urls = [ - os.path.join( - os.path.dirname(original_dataset_url), - dataset_url) for dataset_url in dataset_urls] - return dataset_urls[:-1], dataset_urls[-1] - - -class Model: +class Estimator: def __init__(self, **kwargs): self.train_args = TrainingArguments(**kwargs) self.val_args = EvaluationArguments(**kwargs) @@ -90,8 +88,10 @@ class Model: self.trainer = None self.train_model_url = None - label_save_dir = Context.get_parameters("INFERENCE_RESULT_DIR", os.path.join( - BaseConfig.data_path_prefix, "inference_results")) + label_save_dir = Context.get_parameters( + "INFERENCE_RESULT_DIR", + os.path.join(BaseConfig.data_path_prefix, + "inference_results")) self.val_args.color_label_save_path = os.path.join( label_save_dir, "color") self.val_args.merge_label_save_path = os.path.join( @@ -100,13 +100,9 @@ class Model: self.val_args.weight_path = kwargs.get("weight_path") self.validator = Validator(self.val_args) - # self.ramp_val_args = EvaluationArguments() - # self.ramp_val_args.weight_path = "/home/lsq/RFNet/models/ramp_train1_200.pth" - # self.ramp_val_args.merge = False - # self.validator_ramp = Validator(self.ramp_val_args) - def train(self, train_data, valid_data=None, **kwargs): - self.trainer = Trainer(self.train_args, train_data=train_data) + self.trainer = Trainer( + self.train_args, train_data=train_data, valid_data=valid_data) LOGGER.info("Total epoches: {}".format(self.trainer.args.epochs)) for epoch in range( self.trainer.args.start_epoch, @@ -115,11 +111,12 @@ class Model: self.trainer.validation(epoch) self.trainer.training(epoch) - if self.trainer.args.no_val and (epoch % - self.trainer.args.eval_interval == ( - self.trainer.args.eval_interval - - 1) or epoch == self.trainer.args.epochs - 1): - # save checkpoint when it meets eval_interval or the training finishes + if self.trainer.args.no_val and \ + (epoch % self.trainer.args.eval_interval == + (self.trainer.args.eval_interval - 1) or + epoch == self.trainer.args.epochs - 1): + # save checkpoint when it meets eval_interval + # or the training finishes is_best = False train_model_url = self.trainer.saver.save_checkpoint({ 'epoch': epoch + 1, @@ -128,70 +125,37 @@ class Model: 'best_pred': self.trainer.best_pred, }, is_best) - # if not self.trainer.args.no_val and \ - # epoch % self.train_args.eval_interval == (self.train_args.eval_interval - 1) \ - # and self.trainer.val_loader: - # self.trainer.validation(epoch) - self.trainer.writer.close() - self.train_model_url = train_model_url - return self.train_model_url + + return {"mIoU": 0 if not valid_data + else self.trainer.validation(epoch)} def predict(self, data, **kwargs): - prediction = kwargs.get('prediction') if isinstance(data[0], dict): data = preprocess_frames(data) - + if isinstance(data[0], np.ndarray): data = preprocess_url(data) - + self.validator.test_loader = DataLoader( data, batch_size=self.val_args.test_batch_size, shuffle=False, pin_memory=False) - if not prediction: - return self.validator.validate() - else: - return prediction - - # def predict(self, data, **kwargs): - # if isinstance(data[0], np.ndarray): - # data = preprocess_url(data) - - # if isinstance(data[0], dict): - # data = preprocess_frames(data) - - # self.validator.test_loader = DataLoader( - # data, - # batch_size=self.val_args.test_batch_size, - # shuffle=False, - # pin_memory=False) - - # # TODO: predict ramp using specific model - # self.validator_ramp.test_loader = DataLoader( - # data, - # batch_size=self.val_args.test_batch_size, - # shuffle=False, - # pin_memory=False) - - # prediction = kwargs.get('prediction') - # if not prediction: - # return (self.validator.validate(), self.validator_ramp.validate()) - # else: - # return (prediction, self.validator_ramp.validate()) + return self.validator.validate() def evaluate(self, data, **kwargs): predictions = self.predict(data.x) - return robo_accuracy(data.y, predictions) + return accuracy(data.y, predictions) def load(self, model_url, **kwargs): if model_url: self.validator.new_state_dict = torch.load(model_url) self.validator.model = load_my_state_dict( - self.validator.model, self.validator.new_state_dict['state_dict']) + self.validator.model, + self.validator.new_state_dict['state_dict']) self.train_args.resume = model_url else: @@ -203,14 +167,3 @@ class Model: return self.train_model_url return FileOps.upload(self.train_model_url, model_path) - - -if __name__ == '__main__': - model = Model(num_class=31) - txt = "/home/lsq/RFNet/data_index/train.txt" - model.load("/home/lsq/RFNet/models/best_all_epoch_142_mean-iu_0.94952.pth") - - data = TxtDataParse(data_type="eval", func=_load_txt_dataset) - data.parse(txt, use_raw=False) - model.evaluate(data) - # model.save("./models/e1_2f.pth") diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/replicate.py b/examples/lifelong_learning/cityscapes/RFNet/models/replicate.py similarity index 87% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/models/replicate.py rename to examples/lifelong_learning/cityscapes/RFNet/models/replicate.py index 3734266e..6ae6883f 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/replicate.py +++ b/examples/lifelong_learning/cityscapes/RFNet/models/replicate.py @@ -1,13 +1,3 @@ -# -*- coding: utf-8 -*- -# File : replicate.py -# Author : Jiayuan Mao -# Email : maojiayuan@gmail.com -# Date : 27/01/2018 -# -# This file is part of Synchronized-BatchNorm-PyTorch. -# https://github.com/vacancy/Synchronized-BatchNorm-PyTorch -# Distributed under MIT License. - import functools from torch.nn.parallel.data_parallel import DataParallel @@ -57,7 +47,8 @@ class DataParallelWithCallback(DataParallel): """ def replicate(self, module, device_ids): - modules = super(DataParallelWithCallback, self).replicate(module, device_ids) + modules = super(DataParallelWithCallback, + self).replicate(module, device_ids) execute_replication_callbacks(modules) return modules @@ -85,4 +76,4 @@ def patch_replication_callback(data_parallel): execute_replication_callbacks(modules) return modules - data_parallel.replicate = new_replicate \ No newline at end of file + data_parallel.replicate = new_replicate diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/resnet/__init__.py b/examples/lifelong_learning/cityscapes/RFNet/models/resnet/__init__.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/models/resnet/__init__.py rename to examples/lifelong_learning/cityscapes/RFNet/models/resnet/__init__.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/resnet/resnet_single_scale_single_attention.py b/examples/lifelong_learning/cityscapes/RFNet/models/resnet/resnet_single_scale_single_attention.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/models/resnet/resnet_single_scale_single_attention.py rename to examples/lifelong_learning/cityscapes/RFNet/models/resnet/resnet_single_scale_single_attention.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/rfnet.py b/examples/lifelong_learning/cityscapes/RFNet/models/rfnet.py similarity index 75% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/models/rfnet.py rename to examples/lifelong_learning/cityscapes/RFNet/models/rfnet.py index 23683554..628e6bd6 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/rfnet.py +++ b/examples/lifelong_learning/cityscapes/RFNet/models/rfnet.py @@ -1,16 +1,18 @@ import torch.nn as nn -from itertools import chain # 串联多个迭代对象 +from itertools import chain from .util import _BNReluConv, upsample + class RFNet(nn.Module): def __init__(self, backbone, num_classes, use_bn=True): super(RFNet, self).__init__() self.backbone = backbone self.num_classes = num_classes - self.logits = _BNReluConv(self.backbone.num_features, self.num_classes, batch_norm=use_bn) + self.logits = _BNReluConv( + self.backbone.num_features, self.num_classes, batch_norm=use_bn) - def forward(self, rgb_inputs, depth_inputs = None): + def forward(self, rgb_inputs, depth_inputs=None): x, additional = self.backbone(rgb_inputs, depth_inputs) logits = self.logits.forward(x) logits_upsample = upsample(logits, rgb_inputs.shape[2:]) @@ -21,4 +23,3 @@ class RFNet(nn.Module): def fine_tune_params(self): return self.backbone.fine_tune_params() - diff --git a/examples/lifelong_learning/cityscapes/RFNet/models/util.py b/examples/lifelong_learning/cityscapes/RFNet/models/util.py new file mode 100644 index 00000000..381e4e04 --- /dev/null +++ b/examples/lifelong_learning/cityscapes/RFNet/models/util.py @@ -0,0 +1,144 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def upsample(x, size): return F.interpolate( + x, size, mode='bilinear', align_corners=False) + + +batchnorm_momentum = 0.01 / 2 + + +def get_n_params(parameters): + pp = 0 + for p in parameters: + nn = 1 + for s in list(p.size()): + nn = nn * s + pp += nn + return pp + + +class _BNReluConv(nn.Sequential): + def __init__(self, + num_maps_in, + num_maps_out, + k=3, + batch_norm=True, + bn_momentum=0.1, + bias=False, + dilation=1): + super(_BNReluConv, self).__init__() + if batch_norm: + self.add_module('norm', nn.BatchNorm2d( + num_maps_in, momentum=bn_momentum)) + self.add_module('relu', nn.ReLU(inplace=batch_norm is True)) + padding = k // 2 + self.add_module('conv', + nn.Conv2d(num_maps_in, + num_maps_out, + kernel_size=k, + padding=padding, + bias=bias, + dilation=dilation)) + + +class _Upsample(nn.Module): + def __init__(self, + num_maps_in, + skip_maps_in, + num_maps_out, + use_bn=True, + k=3): + super(_Upsample, self).__init__() + self.bottleneck = _BNReluConv( + skip_maps_in, num_maps_in, k=1, batch_norm=use_bn) + self.blend_conv = _BNReluConv( + num_maps_in, num_maps_out, k=k, batch_norm=use_bn) + + def forward(self, x, skip): + skip = self.bottleneck.forward(skip) + skip_size = skip.size()[2:4] + x = upsample(x, skip_size) + x = x + skip + x = self.blend_conv.forward(x) + return x + + +class SpatialPyramidPooling(nn.Module): + def __init__(self, + num_maps_in, + num_levels, + bt_size=512, + level_size=128, + out_size=128, + grids=(6, 3, 2, 1), + square_grid=False, + bn_momentum=0.1, + use_bn=True): + super(SpatialPyramidPooling, self).__init__() + self.grids = grids + self.square_grid = square_grid + self.spp = nn.Sequential() + self.spp.add_module('spp_bn', + _BNReluConv(num_maps_in, + bt_size, + k=1, + bn_momentum=bn_momentum, + batch_norm=use_bn)) + num_features = bt_size + final_size = num_features + for i in range(num_levels): + final_size += level_size + self.spp.add_module('spp' + str(i), + _BNReluConv(num_features, + level_size, + k=1, + bn_momentum=bn_momentum, + batch_norm=use_bn)) + self.spp.add_module('spp_fuse', + _BNReluConv(final_size, + out_size, + k=1, + bn_momentum=bn_momentum, + batch_norm=use_bn)) + + def forward(self, x): + levels = [] + target_size = x.size()[2:4] + + ar = target_size[1] / target_size[0] + + x = self.spp[0].forward(x) + levels.append(x) + num = len(self.spp) - 1 + + for i in range(1, num): + if not self.square_grid: + grid_size = (self.grids[i - 1], + max(1, round(ar * self.grids[i - 1]))) + x_pooled = F.adaptive_avg_pool2d(x, grid_size) + else: + x_pooled = F.adaptive_avg_pool2d(x, self.grids[i - 1]) + level = self.spp[i].forward(x_pooled) + + level = upsample(level, target_size) + levels.append(level) + x = torch.cat(levels, 1) + x = self.spp[-1].forward(x) + return x + + +class _UpsampleBlend(nn.Module): + def __init__(self, num_features, use_bn=True): + super(_UpsampleBlend, self).__init__() + self.blend_conv = _BNReluConv( + num_features, num_features, k=3, batch_norm=use_bn) + + def forward(self, x, skip): + skip_size = skip.size()[2:4] + x = upsample(x, skip_size) + x = x + skip + x = self.blend_conv.forward(x) + return x diff --git a/examples/lifelong_learning/cityscapes/RFNet/predict.py b/examples/lifelong_learning/cityscapes/RFNet/predict.py new file mode 100644 index 00000000..914c7ce4 --- /dev/null +++ b/examples/lifelong_learning/cityscapes/RFNet/predict.py @@ -0,0 +1,105 @@ +# Copyright 2023 The KubeEdge 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 time + +from PIL import Image +from sedna.datasources import BaseDataSource +from sedna.common.config import Context +from sedna.common.log import LOGGER +from sedna.common.file_ops import FileOps +from sedna.core.lifelong_learning import LifelongLearning + +from interface import Estimator + + +def unseen_sample_postprocess(sample, save_url): + if isinstance(sample, dict): + img = sample.get("image") + image_name = "{}.png".format(str(time.time())) + image_url = FileOps.join_path(save_url, image_name) + img.save(image_url) + else: + image_name = os.path.basename(sample[0]) + image_url = FileOps.join_path(save_url, image_name) + FileOps.upload(sample[0], image_url, clean=False) + + +def preprocess(samples): + data = BaseDataSource(data_type="test") + data.x = [samples] + return data + + +def init_ll_job(): + estimator = Estimator(num_class=Context.get_parameters("num_class", 24), + save_predicted_image=True, + merge=True) + + task_allocation = { + "method": "TaskAllocationStream" + } + unseen_task_allocation = { + "method": "UnseenTaskAllocationDefault" + } + + ll_job = LifelongLearning( + estimator, + unseen_estimator=unseen_task_processing, + task_definition=None, + task_relationship_discovery=None, + task_allocation=task_allocation, + task_remodeling=None, + inference_integrate=None, + task_update_decision=None, + unseen_task_allocation=unseen_task_allocation, + unseen_sample_recognition=None, + unseen_sample_re_recognition=None) + return ll_job + + +def unseen_task_processing(): + return "Warning: unseen sample detected." + + +def predict(): + ll_job = init_ll_job() + test_data_dir = Context.get_parameters("test_data") + test_data = os.listdir(test_data_dir) + test_data_num = len(test_data) + count = 0 + + # Simulate a permenant inference service + while True: + for i, data in enumerate(test_data): + LOGGER.info(f"Start to inference image {i + count + 1}") + + test_data_url = os.path.join(test_data_dir, data) + img_rgb = Image.open(test_data_url).convert("RGB") + sample = {'image': img_rgb, "depth": img_rgb, "label": img_rgb} + predict_data = preprocess(sample) + prediction, is_unseen, _ = ll_job.inference( + predict_data, + unseen_sample_postprocess=unseen_sample_postprocess) + LOGGER.info(f"Image {i + count + 1} is unseen task: {is_unseen}") + LOGGER.info( + f"Image {i + count + 1} prediction result: {prediction}") + time.sleep(1.0) + + count += test_data_num + + +if __name__ == '__main__': + predict() diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/train.py b/examples/lifelong_learning/cityscapes/RFNet/train.py similarity index 59% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/train.py rename to examples/lifelong_learning/cityscapes/RFNet/train.py index 468d45dd..4497b752 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/train.py +++ b/examples/lifelong_learning/cityscapes/RFNet/train.py @@ -1,10 +1,24 @@ +# Copyright 2023 The KubeEdge 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 from sedna.core.lifelong_learning import LifelongLearning from sedna.common.config import Context, BaseConfig from sedna.datasources import TxtDataParse -from basemodel import Model +from interface import Estimator def _load_txt_dataset(dataset_url): @@ -20,11 +34,15 @@ def _load_txt_dataset(dataset_url): def train(estimator, train_data): task_definition = { - "method": "TaskDefinitionSimple" + "method": "TaskDefinitionByOrigin", + "param": { + "attribute": Context.get_parameters("attribute"), + "city": Context.get_parameters("city") + } } task_allocation = { - "method": "TaskAllocationSimple" + "method": "TaskAllocationByOrigin" } ll_job = LifelongLearning(estimator, @@ -42,24 +60,9 @@ def train(estimator, train_data): ll_job.train(train_data) -def update(estimator, train_data): - ll_job = LifelongLearning(estimator, - task_definition=None, - task_relationship_discovery=None, - task_allocation=None, - task_remodeling=None, - inference_integrate=None, - task_update_decision=None, - unseen_task_allocation=None, - unseen_sample_recognition=None, - unseen_sample_re_recognition=None - ) - - ll_job.update(train_data) - - def run(): - estimator = Model(num_class=31, epochs=1) + estimator = Estimator(num_class=int(Context.get_parameters("num_class", 24)), + epochs=int(Context.get_parameters("epoches", 1))) train_dataset_url = BaseConfig.train_dataset_url train_data = TxtDataParse(data_type="train", func=_load_txt_dataset) train_data.parse(train_dataset_url, use_raw=False) diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/__init__.py b/examples/lifelong_learning/cityscapes/RFNet/utils/__init__.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/__init__.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/__init__.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/args.py b/examples/lifelong_learning/cityscapes/RFNet/utils/args.py similarity index 96% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/args.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/args.py index 68bc89cf..aec10028 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/args.py +++ b/examples/lifelong_learning/cityscapes/RFNet/utils/args.py @@ -19,7 +19,7 @@ class Arguments: self.image_size = kwargs.get( "image_size", (2048, 1024)) # output image shape # input batch size for training - self.batch_size = kwargs.get("batch_size") + self.batch_size = int(kwargs.get("batch_size", 4)) self.val_batch_size = int(kwargs.get( "val_batch_size", 1)) # input batch size for validation self.test_batch_size = int(kwargs.get( diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/calculate_weights.py b/examples/lifelong_learning/cityscapes/RFNet/utils/calculate_weights.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/calculate_weights.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/calculate_weights.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/iouEval.py b/examples/lifelong_learning/cityscapes/RFNet/utils/iouEval.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/iouEval.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/iouEval.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/loss.py b/examples/lifelong_learning/cityscapes/RFNet/utils/loss.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/loss.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/loss.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/lr_scheduler.py b/examples/lifelong_learning/cityscapes/RFNet/utils/lr_scheduler.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/lr_scheduler.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/lr_scheduler.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/metrics.py b/examples/lifelong_learning/cityscapes/RFNet/utils/metrics.py similarity index 97% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/metrics.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/metrics.py index ccc06aa0..7a4eb883 100644 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/metrics.py +++ b/examples/lifelong_learning/cityscapes/RFNet/utils/metrics.py @@ -110,11 +110,6 @@ class Evaluator(object): np.diag(self.confusion_matrix)) FWIoU = (freq[freq > 0] * iu[freq > 0]).sum() - CFWIoU = freq[freq > 0] * iu[freq > 0] - print('-----------FWIoU of each classes-----------') - print("road : %.6f" % (CFWIoU[0] * 100.0), "%\t") - print("sidewalk : %.6f" % (CFWIoU[1] * 100.0), "%\t") - return FWIoU def Frequency_Weighted_Intersection_over_Union_Curb(self): diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/ml_regression.py b/examples/lifelong_learning/cityscapes/RFNet/utils/ml_regression.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/ml_regression.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/ml_regression.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/nn_regression.py b/examples/lifelong_learning/cityscapes/RFNet/utils/nn_regression.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/nn_regression.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/nn_regression.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/saver.py b/examples/lifelong_learning/cityscapes/RFNet/utils/saver.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/saver.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/saver.py diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/utils/summaries.py b/examples/lifelong_learning/cityscapes/RFNet/utils/summaries.py similarity index 100% rename from examples/lifelong_learning/robot_dog_delivery/RFNet/utils/summaries.py rename to examples/lifelong_learning/cityscapes/RFNet/utils/summaries.py diff --git a/examples/lifelong_learning/cityscapes/yaml/dataset.yaml b/examples/lifelong_learning/cityscapes/yaml/dataset.yaml new file mode 100644 index 00000000..15db8935 --- /dev/null +++ b/examples/lifelong_learning/cityscapes/yaml/dataset.yaml @@ -0,0 +1,8 @@ +apiVersion: sedna.io/v1alpha1 +kind: Dataset +metadata: + name: lifelong-robo-dataset +spec: + url: "$data_url" + format: "txt" + nodeName: "$DATA_NODE" \ No newline at end of file diff --git a/examples/lifelong_learning/cityscapes/yaml/robot-dog-delivery.yaml b/examples/lifelong_learning/cityscapes/yaml/robot-dog-delivery.yaml new file mode 100644 index 00000000..2c25f113 --- /dev/null +++ b/examples/lifelong_learning/cityscapes/yaml/robot-dog-delivery.yaml @@ -0,0 +1,119 @@ +apiVersion: sedna.io/v1alpha1 +kind: LifelongLearningJob +metadata: + name: $job_name +spec: + dataset: + name: "lifelong-robo-dataset" + trainProb: 0.8 + trainSpec: + template: + spec: + nodeName: $TRAIN_NODE + dnsPolicy: ClusterFirstWithHostNet + containers: + - image: $cloud_image + name: train-worker + imagePullPolicy: IfNotPresent + args: ["train.py"] + env: + - name: "num_class" + value: "24" + - name: "epoches" + value: "1" + resources: + limits: + cpu: 6 + memory: 12Gi + requests: + cpu: 4 + memory: 10Gi + volumeMounts: + - mountPath: /dev/shm + name: cache-volume + volumes: + - emptyDir: + medium: Memory + sizeLimit: 256Mi + name: cache-volume + trigger: + checkPeriodSeconds: 30 + timer: + start: 00:00 + end: 24:00 + condition: + operator: ">" + threshold: 100 + metric: num_of_samples + evalSpec: + template: + spec: + nodeName: $EVAL_NODE + dnsPolicy: ClusterFirstWithHostNet + containers: + - image: $cloud_image + name: eval-worker + imagePullPolicy: IfNotPresent + args: ["evaluate.py"] + env: + - name: "operator" + value: "<" + - name: "model_threshold" + value: "0" + - name: "num_class" + value: "24" + resources: + limits: + cpu: 6 + memory: 6Gi + requests: + cpu: 4 + memory: 5Gi + deploySpec: + template: + spec: + nodeName: $INFER_NODE + dnsPolicy: ClusterFirstWithHostNet + hostNetwork: true + containers: + - image: $edge_image + name: infer-worker + imagePullPolicy: IfNotPresent + args: ["predict.py"] + env: + - name: "test_data" + value: "/data/test_data" + - name: "num_class" + value: "24" + - name: "unseen_save_url" + value: "/data/unseen_samples" + - name: "INFERENCE_RESULT_DIR" + value: "/data/infer_results" + volumeMounts: + - name: unseenurl + mountPath: /data/unseen_samples + - name: inferdata + mountPath: /data/infer_results + - name: testdata + mountPath: /data/test_data + resources: + limits: + cpu: 6 + memory: 6Gi + requests: + cpu: 4 + memory: 3Gi + volumes: + - name: unseenurl + hostPath: + path: /data/unseen_samples + type: DirectoryOrCreate + - name: inferdata + hostPath: + path: /data/infer_results + type: DirectoryOrCreate + - name: testdata + hostPath: + path: /data/test_data + type: DirectoryOrCreate + outputDir: $OUTPUT/$job_name \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/README.md b/examples/lifelong_learning/robot_dog_delivery/README.md deleted file mode 100644 index f22c51f5..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/README.md +++ /dev/null @@ -1,201 +0,0 @@ -# Using Lifelong Learning in Campus Robot Delivery Scenario - -## Introduction -This example introduces how to use Sedna lifelong learning to implement the lifelong learning delivery task of the robot in the campus. - -This demo mainly shows: -1. Lifelong learning unseen task recognition algorithm (prediction) can identify and collect unseen task samples. -2. Lifelong learning unseen task recognition algorithm (detection) can trigger alarms to remind robot admin that emergency response is required. -3. Lifelong learning unseen task training algorithm improves the inference accuracy of known categories and the ability to identify new categories. - -## System Architecture - -### Install Sedna -Follow the [Sedna installation document](/docs/setup/install.md) to install Sedna. - -### Prepare Dataset -Step1: download [data.txt](https://kubeedge.obs.cn-north-1.myhuaweicloud.com:443/sedna-robo/data.txt?AWSAccessKeyId=EMPTKHQUGPO2CDUFD2YR&Expires=1697698966&Signature=s42sKZVewIP/kgLc4dEzjNCRXfk%3D) -and upload it to a specfied s3 directory. In this example, the directory is s3://kubeedge/sedna-robo/sedna_data. - -Step2: download and decompress [sedna_data.zip](https://kubeedge.obs.cn-north-1.myhuaweicloud.com:443/sedna-robo/sedna_data.zip?AWSAccessKeyId=EMPTKHQUGPO2CDUFD2YR&Expires=1697700463&Signature=9OlCC8qBcQr8LfX1ptbsr7nhU5s%3D), -then upload the training images in it to the s3 directory where data.txt is stored. - -### Prepare Images -This example uses these images: - -1. training worker: swr.cn-south-1.myhuaweicloud.com/sedna/sedna-robo:v0.1.1 -2. evaluate worker: swr.cn-south-1.myhuaweicloud.com/sedna/sedna-robo:v0.1.1 -3. inference worker: swr.cn-south-1.myhuaweicloud.com/sedna/sedna-robo-infer:v0.1.1 - -These images are generated by the script [build_images.sh](/examples/build_image.sh). - -### Create Lifelong Learning Job - -#### Preparations -Before this, user must provide an s3 directory for storage which is denoted as "s3_prefix" in this example, by setting environment variable s3_prefix. -``` -s3_prefix=$s3_prefix -cloud_image=swr.cn-south-1.myhuaweicloud.com/sedna/sedna-robo:v0.1.1 -edge_image=swr.cn-south-1.myhuaweicloud.com/sedna/sedna-robo-infer:v0.1.1 -data_url=$s3_prefix/sedna_data/data.txt - -DATA_NODE=sedna-mini-control-plane -TRAIN_NODE=sedna-mini-control-plane -EVAL_NODE=sedna-mini-control-plane -INFER_NODE=sedna-mini-control-plane -OUTPUT=$s3_prefix/lifelonglearningjob/output -job_name=robo-demo -``` -#### Create s3 storage resources -Before this, users must generate the S3_ENDPOINT, ACCESS_KEY_ID and SECRET_ACCESS_KEY of their own s3 accounts and set environment - variables S3_ENDPOINT, ACCESS_KEY_ID and SECRET_ACCESS_KEY. -``` -action=${1:-create} - -kubectl $action -f - <" - threshold: 100 - metric: num_of_samples - evalSpec: - template: - spec: - nodeName: $EVAL_NODE - dnsPolicy: ClusterFirstWithHostNet - containers: - - image: $cloud_image - name: eval-worker - imagePullPolicy: IfNotPresent - args: ["sedna_evaluate.py"] - env: - - name: "operator" - value: "<" - - name: "model_threshold" # Threshold for filtering deploy models - value: "0" - - name: "BACKEND_TYPE" - value: "PYTORCH" - resources: - limits: - cpu: 6 - memory: 6Gi - requests: - cpu: 3 - memory: 3Gi - deploySpec: - template: - spec: - nodeName: $INFER_NODE - dnsPolicy: ClusterFirstWithHostNet - hostNetwork: true - containers: - - image: $edge_image - name: infer-worker - imagePullPolicy: IfNotPresent - env: - - name: "BIG_MODEL_IP" - value: "http://94.74.91.114" - - name: "BIG_MODEL_PORT" - value: "30001" - - name: "RUN_FILE" - value: "integration_main.py" - resources: # user defined resources - limits: - cpu: 6 - memory: 6Gi - requests: - cpu: 3 - memory: 3Gi - - credentialName: my - outputDir: $OUTPUT/$job_name -EOF -``` - -### Check Lifelong Learning Status - -``` -kubectl get lifelonglearningjob -``` - -### Effect Display - - - - - diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/accuracy.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/accuracy.py deleted file mode 100644 index 271bb9ae..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/accuracy.py +++ /dev/null @@ -1,71 +0,0 @@ -from tqdm import tqdm -from sedna.common.class_factory import ClassType, ClassFactory - -from utils.args import EvaluationArguments -from utils.metrics import Evaluator -from dataloaders import make_data_loader - -__all__ = ('accuracy', 'robo_accuracy') - - -@ClassFactory.register(ClassType.GENERAL) -def accuracy(y_true, y_pred, **kwargs): - args = EvaluationArguments() - _, _, test_loader = make_data_loader(args, test_data=y_true) - evaluator = Evaluator(args.num_class) - - tbar = tqdm(test_loader, desc='\r') - for i, (sample, img_path) in enumerate(tbar): - if args.depth: - image, depth, target = sample['image'], sample['depth'], sample['label'] - else: - image, target = sample['image'], sample['label'] - if args.cuda: - image, target = image.cuda(), target.cuda() - if args.depth: - depth = depth.cuda() - - target[target > evaluator.num_class - 1] = 255 - target = target.cpu().numpy() - # Add batch sample into evaluator - evaluator.add_batch(target, y_pred[i]) - - # Test during the training - CPA = evaluator.Pixel_Accuracy_Class() - mIoU = evaluator.Mean_Intersection_over_Union() - FWIoU = evaluator.Frequency_Weighted_Intersection_over_Union() - - print("CPA:{}, mIoU:{}, fwIoU: {}".format(CPA, mIoU, FWIoU)) - return CPA - - -@ClassFactory.register(ClassType.GENERAL) -def robo_accuracy(y_true, y_pred, **kwargs): - y_pred = y_pred[0] - args = EvaluationArguments() - _, _, test_loader = make_data_loader(args, test_data=y_true) - evaluator = Evaluator(args.num_class) - - tbar = tqdm(test_loader, desc='\r') - for i, (sample, img_path) in enumerate(tbar): - if args.depth: - image, depth, target = sample['image'], sample['depth'], sample['label'] - else: - image, target = sample['image'], sample['label'] - if args.cuda: - image, target = image.cuda(), target.cuda() - if args.depth: - depth = depth.cuda() - - target[target > evaluator.num_class - 1] = 255 - target = target.cpu().numpy() - # Add batch sample into evaluator - evaluator.add_batch(target, y_pred[i]) - - # Test during the training - CPA = evaluator.Pixel_Accuracy_Class() - mIoU = evaluator.Mean_Intersection_over_Union() - FWIoU = evaluator.Frequency_Weighted_Intersection_over_Union() - - print("CPA:{}, mIoU:{}, fwIoU: {}".format(CPA, mIoU, FWIoU)) - return CPA diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/datasets/cityscapes.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/datasets/cityscapes.py deleted file mode 100644 index 6adb598a..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/dataloaders/datasets/cityscapes.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import numpy as np -from PIL import Image -from torch.utils import data -from torchvision import transforms -from dataloaders import custom_transforms as tr - -class CityscapesSegmentation(data.Dataset): - - def __init__(self, args, data=None, split="train"): - - self.split = split - self.args = args - self.images = {} - self.disparities = {} - self.labels = {} - - self.images[split] = [img[0] for img in data.x] if hasattr(data, "x") else data - - if hasattr(data, "x") and len(data.x[0]) == 1: - self.disparities[split] = self.images[split] - elif hasattr(data, "x") and len(data.x[0]) == 2: - self.disparities[split] = [img[1] for img in data.x] - else: - self.disparities[split] = data - - self.labels[split] = data.y if hasattr(data, "y") else data - - self.ignore_index = 255 - - if len(self.images[split]) == 0: - raise Exception("No RGB images for split=[%s] found in %s" % (split, self.images_base)) - if len(self.disparities[split]) == 0: - raise Exception("No depth images for split=[%s] found in %s" % (split, self.disparities_base)) - - print("Found %d %s RGB images" % (len(self.images[split]), split)) - print("Found %d %s disparity images" % (len(self.disparities[split]), split)) - - - def __len__(self): - return len(self.images[self.split]) - - def __getitem__(self, index): - img_path = self.images[self.split][index].rstrip() - disp_path = self.disparities[self.split][index].rstrip() - try: - lbl_path = self.labels[self.split][index].rstrip() - _img = Image.open(img_path).convert('RGB').resize(self.args.image_size, Image.BILINEAR) - _depth = Image.open(disp_path).resize(self.args.image_size, Image.BILINEAR) - _target = Image.open(lbl_path).resize(self.args.image_size, Image.BILINEAR) - # _img = Image.open(img_path).convert('RGB') - # _depth = Image.open(disp_path) - # _target = Image.open(lbl_path) - sample = {'image': _img,'depth':_depth, 'label': _target} - except: - _img = Image.open(img_path).convert('RGB').resize(self.args.image_size, Image.BILINEAR) - _depth = Image.open(disp_path).resize(self.args.image_size, Image.BILINEAR) - # _img = Image.open(img_path).convert('RGB') - # _depth = Image.open(disp_path) - sample = {'image': _img,'depth':_depth, 'label': _img} - - if self.split == 'train': - return self.transform_tr(sample) - elif self.split == 'val': - return self.transform_val(sample), img_path - elif self.split == 'test': - return self.transform_ts(sample), img_path - elif self.split == 'custom_resize': - return self.transform_ts(sample), img_path - - - def recursive_glob(self, rootdir='.', suffix=''): - """Performs recursive glob with given suffix and rootdir - :param rootdir is the root directory - :param suffix is the suffix to be searched - """ - return [os.path.join(looproot, filename) - for looproot, _, filenames in os.walk(rootdir) - for filename in filenames if filename.endswith(suffix)] - - def transform_tr(self, sample): - composed_transforms = transforms.Compose([ - tr.CropBlackArea(), - tr.RandomHorizontalFlip(), - tr.RandomScaleCrop(base_size=self.args.base_size, crop_size=self.args.crop_size, fill=255), - # tr.RandomGaussianBlur(), - tr.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), - tr.ToTensor()]) - - return composed_transforms(sample) - - def transform_val(self, sample): - - composed_transforms = transforms.Compose([ - tr.CropBlackArea(), - tr.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), - tr.ToTensor()]) - - return composed_transforms(sample) - - def transform_ts(self, sample): - - composed_transforms = transforms.Compose([ - #tr.CropBlackArea(), - #tr.FixedResize(size=self.args.crop_size), - tr.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), - tr.ToTensor()]) - - return composed_transforms(sample) - -if __name__ == '__main__': - from dataloaders.utils import decode_segmap - from torch.utils.data import DataLoader - import matplotlib.pyplot as plt - import argparse - - parser = argparse.ArgumentParser() - args = parser.parse_args() - args.base_size = 513 - args.crop_size = 513 - - cityscapes_train = CityscapesSegmentation(args, split='train') - - dataloader = DataLoader(cityscapes_train, batch_size=2, shuffle=True, num_workers=2) - - for ii, sample in enumerate(dataloader): - for jj in range(sample["image"].size()[0]): - img = sample['image'].numpy() - gt = sample['label'].numpy() - tmp = np.array(gt[jj]).astype(np.uint8) - segmap = decode_segmap(tmp, dataset='cityscapes') - img_tmp = np.transpose(img[jj], axes=[1, 2, 0]) - img_tmp *= (0.229, 0.224, 0.225) - img_tmp += (0.485, 0.456, 0.406) - img_tmp *= 255.0 - img_tmp = img_tmp.astype(np.uint8) - plt.figure() - plt.title('display') - plt.subplot(211) - plt.imshow(img_tmp) - plt.subplot(212) - plt.imshow(segmap) - - if ii == 1: - break - - plt.show(block=True) - diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/util.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/models/util.py deleted file mode 100644 index 7926bd20..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/models/util.py +++ /dev/null @@ -1,98 +0,0 @@ -import torch -import torch.nn as nn -import torch.nn.functional as F - -upsample = lambda x, size: F.interpolate(x, size, mode='bilinear', align_corners=False) -batchnorm_momentum = 0.01 / 2 - - -def get_n_params(parameters): - pp = 0 - for p in parameters: - nn = 1 - for s in list(p.size()): - nn = nn * s - pp += nn - return pp - - -class _BNReluConv(nn.Sequential): - def __init__(self, num_maps_in, num_maps_out, k=3, batch_norm=True, bn_momentum=0.1, bias=False, dilation=1): - super(_BNReluConv, self).__init__() - if batch_norm: - self.add_module('norm', nn.BatchNorm2d(num_maps_in, momentum=bn_momentum)) - self.add_module('relu', nn.ReLU(inplace=batch_norm is True)) - padding = k // 2 # same conv - self.add_module('conv', nn.Conv2d(num_maps_in, num_maps_out, - kernel_size=k, padding=padding, bias=bias, dilation=dilation)) - - -class _Upsample(nn.Module): - def __init__(self, num_maps_in, skip_maps_in, num_maps_out, use_bn=True, k=3): - super(_Upsample, self).__init__() - self.bottleneck = _BNReluConv(skip_maps_in, num_maps_in, k=1, batch_norm=use_bn) - self.blend_conv = _BNReluConv(num_maps_in, num_maps_out, k=k, batch_norm=use_bn) - - def forward(self, x, skip): - skip = self.bottleneck.forward(skip) - skip_size = skip.size()[2:4] - x = upsample(x, skip_size) - x = x + skip - x = self.blend_conv.forward(x) - return x - - -class SpatialPyramidPooling(nn.Module): - def __init__(self, num_maps_in, num_levels, bt_size=512, level_size=128, out_size=128, - grids=(6, 3, 2, 1), square_grid=False, bn_momentum=0.1, use_bn=True): - super(SpatialPyramidPooling, self).__init__() - self.grids = grids - self.square_grid = square_grid - self.spp = nn.Sequential() - self.spp.add_module('spp_bn', - _BNReluConv(num_maps_in, bt_size, k=1, bn_momentum=bn_momentum, batch_norm=use_bn)) - num_features = bt_size - final_size = num_features - for i in range(num_levels): - final_size += level_size - self.spp.add_module('spp' + str(i), - _BNReluConv(num_features, level_size, k=1, bn_momentum=bn_momentum, batch_norm=use_bn)) - self.spp.add_module('spp_fuse', - _BNReluConv(final_size, out_size, k=1, bn_momentum=bn_momentum, batch_norm=use_bn)) - - def forward(self, x): - levels = [] - target_size = x.size()[2:4] - - ar = target_size[1] / target_size[0] - - x = self.spp[0].forward(x) - levels.append(x) - num = len(self.spp) - 1 - - for i in range(1, num): - if not self.square_grid: - grid_size = (self.grids[i - 1], max(1, round(ar * self.grids[i - 1]))) - x_pooled = F.adaptive_avg_pool2d(x, grid_size) - else: - x_pooled = F.adaptive_avg_pool2d(x, self.grids[i - 1]) - level = self.spp[i].forward(x_pooled) - - level = upsample(level, target_size) - levels.append(level) - x = torch.cat(levels, 1) - x = self.spp[-1].forward(x) - return x - - -class _UpsampleBlend(nn.Module): - def __init__(self, num_features, use_bn=True): - super(_UpsampleBlend, self).__init__() - self.blend_conv = _BNReluConv(num_features, num_features, k=3, batch_norm=use_bn) - - def forward(self, x, skip): - skip_size = skip.size()[2:4] - x = upsample(x, skip_size) - x = x + skip - x = self.blend_conv.forward(x) - return x diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/predict.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/predict.py deleted file mode 100644 index 4e0436e7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/predict.py +++ /dev/null @@ -1,51 +0,0 @@ -import time - -from sedna.datasources import BaseDataSource -from sedna.core.lifelong_learning import LifelongLearning - -from basemodel import Model - - -def preprocess(samples): - data = BaseDataSource(data_type="test") - data.x = [samples] - return data - -def postprocess(samples): - image_names, imgs = [], [] - for sample in samples: - img = sample.get("image") - image_names.append("{}.png".format(str(time.time()))) - imgs.append(img) - - return image_names, imgs - -def init_ll_job(): - estimator = Model(num_class=31, - save_predicted_image=True, - merge=True) - - task_allocation = { - "method": "TaskAllocationDefault" - } - unseen_task_allocation = { - "method": "UnseenTaskAllocationDefault" - } - - ll_job = LifelongLearning( - estimator, - unseen_estimator=unseen_task_processing, - task_definition=None, - task_relationship_discovery=None, - task_allocation=task_allocation, - task_remodeling=None, - inference_integrate=None, - task_update_decision=None, - unseen_task_allocation=unseen_task_allocation, - unseen_sample_recognition=None, - unseen_sample_re_recognition=None) - return ll_job - - -def unseen_task_processing(): - return "Warning: unseen sample detected." diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/ramp_postprocess.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/ramp_postprocess.py deleted file mode 100644 index ba9762af..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/ramp_postprocess.py +++ /dev/null @@ -1,168 +0,0 @@ -import os -import time - -import cv2 -import numpy as np - - -def parse_result(label, count, ratio): - count_d = dict(zip(label, count)) - ramp_count = count_d.get(21, 0) - if ramp_count / np.sum(count) > ratio: - return True - else: - return False - - -def get_ramp(results, img_rgb): - results = np.array(results[0]) - input_height, input_width = results.shape - - # big trapezoid - big_closest = np.array([ - [0, int(input_height)], - [int(input_width), - int(input_height)], - [int(0.882 * input_width + .5), - int(.8 * input_height + .5)], - [int(0.118 * input_width + .5), - int(.8 * input_height + .5)] - ]) - - big_future = np.array([ - [int(0.118 * input_width + .5), - int(.8 * input_height + .5)], - [int(0.882 * input_width + .5), - int(.8 * input_height + .5)], - [int(.765 * input_width + .5), - int(.66 * input_height + .5)], - [int(.235 * input_width + .5), - int(.66 * input_height + .5)] - ]) - - # small trapezoid - small_closest = np.array([ - [488, int(input_height)], - [1560, int(input_height)], - [1391, int(.8 * input_height + .5)], - [621, int(.8 * input_height + .5)] - ]) - - small_future = np.array([ - [741, int(.66 * input_height + .5)], - [1275, int(.66 * input_height + .5)], - [1391, int(.8 * input_height + .5)], - [621, int(.8 * input_height + .5)] - ]) - - upper_left = np.array([ - [1567, 676], - [1275, 676], - [1391, 819], - [1806, 819] - ]) - - bottom_left = np.array([ - [1806, 819], - [1391, 819], - [1560, 1024], - [2048, 1024] - ]) - - upper_right = np.array([ - [741, 676], - [481, 676], - [242, 819], - [621, 819] - ]) - - bottom_right = np.array([ - [621, 819], - [242, 819], - [0, 1024], - [488, 1024] - ]) - - # _draw_closest_and_future((big_closest, big_future), (small_closest, small_future), img_rgb) - - ramp_location = locate_ramp(small_closest, small_future, - upper_left, bottom_left, - upper_right, bottom_right, - results) - - if not ramp_location: - ramp_location = "no_ramp" - - return ramp_location - - -def locate_ramp(small_closest, small_future, - upper_left, bottom_left, - upper_right, bottom_right, - results): - - if has_ramp(results, (small_closest, small_future), 0.9, 0.7): - return "small_trapezoid" - - right_location = has_ramp(results, (bottom_right, upper_right), 0.4, 0.2) - if right_location: - return f"{right_location}_left" - - left_location = has_ramp(results, (bottom_left, upper_left), 0.4, 0.2) - if left_location: - return f"{left_location}_right" - - return False - - -def has_ramp(results, areas, partial_ratio, all_ratio): - bottom, upper = areas - input_height, input_width = results.shape - - mask = np.zeros((input_height, input_width), dtype=np.uint8) - mask = cv2.fillPoly(mask, [bottom], 1) - label, count = np.unique(results[mask == 1], return_counts=True) - has_ramp_bottom = parse_result(label, count, partial_ratio) - - mask = np.zeros((input_height, input_width), dtype=np.uint8) - mask = cv2.fillPoly(mask, [upper], 1) - label, count = np.unique(results[mask == 1], return_counts=True) - has_ramp_upper = parse_result(label, count, partial_ratio) - - if has_ramp_bottom: - return "bottom" - if has_ramp_upper: - return "upper" - - mask = np.zeros((input_height, input_width), dtype=np.uint8) - mask = cv2.fillPoly(mask, [bottom], 1) - mask = cv2.fillPoly(mask, [upper], 1) - label, count = np.unique(results[mask == 1], return_counts=True) - has_ramp = parse_result(label, count, all_ratio) - if has_ramp: - return "center" - else: - return False - - -def _draw_closest_and_future(big, small, img_rgb): - big_closest, big_future = big - small_closest, small_future = small - - img_array = np.array(img_rgb) - big_closest_color = [0, 50, 50] - big_future_color = [0, 69, 0] - - small_closest_color = [0, 100, 100] - small_future_color = [69, 69, 69] - - height, weight, channel = img_array.shape - img = np.zeros((height, weight, channel), dtype=np.uint8) - img = cv2.fillPoly(img, [big_closest], big_closest_color) - img = cv2.fillPoly(img, [big_future], big_future_color) - img = cv2.fillPoly(img, [small_closest], small_closest_color) - img = cv2.fillPoly(img, [small_future], small_future_color) - - img_array = 0.3 * img + img_array - - cv2.imwrite("test.png", img_array) diff --git a/examples/lifelong_learning/robot_dog_delivery/RFNet/robo_infer_service.py b/examples/lifelong_learning/robot_dog_delivery/RFNet/robo_infer_service.py deleted file mode 100644 index ce1ab83b..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/RFNet/robo_infer_service.py +++ /dev/null @@ -1,335 +0,0 @@ -# Copyright 2021 The KubeEdge 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 time -from io import BytesIO -from typing import Optional, Any - -import cv2 -import numpy as np -from PIL import Image -import uvicorn -from pydantic import BaseModel -from fastapi import FastAPI, UploadFile, File -from fastapi.routing import APIRoute -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import HTMLResponse -from sedna.common.utils import get_host_ip -from sedna.common.config import BaseConfig -from sedna.common.config import Context - -from predict import init_ll_job, preprocess -from ramp_postprocess import get_ramp - - -class ImagePayload(BaseModel): - image: UploadFile = File(...) - depth: Optional[UploadFile] = None - - -class ResultModel(BaseModel): - type: int = 0 - box: Any = None - curr: str = None - future: str = None - img: str = None - ramp: str = None - - -class ResultResponse(BaseModel): - msg: str = "" - result: Optional[ResultModel] = None - code: int - - -class BaseServer: - # pylint: disable=too-many-instance-attributes,too-many-arguments - DEBUG = True - WAIT_TIME = 15 - - def __init__( - self, - servername: str, - host: str, - http_port: int = 8080, - grpc_port: int = 8081, - workers: int = 1, - ws_size: int = 16 * 1024 * 1024, - ssl_key=None, - ssl_cert=None, - timeout=300): - self.server_name = servername - self.app = None - self.host = host or '0.0.0.0' - self.http_port = http_port or 80 - self.grpc_port = grpc_port - self.workers = workers - self.keyfile = ssl_key - self.certfile = ssl_cert - self.ws_size = int(ws_size) - self.timeout = int(timeout) - protocal = "https" if self.certfile else "http" - self.url = f"{protocal}://{self.host}:{self.http_port}" - - def run(self, app, **kwargs): - if hasattr(app, "add_middleware"): - app.add_middleware( - CORSMiddleware, allow_origins=["*"], allow_credentials=True, - allow_methods=["*"], allow_headers=["*"], - ) - - uvicorn.run( - app, - host=self.host, - port=self.http_port, - ssl_keyfile=self.keyfile, - ssl_certfile=self.certfile, - workers=self.workers, - timeout_keep_alive=self.timeout, - **kwargs) - - def get_all_urls(self): - url_list = [{"path": route.path, "name": route.name} - for route in getattr(self.app, 'routes', [])] - return url_list - - -class InferenceServer(BaseServer): # pylint: disable=too-many-arguments - """ - rest api server for inference - """ - - def __init__( - self, - servername, - host: str, - http_port: int = 30001, - max_buffer_size: int = 104857600, - workers: int = 1): - super( - InferenceServer, - self).__init__( - servername=servername, - host=host, - http_port=http_port, - workers=workers) - - self.ll_job = init_ll_job() - - self.inference_image_dir = os.environ.get("IMAGE_TOPIC_URL", os.path.join( - BaseConfig.data_path_prefix, "inference_images")) - os.makedirs(self.inference_image_dir, exist_ok=True) - - self.max_buffer_size = max_buffer_size - self.app = FastAPI( - routes=[ - APIRoute( - f"/{servername}", - self.model_info, - methods=["GET"], - ), - APIRoute( - f"/{servername}/predict", - self.predict, - methods=["POST"], - response_model=ResultResponse - ), - ], - log_level="trace", - timeout=600, - ) - self.index_frame = 0 - - def start(self): - return self.run(self.app) - - @staticmethod - def model_info(): - return HTMLResponse( - """

Welcome to the RestNet API!

-

To use this service, send a POST HTTP request to {this-url}/predict

-

The JSON payload has the following format: {"image": "BASE64_STRING_OF_IMAGE", - "depth": "BASE64_STRING_OF_DEPTH"}

- """) - - async def predict(self, image: UploadFile = File(...), depth: Optional[UploadFile] = None) -> ResultResponse: - contents = await image.read() - start_time = time.time() - self.image = Image.open(BytesIO(contents)).convert('RGB') - self.image.save(os.path.join( - self.inference_image_dir, f"{str(time.time())}.png")) - - self.index_frame = self.index_frame + 1 - - img_rgb = Image.fromarray(np.array(self.image)) - if depth: - depth_contents = await depth.read() - depth = Image.open(BytesIO(depth_contents)).convert('RGB') - img_dep = cv2.resize(np.array(depth), (2048, 1024), - interpolation=cv2.INTER_CUBIC) - img_dep = Image.fromarray(img_dep) - else: - img_dep = img_rgb - - sample = {'image': img_rgb, "depth": img_dep, "label": img_rgb} - predict_data = preprocess(sample) - end_time1 = time.time() - print("preprocess time:", end_time1 - start_time) - - end_time2 = time.time() - prediction, is_unseen_task, _ = self.ll_job.inference(predict_data) - end_time3 = time.time() - print("inference time: ", end_time3 - end_time2) - if is_unseen_task: - return { - "msg": "", - "result": { - "type": 1, - "box": '', - "img": '', - "curr": '', - "future": '', - "ramp": '' - }, - "code": 0 - } - - # curb_results, ramp_results = results - - img_rgb = cv2.resize(np.array(self.image), - (2048, 1024), interpolation=cv2.INTER_CUBIC) - img_rgb = Image.fromarray(np.array(img_rgb)) - - results = post_process(prediction) - curr, future = get_curb(results["result"]["box"], img_rgb) - results["result"]["curr"] = curr - results["result"]["future"] = future - results["result"]["box"] = None - if Context.get_parameters("robo_skill") == "ramp_detection": - results["result"]["ramp"] = get_ramp( - prediction[0].tolist(), img_rgb) - else: - results["result"]["ramp"] = "no_ramp" - - end_time4 = time.time() - print("total time:", end_time4 - start_time) - return results - - -def parse_result(label, count): - label_map = ['road', 'sidewalk'] - count_d = dict(zip(label, count)) - curb_count = count_d.get(19, 0) - if curb_count / np.sum(count) > 0.2: # > 0.3 - return "curb" - r = sorted(label, key=count_d.get, reverse=True)[0] - try: - c = label_map[r] - except: - c = "other" - - return c - - -def get_curb(results, img_rgb): - results = np.array(results[0]) - input_height, input_width = results.shape - - # small trapezoid - closest = np.array([ - [0, int(input_height)], - [int(input_width), - int(input_height)], - [int(0.882 * input_width + .5), - int(.8 * input_height + .5)], - [int(0.118 * input_width + .5), - int(.8 * input_height + .5)] - ]) - - future = np.array([ - [int(0.118 * input_width + .5), - int(.8 * input_height + .5)], - [int(0.882 * input_width + .5), - int(.8 * input_height + .5)], - [int(.765 * input_width + .5), - int(.66 * input_height + .5)], - [int(.235 * input_width + .5), - int(.66 * input_height + .5)] - ]) - - # big trapezoid - # closest = np.array([ - # [0, int(input_height)], - # [int(input_width), - # int(input_height)], - # [int(0.882 * input_width + .5), - # int(.7 * input_height + .5)], - # [int(0.118 * input_width + .5), - # int(.7 * input_height + .5)] - # ]) - # - # future = np.array([ - # [int(0.118 * input_width + .5), - # int(.7 * input_height + .5)], - # [int(0.882 * input_width + .5), - # int(.7 * input_height + .5)], - # [int(.765 * input_width + .5), - # int(.5 * input_height + .5)], - # [int(.235 * input_width + .5), - # int(.5 * input_height + .5)] - # ]) - - # _draw_closest_and_future(closest, future, img_rgb) - - mask = np.zeros((input_height, input_width), dtype=np.uint8) - mask = cv2.fillPoly(mask, [closest], 1) - mask = cv2.fillPoly(mask, [future], 2) - d1, c1 = np.unique(results[mask == 1], return_counts=True) - d2, c2 = np.unique(results[mask == 2], return_counts=True) - c = parse_result(d1, c1) - f = parse_result(d2, c2) - - return c, f - - -def _draw_closest_and_future(closest, future, img_rgb): - img_array = np.array(img_rgb) - closest_color = [0, 191, 255] - future_color = [255, 69, 0] - - img_array = cv2.fillPoly(img_array, [closest], closest_color) - img_array = cv2.fillPoly(img_array, [future], future_color) - - new_img = Image.fromarray(img_array) - new_img.save("test.png") - - -def post_process(res): - res = res[0].tolist() - type = 0 - mesg = { - "msg": "", - "result": { - "type": type, - "box": res - }, - "code": 0 - } - return mesg - - -if __name__ == '__main__': - web_app = InferenceServer("lifelong-learning-robo", host=get_host_ip()) - web_app.start() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/battery/simplebattery.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/battery/simplebattery.yaml deleted file mode 100644 index 47112c41..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/battery/simplebattery.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "battery" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_battery_driver" -data: - support: true - target: "/battery_level" - actual_hz: 1 - origin_hz: 10 -requirement: # Used to generate roslaunch files. - - deep_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/camera/realsense435i.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/camera/realsense435i.yaml deleted file mode 100644 index c64aa005..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/camera/realsense435i.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: "d435i" -manufacturer: "intel" -series: "stereo depth" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_rgbd_camera_driver" -rgb: - support: true - encoding: "bgr8" - target: "/camera/color/image_raw" # Topic in ros or function in class - width: 320 - height: 240 - actual_hz: 30 - origin_hz: 30 - pan: # pan value allowed for the camera platform - min: -2.7 - max: 2.6 - tilt: - min: -1.4 - max: 1.75 -depth: - support: true - encoding: "passthrough" - map_factor: 0 # Factor to scale depth image by to convert it into meters - target: "/camera/depth/image_rect_raw" - aligned_depth_to_color: "/camera/aligned_depth_to_color/image_raw" - width: 320 - height: 240 - actual_hz: 30 - origin_hz: 30 -info: - target: "/camera/color/camera_info" - actual_hz: 30 - origin_hz: 30 -pcd: - support: false -requirement: # Used to generate roslaunch files. - - cv_bridge - - std_msgs - - sensor_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/common/movebase.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/common/movebase.yaml deleted file mode 100644 index 1f9272bf..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/common/movebase.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: "movebase" -description: "" -driver: - version: "ros1" - type: "ros" - name: "MoveBase" -target: - goal: "/move_base_simple/goal" # goal to be pusblished - status: "/move_base/status" # topic used to get status of movebase - cancel: "/move_base/cancel" # topic used to cancel the goal sent to movebase - action: "/move_base" # Ros action topic for movebase - move_vel: "/cmd_vel" # topic used to set velocity - laserscan: "/scan" - mapframe: "map" # world frame name -localizer: - algorithm: "odom" - parameters: - - key: "mapframe" - value: "map" -limited: - min_distance: 0.1 - exec_time: 0 -requirement: # Used to generate roslaunch files. - - actionlib - - actionlib_msgs - - move_base_msgs - - geometry_msgs - - tf diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/control/x20control.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/control/x20control.yaml deleted file mode 100644 index a6c97f38..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/control/x20control.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: "ysc_control" -description: "" -driver: - version: "0.0.1" - type: "ros" - name: "ysc_control" -parameter: - local_port: 20002 - ctrl_ip: '192.168.1.120' - ctrl_port: 43893 - gait_topic: "/robot_gait_state" -requirement: # Used to generate roslaunch files. - - deep_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/imu/simpleimu.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/imu/simpleimu.yaml deleted file mode 100644 index 3f8b5ae6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/imu/simpleimu.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "imu" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_imu_driver" -data: - support: true - target: "/imu" - actual_hz: 10 - origin_hz: 200 -requirement: # Used to generate roslaunch files. - - sensor_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/odom/simpleodom.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/odom/simpleodom.yaml deleted file mode 100644 index 7054ed99..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/odom/simpleodom.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: "odom" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_common_driver" -data: - support: true - target: "/odom" - pose: "initialpose" - mapframe: "map" # world frame name - actual_hz: 10 - origin_hz: 200 -requirement: # Used to generate roslaunch files. - - nav_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/robots/ysc_x20.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/robots/ysc_x20.yaml deleted file mode 100644 index 796719d7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/robots/ysc_x20.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: "绝影x20" -manufacturer: "ysc" -series: "x20" -description: "quadruped robot dog" -environment: - backend: "ros1" # ros / ros2 / harmony - requirement: - - rospy - - rostopic - - roslib -sensors: - camera: - - name: "camera_front_up" - config: "realsense435i" - rgb: - target: "/camera_front_up/color/image_raw" # Topic in ros or function in class - actual_hz: 10 - origin_hz: 30 - depth: - target: "/camera_front_up/depth/image_rect_raw" - aligned_depth_to_color: "/camera_front_up/aligned_depth_to_color/image_raw" - info: - target: "/camera_front_up/color/camera_info" - - name: "camera_front_down" - config: "realsense435i" - rgb: - target: "/camera_front_down/color/image_raw" - actual_hz: 10 - origin_hz: 30 - depth: - target: "/camera_front_down/depth/image_rect_raw" - aligned_depth_to_color: "/camera_front_down/aligned_depth_to_color/image_raw" - info: - target: "/camera_front_up/color/camera_info" - imu: - - name: "simple_imu" - config: "simpleimu" - data: - target: "/imu" - actual_hz: 10 - origin_hz: 199 - battery: - - name: "battery" - config: "simplebattery" - data: - target: "/battery_level" - actual_hz: 1 - origin_hz: 10 - odom: - - name: "odom" - config: "simpleodom" - data: - target: "/odom" - actual_hz: 10 - origin_hz: 200 -navigation: - name: "base_planner" - config: "movebase" - target: - goal: "/move_base_simple/goal" # get goal - status: "/move_base/status" # execution status is available - cancel: "/move_base/cancel" # cancel the goal sent to movebase - action: "/move_base" # base action command - planner: "/move_base/GlobalPlanner/make_plan" - move: "/cmd_vel" - laserscan: "/scan" - mapframe: "map" # world frame name - localizer: - algorithm: "odom" - parameter: - - key: "mapframe" - value: "map" - - key: "topic" - value: "/odom" - - key: "pose_pub" - value: "/initialpose" -control: - - legged: - name: "ysc_control" # control method supported by vendor - config: "x20control" diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/system.custom.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/system.custom.yaml deleted file mode 100644 index 3b9c8253..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/configs/system.custom.yaml +++ /dev/null @@ -1 +0,0 @@ -task_id: "xdkwx" diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Battery.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Battery.msg deleted file mode 100644 index 090755bb..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Battery.msg +++ /dev/null @@ -1,2 +0,0 @@ -Header header -float32 data \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdGo.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdGo.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdGo.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdInit.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdInit.msg deleted file mode 100644 index cd03a566..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdInit.msg +++ /dev/null @@ -1,3 +0,0 @@ -float64 x -float64 y -float64 yaw \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdMode.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdMode.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdMode.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdPower.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdPower.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdPower.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdResp.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdResp.msg deleted file mode 100644 index ddf8fa3e..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdResp.msg +++ /dev/null @@ -1 +0,0 @@ -string msg \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSet.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSet.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSet.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSway.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSway.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdSway.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdTurn.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdTurn.msg deleted file mode 100644 index ff5552e6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdTurn.msg +++ /dev/null @@ -1 +0,0 @@ -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdVideo.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdVideo.msg deleted file mode 100644 index 6fbf97b8..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/CmdVideo.msg +++ /dev/null @@ -1,2 +0,0 @@ -uint8 camID -bool cmd \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Driver.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Driver.msg deleted file mode 100644 index 090755bb..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Driver.msg +++ /dev/null @@ -1,2 +0,0 @@ -Header header -float32 data \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Gait.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Gait.msg deleted file mode 100644 index 8c5f757a..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Gait.msg +++ /dev/null @@ -1,2 +0,0 @@ -Header header -int32 data \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Motor.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Motor.msg deleted file mode 100644 index 090755bb..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/Motor.msg +++ /dev/null @@ -1,2 +0,0 @@ -Header header -float32 data \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotLog.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotLog.msg deleted file mode 100644 index da66ca85..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotLog.msg +++ /dev/null @@ -1,2 +0,0 @@ -uint8 level -string msg \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotMovement.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotMovement.msg deleted file mode 100644 index bf90b56f..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotMovement.msg +++ /dev/null @@ -1,7 +0,0 @@ -float32 mileage -float32 speed -float32 acceleration -float32 direction -float32 roll -float32 pitch -float32 yaw \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotNav.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotNav.msg deleted file mode 100644 index cd03a566..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotNav.msg +++ /dev/null @@ -1,3 +0,0 @@ -float64 x -float64 y -float64 yaw \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotStatus.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotStatus.msg deleted file mode 100644 index 248b4493..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/deep_msgs/msg/RobotStatus.msg +++ /dev/null @@ -1,4 +0,0 @@ -uint16 energy -uint16 runtime -string movement -string perception \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/package.xml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/package.xml deleted file mode 100644 index af3dd73b..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/package.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - deep_msgs - 0.0.0 - The deep_msgs package - - - - - luoteng-emoji - - - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - catkin - roscpp - rospy - std_msgs - roscpp - rospy - std_msgs - roscpp - rospy - std_msgs - - - - - - - -message_generation -message_generation -message_runtime - \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/__init__.py deleted file mode 100644 index 04e3d6e0..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2021 The KubeEdge 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. diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_interface.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_interface.py deleted file mode 100644 index 201c40ba..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_interface.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2021 The KubeEdge 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 cv2 -import time -import requests -import tenacity -from tenacity import retry -import numpy as np -from robosdk.utils.logger import logging - -LOGGER = logging.bind(instance="lifelong-learning-robo") - - -@retry(stop=tenacity.stop_after_attempt(5), - retry=tenacity.retry_if_result(lambda x: x is None), - wait=tenacity.wait_fixed(1)) -def http_request(url, method=None, timeout=None, binary=True, **kwargs): - _maxTimeout = timeout if timeout else 10 - _method = "GET" if not method else method - try: - response = requests.request(method=_method, url=url, **kwargs) - if response.status_code == 200: - return (response.json() if binary else - response.content.decode("utf-8")) - elif 200 < response.status_code < 400: - LOGGER.info(f"Redirect_URL: {response.url}") - LOGGER.warning( - 'Get invalid status code %s while request %s', - response.status_code, - url) - except (ConnectionRefusedError, requests.exceptions.ConnectionError): - LOGGER.warning(f'Connection refused while request {url}') - except requests.exceptions.HTTPError as err: - LOGGER.warning(f"Http Error while request {url} : f{err}") - except requests.exceptions.Timeout as err: - LOGGER.warning(f"Timeout Error while request {url} : f{err}") - except requests.exceptions.RequestException as err: - LOGGER.warning(f"Error occurred while request {url} : f{err}") - - -class Estimator: - def __init__(self, service_name="lifelong-learning-robo", - input_size=(240, 424)): - self.input_height, self.input_width = input_size - self.remote_ip = os.getenv("BIG_MODEL_IP", "http://localhost") - self.port = int(os.getenv("BIG_MODEL_PORT", "8080")) - self.endpoint = f"{self.remote_ip}:{self.port}/{service_name}/predict" - self.curr_gait = "" - self.fps = 30 - self.inferDangerCount = 0 - self.hold_time = 3 - self.freq = cv2.getTickFrequency() - self.last_change = int(time.time()) - self._poly = np.array([ - [0, int(self.input_height)], - [int(self.input_width), - int(self.input_height)], - [int(0.764 * self.input_width + .5), - int(0.865 * self.input_height + .5)], - [int(0.236 * self.input_width + .5), - int(0.865 * self.input_height + .5)] - ], dtype=np.int32) - - def predict(self, rgb, depth): - t1 = cv2.getTickCount() - image = cv2.imencode('.jpg', rgb)[1].tobytes() - depth = cv2.imencode('.jpg', depth)[1].tobytes() - orig_h, orig_w, _ = rgb.shape - result = http_request( - self.endpoint, method="POST", files={ - "image": ('rgb.jpg', image, "image/jpeg"), - "depth": None - } - ) - t2 = cv2.getTickCount() - time1 = (t2 - t1) / self.freq - self.fps = round(1 / time1, 2) - - if not isinstance(result, dict): - return - - msg = result.get("msg", "") - r = result.get("result", {}) - - code = int(result.get("code", 1)) if str( - result.get("code", 1)).isdigit() else 1 - if len(msg) and code != 0: - LOGGER.warning(msg) - return - - _type = int(r.get("type", 1)) - if _type == 1: - self.curr_gait = "stop" - LOGGER.warning("unknown result") - step = 1.0 / self.fps - - c = r.get("curr", "unknown") - f = r.get("future", "unknown") - if c == "curb" or f == "curb" or c != f: - self.inferDangerCount = min(self.inferDangerCount + step, 10) - else: - self.inferDangerCount = max(self.inferDangerCount - 2 * step, 0) - - if self.inferDangerCount > 1: - self.curr_gait = "up-stair" - # self.last_change = int(time.time()) - elif self.inferDangerCount == 0: - # now = int(time.time()) - # if now - self.last_change > self.hold_time: - self.curr_gait = "trot" - - location = result.get("result").get("ramp") - return location - -if __name__ == '__main__': - os.environ["BIG_MODEL_IP"] = "http://100.94.29.220" - os.environ["BIG_MODEL_PORT"] = "30001" - f1 = "./E1_door.1716.rgb.png" - f2 = "./E1_door.1716.depth.png" - _frame = cv2.imread(f1) - _depth = cv2.imread(f2, -1) / 1000 - d = Estimator() - cv2.imwrite("./frame_1716.out.png", d.predict(_frame, _depth)) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_main.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_main.py deleted file mode 100644 index e5bede76..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/integration_main.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2021 The KubeEdge 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 time -import threading -import numpy as np -import multiprocessing -from cv_bridge import CvBridge -from robosdk.core import Robot -from robosdk.utils.context import Context -from robosdk.utils.constant import GaitType -from robosdk.msgs.sender.ros import RosMessagePublish - -from ramp_detection.integration_interface import Estimator - -class Detection: - def __init__(self): - self.robot = Robot(name="x20", config="ysc_x20") - self.segment = Estimator() - self.robot.connect() - self.publish = RosMessagePublish() - _topic = Context.get("curb_detection", "/robovideo") - self.publish.register("curb_detection", topic=_topic, - converter=CvBridge().cv2_to_imgmsg, - convert_param={"encoding": "bgr8"}) - # self.robot.navigation.speed(0.4) - self.stair_start_time = None - self.stair_hold_time = 7 - self.complete_change_upstair_time = None - self.unseen_sample_threshold = 3 - self.unseen_sample_num = 0 - - def run(self): - if not getattr(self.robot, "camera", ""): - return - while 1: - img, dep = self.robot.camera.get_rgb_depth() - if img is None: - continue - - result = self.segment.predict(img, depth=dep) - if not result: - self.robot.logger.info("Unseen sample detected.") - # self.unseen_sample_num += 1 - # if self.unseen_sample_num >= self.unseen_sample_threshold: - # self.robot.logger.info("Stop in front of unseen sample!") - # for _ in range(3): - # self.robot.navigation.stop() - # self.unseen_sample_num = 0 - continue - # else: - # self.unseen_sample_num = 0 - - if result == "no_ramp": - self.process_curb(result, img) - else: - self.process_ramp(result) - - def process_curb(self, result, img): - current_time = time.time() - if self.stair_start_time and current_time - self.stair_start_time < self.stair_hold_time: - return - elif self.stair_start_time and current_time - self.stair_start_time >= self.stair_hold_time: - self.stair_start_time = None - - if self.segment.curr_gait == "up-stair": - self.robot.logger.info("match curb") - gait = threading.Thread(name="", target=self.change_to_upstair) - stop = threading.Thread(name="", target=self.stop) - gait.start() - stop.start() - self.stair_start_time = time.time() - elif self.segment.curr_gait == "trot": - self.robot.logger.info("unmatch curb") - self.robot.control.change_gait(GaitType.TROT) - - def process_ramp(self, location): - if location == "small_trapezoid": - self.robot.logger.info(f"Ramp location: {location}. Keep moving.") - self.robot.navigation.go_forward() - return - - self.robot.logger.info(f"Ramp detected: {location}.") - - if location == "upper_left" or location == "center_left": - self.robot.logger.info("Move to the left!") - self.robot.navigation.turn_left() - - elif location == "bottom_left": - self.robot.logger.info("Backward and move to the left!") - self.robot.navigation.go_backward() - self.robot.navigation.turn_left() - - elif location == "upper_right" or location == "center_right": - self.robot.logger.info("Move to the right!") - self.robot.navigation.turn_right() - - elif location == "bottom_right": - self.robot.logger.info("Backward and move to the right!") - self.robot.navigation.go_backward() - self.robot.navigation.turn_right() - - self.robot.navigation.go_forward() - - def change_to_upstair(self): - self.robot.control.change_gait(GaitType.UPSTAIR) - self.complete_change_upstair_time = time.time() - # print("complete_time:", self.complete_change_upstair_time) - - def stop(self): - print("Stop in front of curb!") - while 1: - self.robot.navigation.stop() - if self.complete_change_upstair_time is not None: - break - self.complete_change_upstair_time = None - - - -if __name__ == '__main__': - project = Detection() - project.run() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/interface.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/interface.py deleted file mode 100644 index 7210dbdb..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/interface.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2021 The KubeEdge 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 cv2 -import time -import requests -import tenacity -from tenacity import retry -import numpy as np -from robosdk.utils.logger import logging - -LOGGER = logging.bind(instance="lifelong-learning-robo") - - -@retry(stop=tenacity.stop_after_attempt(5), - retry=tenacity.retry_if_result(lambda x: x is None), - wait=tenacity.wait_fixed(1)) -def http_request(url, method=None, timeout=None, binary=True, **kwargs): - _maxTimeout = timeout if timeout else 10 - _method = "GET" if not method else method - try: - response = requests.request(method=_method, url=url, **kwargs) - if response.status_code == 200: - return (response.json() if binary else - response.content.decode("utf-8")) - elif 200 < response.status_code < 400: - LOGGER.info(f"Redirect_URL: {response.url}") - LOGGER.warning( - 'Get invalid status code %s while request %s', - response.status_code, - url) - except (ConnectionRefusedError, requests.exceptions.ConnectionError): - LOGGER.warning(f'Connection refused while request {url}') - except requests.exceptions.HTTPError as err: - LOGGER.warning(f"Http Error while request {url} : f{err}") - except requests.exceptions.Timeout as err: - LOGGER.warning(f"Timeout Error while request {url} : f{err}") - except requests.exceptions.RequestException as err: - LOGGER.warning(f"Error occurred while request {url} : f{err}") - - -class Estimator: - def __init__(self, service_name="lifelong-learning-robo", - input_size=(240, 424)): - self.input_height, self.input_width = input_size - self.remote_ip = os.getenv("BIG_MODEL_IP", "http://localhost") - self.port = int(os.getenv("BIG_MODEL_PORT", "8080")) - self.endpoint = f"{self.remote_ip}:{self.port}/{service_name}/predict" - self.curr_gait = "" - self.fps = 30 - self.inferDangerCount = 0 - self.hold_time = 3 - self.freq = cv2.getTickFrequency() - self.last_change = int(time.time()) - self._poly = np.array([ - [0, int(self.input_height)], - [int(self.input_width), - int(self.input_height)], - [int(0.764 * self.input_width + .5), - int(0.865 * self.input_height + .5)], - [int(0.236 * self.input_width + .5), - int(0.865 * self.input_height + .5)] - ], dtype=np.int32) - - def predict(self, rgb, depth): - image = cv2.imencode('.jpg', rgb)[1].tobytes() - orig_h, orig_w, _ = rgb.shape - result = http_request( - self.endpoint, method="POST", files={ - "image": ('rgb.jpg', image, "image/jpeg"), - # "depth": ('dep.jpg', depth, "image/jpeg"), - } - ) - - return result - -if __name__ == '__main__': - os.environ["BIG_MODEL_IP"] = "http://100.94.29.220" - os.environ["BIG_MODEL_PORT"] = "30001" - f1 = "./E1_door.1716.rgb.png" - f2 = "./E1_door.1716.depth.png" - _frame = cv2.imread(f1) - _depth = cv2.imread(f2, -1) / 1000 - d = Estimator() - cv2.imwrite("./frame_1716.out.png", d.predict(_frame, _depth)) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/main.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/main.py deleted file mode 100644 index 6b204561..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/ramp_detection/main.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from cv_bridge import CvBridge -from robosdk.core import Robot -from robosdk.utils.context import Context -from robosdk.msgs.sender.ros import RosMessagePublish - -from ramp_detection.interface import Estimator - - -class Detection: - def __init__(self): - self.robot = Robot(name="x20", config="ysc_x20") - self.segment = Estimator() - self.robot.connect() - self.publish = RosMessagePublish() - _topic = Context.get("curb_detection", "/robovideo") - self.publish.register("curb_detection", topic=_topic, - converter=CvBridge().cv2_to_imgmsg, - convert_param={"encoding": "bgr8"}) - - def run(self): - if not getattr(self.robot, "camera", ""): - return - while 1: - img, dep = self.robot.camera.get_rgb_depth() - if img is None: - continue - result = self.segment.predict(img, depth=dep) - print(result) - -if __name__ == '__main__': - project = Detection() - project.run() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements-sdk.txt b/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements-sdk.txt deleted file mode 100644 index 9c91ce37..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements-sdk.txt +++ /dev/null @@ -1,8 +0,0 @@ -loguru~=0.6.0 # MIT -minio~=7.0.3 # Apache-2.0 -numpy>=1.13.3 # BSD -requests~=2.27.1 # MIT -Pillow~=9.0.1 -pydantic~=1.9.0 # MIT -websockets~=9.1 # BSD -tenacity~=8.0.1 # Apache-2.0 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements.txt b/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements.txt deleted file mode 100644 index 66c26594..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -pytest~=4.6.9 -setuptools~=58.3.0 -numpy~=1.21.5 -Pillow~=9.0.1 -requests==2.24.0 -tenacity \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/VERSION b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/VERSION deleted file mode 100644 index 8a9ecc2e..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.0.1 \ No newline at end of file diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/__version__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/__version__.py deleted file mode 100644 index a0581c7c..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/__version__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2021 The KubeEdge 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 - - -_VERSION = os.path.join(os.path.dirname(__file__), "VERSION") - -with open(_VERSION, "r", encoding="utf-8") as fin: - tmp = [line.strip() for line in fin if line.strip()] - __version__ = "-".join(tmp) if tmp else "dev" diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/__init__.py deleted file mode 100644 index 70638ecc..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .image_selection import SimpleSelection diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/base.py deleted file mode 100644 index 130403c6..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/base.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -from typing import List - -from robosdk.utils.logger import logging -from robosdk.utils.util import Config -from robosdk.utils.util import ImageQualityEval - - -__all__ = ("Resolution", ) - - -class Resolution(metaclass=abc.ABCMeta): - def __init__(self, name: str, config: Config): - self.resolution_name = name - self.config = config - if (getattr(self.config, "image", "") and - hasattr(self.config.image, "eval")): - eval_func = self.config.image.eval - else: - eval_func = "vollath" - self.eval = getattr( - ImageQualityEval, eval_func, ImageQualityEval.vollath) - self.logger = logging.bind(instance=self.resolution_name, system=True) - - @abc.abstractmethod - def inference(self, imgs: List): - ... diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/image_selection.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/image_selection.py deleted file mode 100644 index 7980c2ed..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/image/image_selection.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from typing import List - -import cv2 -import numpy as np - -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.util import Config -from robosdk.utils.exceptions import SensorError - -from .base import Resolution - - -__all__ = ("SimpleSelection", ) - - -@ClassFactory.register(ClassType.IMAGE, alias="base_select") -class SimpleSelection(Resolution): # noqa - - def __init__(self, name: str = "base_select", config: Config = None): - super(SimpleSelection, self).__init__(name=name, config=config) - - def inference(self, imgs: List[np.ndarray]) -> np.ndarray: - if not len(imgs): - raise SensorError("No input images found") - if len(imgs) == 1: - return imgs[0] - s = sorted(imgs, key=lambda j: self.eval( - cv2.cvtColor(j, cv2.COLOR_BGR2GRAY))) - return s[-1] diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/__init__.py deleted file mode 100644 index 84a7f046..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .odom import Odom diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/base.py deleted file mode 100644 index f96525c0..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/base.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import threading - -from robosdk.utils.logger import logging -from robosdk.utils.schema import BasePose - - -__all__ = ("Localize", ) - - -class Localize(metaclass=abc.ABCMeta): - - def __init__(self, name: str = "base_localizer"): - self.localize_name = name - self.state_lock = threading.RLock() - self.curr_state = BasePose() - self.logger = logging.bind(instance=self.localize_name, system=True) - - @abc.abstractmethod - def get_curr_state(self) -> BasePose: - ... - - @abc.abstractmethod - def set_curr_state(self, state: BasePose): - ... diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/odom.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/odom.py deleted file mode 100644 index ad6dd063..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/localize/odom.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2021 The KubeEdge 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 copy - -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.schema import BasePose - -from .base import Localize - - -@ClassFactory.register(ClassType.LOCALIZE, alias="odom") -class Odom(Localize): # noqa - def __init__(self, name: str = "Odometry", - mapframe: str = "map", - topic: str = "/odom", - pose_pub: str = "/initialpose" - ): - super(Odom, self).__init__(name=name) - - import rospy - from nav_msgs.msg import Odometry - from geometry_msgs.msg import PoseWithCovarianceStamped - - rospy.Subscriber( - topic, - Odometry, - self.get_odom_state, - ) - self.initial_pose = rospy.Publisher( - pose_pub, - PoseWithCovarianceStamped, - queue_size=1 - ) - self.mapframe = mapframe or "map" - - def get_odom_state(self, msg): - - import tf.transformations - - self.state_lock.acquire() - orientation = msg.pose.pose.orientation - _, _, z = tf.transformations.euler_from_quaternion( - [orientation.x, orientation.y, orientation.z, orientation.w] - ) - self.curr_state.x = msg.pose.pose.position.x - self.curr_state.y = msg.pose.pose.position.y - self.curr_state.z = z - self.state_lock.release() - - def get_curr_state(self, **kwargs) -> BasePose: - state = copy.deepcopy(self.curr_state) - return state - - def set_curr_state(self, state: BasePose): - - import rospy - import tf.transformations - from geometry_msgs.msg import PoseWithCovarianceStamped - - self.curr_state.x = state.x - self.curr_state.y = state.y - self.curr_state.z = state.z - self.curr_state.w = state.w - - initial_pose = PoseWithCovarianceStamped() - initial_pose.header.seq = 1 - initial_pose.header.stamp = rospy.Time.now() - initial_pose.header.frame_id = self.mapframe - - q = tf.transformations.quaternion_from_euler(0, 0, state.z) - initial_pose.pose.pose.position.x = state.x - initial_pose.pose.pose.position.y = state.y - initial_pose.pose.pose.position.z = 0.0 - - initial_pose.pose.pose.orientation.x = q[0] - initial_pose.pose.pose.orientation.y = q[1] - initial_pose.pose.pose.orientation.z = q[2] - initial_pose.pose.pose.orientation.w = q[3] - for _ in range(10): - self.initial_pose.publish(initial_pose) - rospy.sleep(0.1) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/__init__.py deleted file mode 100644 index 1873d928..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .move_base import MoveBase diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/base.py deleted file mode 100644 index 097ad6f9..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/base.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import threading - -from robosdk.utils.schema import BasePose -from robosdk.utils.schema import PathNode -from robosdk.utils.logger import logging -from robosdk.utils.util import Config -from robosdk.cloud_robotics.task_agent.base import RoboActionHandle - -__all__ = ("Navigation", ) - - -class Navigation(metaclass=abc.ABCMeta): - - def __init__(self, name: str, config: Config): - self.navigation_name = name - self.config = config - self.move_base_as = None - self.goal_lock = threading.RLock() - self.logger = logging.bind(instance=self.navigation_name, system=True) - - @abc.abstractmethod - def execute_track(self, plan: PathNode): - ... - - @abc.abstractmethod - def goto(self, goal: BasePose): - ... - - @abc.abstractmethod - def goto_absolute(self, goal: BasePose): - ... - - def stop(self): - self.set_vel(forward=0.0, turn=0.0, execution=3) - - @abc.abstractmethod - def set_vel(self, - forward: float = 0, - turn: float = 0, - execution: int = 1): - """ - set velocity to robot - :param forward: linear velocity in m/s - :param turn: rotational velocity in m/s - :param execution: execution time in seconds - """ - ... - - def set_action_server(self, action: RoboActionHandle): - self.move_base_as = action diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/move_base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/move_base.py deleted file mode 100644 index 909d4501..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/navigation/move_base.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -from importlib import import_module - -import numpy as np - -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.util import Config -from robosdk.utils.schema import BasePose -from robosdk.utils.schema import PathNode -from robosdk.utils.constant import ActionStatus -from robosdk.cloud_robotics.task_agent.base import RoboActionHandle - -from .base import Navigation - -__all__ = ("MoveBase",) - - -@ClassFactory.register(ClassType.NAVIGATION) -class MoveBase(Navigation): # noqa - - def __init__(self, - name: str = "MoveBase", - config: Config = None - ): - super(MoveBase, self).__init__(name=name, config=config) - - import rospy - import actionlib - from geometry_msgs.msg import Twist - from sensor_msgs.msg import LaserScan - from move_base_msgs.msg import MoveBaseAction - from actionlib_msgs.msg import GoalStatusArray, GoalID - - self.move_base_ac = actionlib.SimpleActionClient( - self.config.target.action, MoveBaseAction - ) - rospy.Subscriber( - self.config.target.status, - GoalStatusArray, - self._move_base_status_callback, - ) - self.scan_msg = LaserScan() - rospy.Subscriber( - self.config.target.laserscan, LaserScan, - self._laser_scan_callback) - self.move_base_cancel = rospy.Publisher( - self.config.target.cancel, GoalID, queue_size=1 - ) - self.curr_vel = BasePose() - self.vel_pub = rospy.Publisher( - self.config.target.move_vel, Twist, queue_size=1 - ) - self.curr_goal = BasePose() - rospy.Subscriber( - self.config.target.move_vel, Twist, - self._move_vel_callback) - self.localizer = self.get_localize_algorithm_from_config() - - def _move_vel_callback(self, data): - if data is None: - return - self.curr_vel = BasePose( - x=data.linear.x, - y=data.linear.y, - ) - - def get_localize_algorithm_from_config(self, **param): - localizer = None - _param = dict() - if self.config.localizer and self.config.localizer.algorithm: - try: - _ = import_module(f"robosdk.algorithms.localize") - localizer = ClassFactory.get_cls( - ClassType.LOCALIZE, self.config.localizer.algorithm) - except Exception as e: - self.logger.error( - f"Fail to initial localizer algorithm " - f"{self.config.localizer.algorithm} : {e}") - if not localizer: - return - if (self.config.localizer and - isinstance(self.config.localizer.parameter, list)): - _param = { - p["key"]: p.get("value", "") - for p in self.config.localizer.parameter - if isinstance(p, dict) and "key" in p - } - _param.update(**param) - return localizer(**_param) - - def _transform_goal(self, goal: BasePose): - import tf.transformations - from geometry_msgs.msg import PoseStamped - from geometry_msgs.msg import Pose - from geometry_msgs.msg import Point - from geometry_msgs.msg import Quaternion - from move_base_msgs.msg import MoveBaseGoal - - self.goal_lock.acquire() - q = tf.transformations.quaternion_from_euler(0, 0, goal.z) - pose_stamped = PoseStamped( - pose=Pose( - Point(goal.x, goal.y, 0.000), - Quaternion(q[0], q[1], q[2], q[3]) - ) - ) - pose_stamped.header.frame_id = self.config.target.mapframe - target = MoveBaseGoal() - target.target_pose = pose_stamped - self.curr_goal = goal.copy() - self.goal_lock.release() - return target - - def cancel_goal(self): - from actionlib_msgs.msg import GoalID - - self.logger.warning("Goal Cancel") - try: - self.move_base_cancel_goal_pub.publish(GoalID()) - except Exception as err: - self.logger.debug(f"Cancel goal failure: {err}") - self.move_base_ac.cancel_all_goals() - self.stop() - - def _move_base_status_callback(self, msg): - if msg.status_list: - self.execution_status = getattr(msg.status_list[-1], "status") - - def _laser_scan_callback(self, msg): - self.scan_msg = msg - - def execute_track(self, plan: PathNode, min_gap: float = 0): - target = plan.copy() - if not min_gap: - min_gap = self.config.limited.min_distance - while 1: - curr_point = self.get_location() - if curr_point - target <= abs(min_gap): - target = plan.next - if target is None: - self.logger.info("Path planning execute complete") - break - self.goto(goal=target.position) - - def get_location(self, **parameter): - if self.localizer and hasattr(self.localizer, "get_curr_state"): - return self.localizer.get_curr_state(**parameter) - return self.curr_goal.copy() - - def goto(self, goal: BasePose, - start_pos: BasePose = None, - limit_time: int = 0): # noqa - if start_pos is None: - start_pos = self.get_location() - curr_goal = self._get_absolute_pose(goal, start_pos) - return self.goto_absolute(curr_goal, limit_time=limit_time) - - def goto_absolute(self, goal: BasePose, limit_time: int = 0): - self.logger.info(f"Sending the goal, {str(goal)}") - target = self._transform_goal(goal) - return self._send_action_goal(target, limit_time=limit_time) - - @staticmethod - def _get_absolute_pose(goal: BasePose, base: BasePose): - nx = base.x + goal.x * np.cos(base.z) - goal.y * np.sin(base.z) - ny = base.y + goal.x * np.sin(base.z) + goal.y * np.cos(base.z) - nz = base.z + goal.z - return BasePose(x=nx, y=ny, z=nz) - - def _send_action_goal(self, goal, limit_time: int = 0): - import rospy - - self.logger.debug("Waiting for the server") - self.move_base_ac.wait_for_server() - - self.move_base_ac.send_goal(goal) - - self.logger.debug("Waiting for the move_base Result") - exit_without_time = True - if not limit_time: - limit_time = int(self.config.limited.exec_time) - if limit_time > 0: - exit_without_time = self.move_base_ac.wait_for_result( - rospy.Duration(limit_time) - ) - while 1: - if not exit_without_time: - self.cancel_goal() - self.logger.warning("ERROR:Timed out achieving goal") - return False - if ((self.move_base_as and self.move_base_as.should_stop) or - (self.execution_status == ActionStatus.ABORTED.value)): - self.cancel_goal() - return False - if (isinstance(self.move_base_as, RoboActionHandle) - and self.move_base_as.is_preempt): - self.cancel_goal() - return False - if self.execution_status == ActionStatus.SUCCEEDED.value: - return True - rospy.sleep(0.1) - - def set_vel(self, - forward: float = 0, - turn: float = 0, - execution: int = 1): - """ - set velocity to robot - :param forward: linear velocity in m/s - :param turn: rotational velocity in m/s - :param execution: execution time in seconds - """ - - import rospy - from geometry_msgs.msg import Twist - - msg = Twist() - msg.linear.x = forward - msg.angular.z = turn - - stop_time = rospy.get_rostime() + rospy.Duration(execution) - while rospy.get_rostime() < stop_time: - self.vel_pub.publish(msg) - rospy.sleep(.05) - - def turn_right(self): - self.set_vel(1.5, -.7) - - def turn_left(self): - self.set_vel(1.5, .7) - - def go_forward(self): - self.set_vel(1.3, 0) - - def go_backward(self): - self.set_vel(-.5, 0) - - def stop(self): - self.set_vel(0, 0) - - def go_forward_util(self, stop_distance: float = 0.5): - while self.get_front_distance() > stop_distance: - self.set_vel(.1, 0) - self.stop() - - def speed(self, linear: float = 0., rotational: float = 0.): - from geometry_msgs.msg import Twist - - msg = Twist() - msg.linear.x = linear - msg.angular.z = rotational - - self.vel_pub.publish(msg) - - def get_front_distance(self, degree: int = 10) -> float: - if self.scan_msg is not None: - all_data = getattr(self.scan_msg, "ranges", []) - if not len(all_data): - return 0.0 - circle = int(len(all_data) / 2) - left_degree = max(circle - abs(degree), 10) - right_degree = min(circle + abs(degree), len(all_data)) - ranges = list( - filter(lambda x: (x != float('inf') and x != float("-inf")), - all_data[left_degree:right_degree]) - ) - return float(np.mean(ranges)) - return 0.0 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/Astar.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/Astar.py deleted file mode 100644 index 651c9ccc..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/Astar.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -A* grid planning -author: Atsushi Sakai(@Atsushi_twi) - Nikos Kanargias (nkana@tee.gr) -see https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathPlanning/AStar/a_star.py # noqa -""" -import math - -from robosdk.utils.schema import BasePose -from robosdk.utils.schema import PathNode -from robosdk.utils.constant import PgmItem -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - -from .base import PathPlanner -from .base import GridMap - - -__all__ = ("AStar", ) - - -@ClassFactory.register(ClassType.PATHPLANNING) -class AStar(PathPlanner): # noqa - - def __init__(self, - world_map: GridMap, - start: BasePose, - goal: BasePose): - super(AStar, self).__init__( - world_map=world_map, start=start, goal=goal) - self.max_x, self.max_y = self.world.grid.shape - - class Node: - def __init__(self, x, y, cost, parent_index): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, step=0) -> PathNode: - sx, sy = self.s_start.x, self.s_start.y - gx, gy, angle = self.s_goal.x, self.s_goal.y, self.s_goal.z - start_node = self.Node(self.calc_xy_index(sx), - self.calc_xy_index(sy), 0.0, -1) - goal_node = self.Node(self.calc_xy_index(gx), - self.calc_xy_index(gy), 0.0, -1) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(start_node)] = start_node - - while 1: - if len(open_set) == 0: - break - - c_id = min( - open_set, - key=lambda o: (open_set[o].cost + - self.calc_heuristic(goal_node, open_set[o]))) - current = open_set[c_id] - - if current.x == goal_node.x and current.y == goal_node.y: - goal_node.parent_index = current.parent_index - goal_node.cost = current.cost - break - - # Remove the item from the open set - del open_set[c_id] - - # Add it to the closed set - closed_set[c_id] = current - - # expand_grid search grid based on motion model - for i, _ in enumerate(self.motion): - node = self.Node(current.x + self.motion[i][0], - current.y + self.motion[i][1], - current.cost + self.motion[i][2], c_id) - n_id = self.calc_grid_index(node) - if (not self.verify_node(node)) or (n_id in closed_set): - continue - - if n_id not in open_set: - open_set[n_id] = node # discovered a new node - else: - if open_set[n_id].cost > node.cost: - # This path is the best until now. record it - open_set[n_id] = node - - return self.calc_final_path( - goal_node, closed_set, angle=angle, step=step) - - def calc_final_path(self, goal_node, closed_set, angle=0.2, step=0): - # generate final course - - rx, ry = [self.calc_grid_position(goal_node.x)], [ - self.calc_grid_position(goal_node.y)] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(self.calc_grid_position(n.x)) - ry.append(self.calc_grid_position(n.y)) - parent_index = n.parent_index - prev = None - first_node = None - if len(rx) < 4 or step == 1: - sequence = zip(reversed(rx), reversed(ry)) - elif step > 1: - a1, b1 = rx[::-step], ry[::-step] - if a1[-1] != rx[0]: - a1.append(rx[0]) - b1.append(rx[0]) - sequence = zip(a1, b1) - else: # auto gen waypoint - sequence = [] - prev = None - for inx in range(len(rx) - 1, -1, -1): - if (len(sequence) == 0) or (inx == 0): - prev = (rx[inx], ry[inx]) - sequence.append(prev) - continue - _x, _y = rx[inx], ry[inx] - _x_n, _y_n = rx[inx - 1], ry[inx - 1] - if ((_x_n - _x) != (_x - prev[0])) or ( - (_y_n - _y) != (_y - prev[1]) - ): - sequence.append((_x, _y)) - prev = (_x, _y) - for seq, node in enumerate(sequence): - position = self.world.pixel2world(x=node[0], y=node[1], alt=angle) - curr = PathNode( - seq=seq, point=node, position=position, prev=prev - ) - if isinstance(prev, PathNode): - prev.next = curr - else: - first_node = curr - prev = curr - return first_node - - @staticmethod - def calc_heuristic(n1, n2): - w = 1.0 # weight of heuristic - d = w * math.hypot(n1.x - n2.x, n1.y - n2.y) - return d - - @staticmethod - def calc_grid_position(index, min_position=0): - """ - calc grid position - :param index: - :param min_position: - :return: - """ - pos = index + min_position - return pos - - @staticmethod - def calc_xy_index(position, min_pos=0): - return position - min_pos - - def calc_grid_index(self, node): - return node.y * self.max_x + node.x - - def verify_node(self, node): - px = self.calc_grid_position(node.x) - py = self.calc_grid_position(node.y) - - if px <= 0: - return False - elif py <= 0: - return False - elif px >= self.max_x: - return False - elif py >= self.max_y: - return False - - # collision check - if self.world.grid[node.x][node.y] == PgmItem.OBSTACLE.value: - return False - - return True diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/__init__.py deleted file mode 100644 index 5017e5d2..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .Astar import AStar -from .dijkstra import Dijkstra diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/base.py deleted file mode 100644 index dd48f5ce..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/base.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import os -import math -from typing import List - -import yaml -import numpy as np -from PIL import Image - -from robosdk.utils.schema import BasePose -from robosdk.utils.schema import PgmMap -from robosdk.utils.schema import PathNode -from robosdk.utils.constant import PgmItem - - -__all__ = ("GridMap", "PathPlanner") - - -class MapBase(metaclass=abc.ABCMeta): - """ - Map base class - """ - - def __init__(self): - self.info = None - self.grid = None - self.obstacles = None - - @abc.abstractmethod - def parse_panoptic(self, **kwargs): - ... - - @abc.abstractmethod - def add_obstacle(self, **kwargs): - ... - - @abc.abstractmethod - def pixel2world(self, **kwargs) -> BasePose: - ... - - @abc.abstractmethod - def world2pixel(self, **kwargs) -> BasePose: - ... - - -class GridMap(MapBase): # noqa - """ - 2D grid map - """ - - def __init__(self): - super(GridMap, self).__init__() - self.width = 0 - self.height = 0 - self.width_m = 0 - self.height_m = 0 - self.obstacles = [] - self.padding_map = None - - def read_from_pgm(self, config: str, pgm: str = None): - with open(config) as f: - data = yaml.load(f, Loader=yaml.FullLoader) - image = pgm if pgm else data['image'] - if not os.path.isfile(image): - image = os.path.join(os.path.dirname(config), - os.path.basename(image)) - if not os.path.isfile(image): - prefix, _ = os.path.splitext(config) - image = f"{prefix}.pgm" - if not os.path.isfile(image): - raise FileExistsError(f"Read PGM from {config} Error ...") - self.info = PgmMap( - image=image, - resolution=round(float(data['resolution']), 4), - origin=list(map(float, data['origin'])), - reverse=int(data['negate']), - occupied_thresh=data['occupied_thresh'], - free_thresh=data['free_thresh'] - ) - fh = Image.open(image) - self.height, self.width = fh.size - self.width_m = self.width * self.info.resolution - self.height_m = self.height * self.info.resolution - data = np.array(fh) - occ = data / 255. if self.info.reverse else (255. - data) / 255. - - self.grid = np.zeros((self.width, self.height)) + PgmItem.UNKNOWN.value - self.grid[occ > self.info.occupied_thresh] = PgmItem.OBSTACLE.value - self.grid[occ < self.info.free_thresh] = PgmItem.FREE.value - self.obstacles = list(zip(*np.where(occ > self.info.occupied_thresh))) - - def calc_obstacle_map(self, robot_radius: float = 0.01): - if not len(self.obstacles): - return - obstacles = np.array(self.obstacles) - row = obstacles[:, 0] - col = obstacles[:, 1] - x_min, x_max = min(row), max(row) - y_min, y_max = min(col), max(col) - self.grid = self.grid[x_min:x_max, y_min:y_max] - self.padding_map = np.array([x_min, y_min, 0]) - self.obstacles = obstacles - [x_min, y_min] - self.height, self.width = self.grid.shape[:2] - self.width_m = self.width * self.info.resolution - self.height_m = self.height * self.info.resolution - - if self.info.resolution < robot_radius: - # todo: Adjust obstacles to robot size - robot = int(robot_radius / self.info.resolution + 0.5) - for ox, oy in self.obstacles: - self.add_obstacle( - ox - robot, oy - robot, - ox + robot, ox + robot - ) - - def pixel2world(self, - x: float = 0., - y: float = 0., - alt: float = 0.) -> BasePose: - data = np.array([y, x, alt]) - if self.padding_map is not None: - data += self.padding_map - x, y, z = list( - np.array(self.info.origin) + data * self.info.resolution - ) - return BasePose(x=x, y=y, z=z) - - def world2pixel(self, x, y, z=0.0) -> BasePose: - p1 = (np.array([y, x]) - self.info.origin[:2]) / self.info.resolution - if self.padding_map is not None: - p1 -= self.padding_map[:2] - px, py = int(p1[0] + 0.5), int(p1[1] + 0.5) - return BasePose(x=px, y=py, z=z) - - def add_obstacle(self, x1, y1, x2, y2): - pass - - def parse_panoptic(self, panoptic): - pass - - -class PathPlanner(metaclass=abc.ABCMeta): - - def __init__(self, world_map: MapBase, start: BasePose, goal: BasePose): - self.world = world_map - self.motion = [[1, 0, 1], - [0, 1, 1], - [-1, 0, 1], - [0, -1, 1], - [-1, -1, math.sqrt(2)], - [-1, 1, math.sqrt(2)], - [1, -1, math.sqrt(2)], - [1, 1, math.sqrt(2)]] - self.s_start = self.world.world2pixel(x=start.x, y=start.y, z=start.z) - self.s_goal = self.world.world2pixel(x=goal.x, y=goal.y, z=start.z) - - @abc.abstractmethod - def planning(self, **kwargs) -> PathNode: - pass - - def set_motion(self, motions: List): - self.motion = motions.copy() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/dijkstra.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/dijkstra.py deleted file mode 100644 index e430b32e..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/algorithms/path_planning/dijkstra.py +++ /dev/null @@ -1,187 +0,0 @@ -""" - -Grid based Dijkstra planning - -author: Atsushi Sakai(@Atsushi_twi) -see https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathPlanning/Dijkstra/dijkstra.py # noqa -""" - -import math - -from robosdk.utils.schema import BasePose -from robosdk.utils.schema import PathNode -from robosdk.utils.constant import PgmItem -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - -from .base import PathPlanner -from .base import GridMap - - -__all__ = ("Dijkstra", ) - - -@ClassFactory.register(ClassType.PATHPLANNING) -class Dijkstra(PathPlanner): # noqa - - def __init__(self, - world_map: GridMap, - start: BasePose, - goal: BasePose): - super(Dijkstra, self).__init__( - world_map=world_map, start=start, goal=goal - ) - self.max_x, self.max_y = self.world.grid.shape - - class Node: - def __init__(self, x, y, cost, parent_index): - self.x = x # index of grid - self.y = y # index of grid - self.cost = cost - self.parent_index = parent_index # index of previous Node - - def __str__(self): - return str(self.x) + "," + str(self.y) + "," + str( - self.cost) + "," + str(self.parent_index) - - def planning(self, step=0) -> PathNode: - sx, sy = self.s_start.x, self.s_start.y - gx, gy, angle = self.s_goal.x, self.s_goal.y, self.s_goal.z - start_node = self.Node(self.calc_xy_index(sx), - self.calc_xy_index(sy), 0.0, -1) - goal_node = self.Node(self.calc_xy_index(gx), - self.calc_xy_index(gy), 0.0, -1) - - open_set, closed_set = dict(), dict() - open_set[self.calc_grid_index(start_node)] = start_node - - while 1: - if len(open_set) == 0: - break - - c_id = min(open_set, key=lambda o: open_set[o].cost) - current = open_set[c_id] - - if current.x == goal_node.x and current.y == goal_node.y: - goal_node.parent_index = current.parent_index - goal_node.cost = current.cost - break - del open_set[c_id] - closed_set[c_id] = current - - # expand search grid based on motion model - for move_x, move_y, move_cost in self.motion: - node = self.Node(current.x + move_x, current.y + move_y, - current.cost + move_cost, c_id) - n_id = self.calc_grid_index(node) - - if not self.verify_node(node) or (n_id in closed_set): - continue - - if n_id not in open_set: - open_set[n_id] = node # Discover a new node - else: - if open_set[n_id].cost >= node.cost: - # This path is the best until now. record it! - open_set[n_id] = node - - return self.calc_final_path( - goal_node, closed_set, angle=angle, step=step) - - def calc_final_path(self, goal_node, closed_set, angle=0.2, step=0): - # generate final course - rx, ry = [self.calc_grid_position(goal_node.x)], [ - self.calc_grid_position(goal_node.y)] - parent_index = goal_node.parent_index - while parent_index != -1: - n = closed_set[parent_index] - rx.append(self.calc_grid_position(n.x)) - ry.append(self.calc_grid_position(n.y)) - parent_index = n.parent_index - prev = None - first_node = None - if len(rx) < 4 or step == 1: - sequence = zip(reversed(rx), reversed(ry)) - elif step > 1: - a1, b1 = rx[::-step], ry[::-step] - if a1[-1] != rx[0]: - a1.append(rx[0]) - b1.append(rx[0]) - sequence = zip(a1, b1) - else: # auto gen waypoint - sequence = [] - prev = None - for inx in range(len(rx) - 1, -1, -1): - if (len(sequence) == 0) or (inx == 0): - prev = (rx[inx], ry[inx]) - sequence.append(prev) - continue - _x, _y = rx[inx], ry[inx] - _x_n, _y_n = rx[inx - 1], ry[inx - 1] - if ((_x_n - _x) != (_x - prev[0])) or ( - (_y_n - _y) != (_y - prev[1]) - ): - sequence.append((_x, _y)) - prev = (_x, _y) - for seq, node in enumerate(sequence): - position = self.world.pixel2world(x=node[0], y=node[1], alt=angle) - curr = PathNode( - seq=seq, point=node, position=position, prev=prev - ) - if isinstance(prev, PathNode): - prev.next = curr - else: - first_node = curr - prev = curr - return first_node - - @staticmethod - def calc_grid_position(index, min_position=0): - """ - calc grid position - :param index: - :param min_position: - :return: - """ - pos = index + min_position - return pos - - @staticmethod - def calc_xy_index(position, min_pos=0): - return position - min_pos - - def calc_grid_index(self, node): - return node.y * self.max_x + node.x - - def verify_node(self, node): - px = self.calc_grid_position(node.x) - py = self.calc_grid_position(node.y) - - if px <= 0: - return False - elif py <= 0: - return False - elif px >= self.max_x: - return False - elif py >= self.max_y: - return False - - # collision check - if self.world.grid[node.x][node.y] == PgmItem.OBSTACLE.value: - return False - - return True - - @staticmethod - def get_motion_model(): - # dx, dy, cost - motion = [[1, 0, 1], - [0, 1, 1], - [-1, 0, 1], - [0, -1, 1], - [-1, -1, math.sqrt(2)], - [-1, 1, math.sqrt(2)], - [1, -1, math.sqrt(2)], - [1, 1, math.sqrt(2)]] - - return motion diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/__init__.py deleted file mode 100644 index 12511dcf..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .ros import RosTopicCollector diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/base.py deleted file mode 100644 index a75cf460..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/base.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import threading - -from robosdk.utils.util import Config -from robosdk.utils.logger import logging -from robosdk.cloud_robotics.message_channel import WSMessageChannel -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - - -class DataCollectorBase(metaclass=abc.ABCMeta): - def __init__(self, *args, **kwargs): - self.data_sub_lock = threading.RLock() - self.curr_frame_id = 0 - self.curr_frame = None - - @abc.abstractmethod - def start(self, *args, **kwargs): - ... - - @abc.abstractmethod - def close(self, *args, **kwargs): - ... - - @abc.abstractmethod - def parse(self, *args, **kwargs): - ... - - -class DataCollector(metaclass=abc.ABCMeta): # noqa - def __init__(self, config: Config = None): - self.config = config - self.logger = logging.bind(instance="dataCollector", system=True) - self.data_sub_lock = threading.RLock() - try: - self.message_channel = ClassFactory.get_cls( - ClassType.GENERAL, self.config.Interaction)() - except (ValueError, AttributeError) as e: - self.logger.warning(f"fail to locate message channel, {e}, " - f"use `WSMessageChannel` as default") - self.message_channel = WSMessageChannel() - - @abc.abstractmethod - def connect(self, *args, **kwargs): - ... - - @abc.abstractmethod - def close(self, *args, **kwargs): - ... - - def start(self, *args, **kwargs): - self.message_channel.setDaemon(True) - self.message_channel.start() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/ros.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/ros.py deleted file mode 100644 index a26db506..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/data_collection/ros.py +++ /dev/null @@ -1,253 +0,0 @@ -# Copyright 2021 The KubeEdge 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 base64 -import json -import numpy as np - -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.exceptions import SensorError -from .base import DataCollectorBase -from .base import DataCollector - - -__all__ = ("RosDataCollector", "RosImages", "RosTopicCollector") - - -@ClassFactory.register(ClassType.GENERAL, alias="rospy/AnyMsg") -class RosDataCollector(DataCollectorBase): # noqa - ros_time_types = ['time', 'duration'] - ros_primitive_types = ['bool', 'byte', 'char', 'int8', 'uint8', 'int16', - 'uint16', 'int32', 'uint32', 'int64', 'uint64', - 'float32', 'float64', 'string'] - ros_header_types = ['Header', 'std_msgs/Header', 'roslib/Header'] - - def __init__(self, name: str, msg_type: str, publisher: str = ""): - super(RosDataCollector, self).__init__() - - import message_filters - import roslib.message - - self.message_class = roslib.message.get_message_class(msg_type) - if not self.message_class: - raise SensorError(f"message class - {name} were unable to load.") - self.sub = message_filters.Subscriber(self.topic, self.message_class) - self.topic = name - self.publisher = publisher - - def start(self): - self.sub.registerCallback(self.parse) - - def close(self): - self.sub.sub.unregister() - - def __del__(self): - self.close() - - def parse(self, data): - if data is None: - return - self.data_sub_lock.acquire() - self.curr_frame_id += 1 - self.curr_frame = data - json_data = self.convert_ros_message_to_dictionary(message=data) - self.data_sub_lock.release() - return json_data - - @staticmethod - def _get_message_fields(message): - return zip(message.__slots__, message._slot_types) - - @staticmethod - def _convert_from_ros_binary(field_value): - field_value = base64.b64encode(field_value).decode('utf-8') - return field_value - - @staticmethod - def _convert_from_ros_time(field_value): - field_value = { - 'secs': field_value.secs, - 'nsecs': field_value.nsecs - } - return field_value - - def _convert_from_ros_array(self, field_type, field_value, - binary_array_as_bytes=True): - # use index to raise ValueError if '[' not present - list_type = field_type[:field_type.index('[')] - return [self._convert_from_ros_type( - list_type, value, binary_array_as_bytes) for value in field_value] - - @staticmethod - def _is_ros_binary_type(field_type): - """ Checks if the field is a binary array one, fixed size or not""" - return field_type.startswith('uint8[') or field_type.startswith('char[') - - @staticmethod - def _is_field_type_an_array(field_type): - return field_type.find('[') >= 0 - - def _is_field_type_a_primitive_array(self, field_type): - bracket_index = field_type.find('[') - if bracket_index < 0: - return False - else: - list_type = field_type[:bracket_index] - return list_type in self.ros_primitive_types - - def _convert_from_ros_type(self, field_type, field_value, - binary_array_as_bytes=True): - if field_type in self.ros_primitive_types: - field_value = str(field_value) - elif field_type in self.ros_time_types: - field_value = self._convert_from_ros_time(field_value) - elif self._is_ros_binary_type(field_type): - if binary_array_as_bytes: - field_value = self._convert_from_ros_binary(field_value) - elif type(field_value) == str: - field_value = [ord(v) for v in field_value] - else: - field_value = list(field_value) - elif self._is_field_type_a_primitive_array(field_type): - field_value = list(field_value) - elif self._is_field_type_an_array(field_type): - field_value = self._convert_from_ros_array( - field_type, field_value, binary_array_as_bytes) - else: - field_value = self.convert_ros_message_to_dictionary( - field_value, binary_array_as_bytes) - return field_value - - def convert_ros_message_to_dictionary(self, message, - binary_array_as_bytes=False): - """ - Takes in a ROS message and returns a Python dictionary. - """ - - dictionary = {} - message_fields = self._get_message_fields(message) - for field_name, field_type in message_fields: - field_value = getattr(message, field_name) - dictionary[field_name] = self._convert_from_ros_type( - field_type, field_value, binary_array_as_bytes) - return dictionary - - -@ClassFactory.register(ClassType.GENERAL, alias="sensor_msgs/Image") -class RosImages(RosDataCollector): - def __init__(self, name: str, publisher: str = ""): - super(RosImages, self).__init__(name=name, publisher=publisher, - msg_type="sensor_msgs/Image") - from cv_bridge import CvBridge - self.cv_bridge = CvBridge() - - def parse(self, data): - if data is None: - return - self.data_sub_lock.acquire() - self.curr_frame_id += 1 - self.curr_frame = self.cv_bridge.imgmsg_to_cv2(data, data.encoding) - json_data = dict( - header={ - 'seq': data.header.seq, - 'stamp': { - 'secs': data.header.stamp.secs, - 'nsecs': data.header.stamp.nsecs - }, - 'frame_id': data.header.frame_id - }, - data=np.array(self.curr_frame).tolist(), - height=data.height, - width=data.width, - encoding=data.encoding, - is_bigendian=data.is_bigendian, - step=data.step - ) - self.data_sub_lock.release() - return json_data - - -@ClassFactory.register(ClassType.GENERAL) -class RosTopicCollector(DataCollector): # noqa - - def __init__(self): - super(RosTopicCollector, self).__init__() - - import rostopic - - pubs, _ = rostopic.get_topic_list() - self.logger.info(f"{len(pubs)} topics has found.") - - self.all_topics = [] - - filter_topics = set() - filter_topic_types = set() - keep_topics = set() - keep_topic_types = set() - if self.config.IgnoreData: - filter_topics = self.config.IgnoreData.get( - "topic_name", "").split(",") - filter_topic_types = self.config.IgnoreData.get( - "topic_type", "").split(",") - if self.config.ForcusData: - keep_topics = self.config.ForcusData.get( - "topic_name", "").split(",") - keep_topic_types = self.config.ForcusData.get( - "topic_type", "").split(",") - for name, _type, publisher in pubs: - if name in filter_topics or _type in filter_topic_types: - self.logger.info(f"Skip sensor data of {name} - {_type} ...") - continue - if len(keep_topics) and name not in keep_topics: - self.logger.info(f"Skip sensor data of {name} - {_type} ...") - continue - if len(keep_topic_types) and _type not in keep_topic_types: - self.logger.info(f"Skip sensor data of {name} - {_type} ...") - continue - try: - sub_cls = ClassFactory.get_cls(ClassType.GENERAL, _type) - except ValueError: - sub_cls = ClassFactory.get_cls(ClassType.GENERAL, - "rospy/AnyMsg") - try: - sub = sub_cls(name=name, publisher=publisher) - except (ValueError, SensorError): - self.logger.warning(f"Sensor data of {name} " - f"were unable to record.") - continue - self.all_topics.append(sub) - - def connect(self): - import message_filters - - subs = [i.sub for i in self.all_topics] - if not len(subs): - raise SensorError("No data available.") - sync = message_filters.ApproximateTimeSynchronizer( - subs, queue_size=10, slop=0.2 - ) - sync.registerCallback(self.convert) - self.logger.info(f"DataCollector connect successfully") - - def stop(self): - self.logger.warning("trying to unsubscribe") - map(lambda sub: sub.close(), self.all_topics) - - def convert(self, *all_data): - data_collect = {} - for inx, msg_data in enumerate(all_data): - topic = self.all_topics[inx] - data = topic.parse(msg_data) - data_collect[topic.name] = data - self.message_channel.add_data(json.dumps(data_collect)) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/__init__.py deleted file mode 100644 index 9745e976..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .message_channel import WSMessageChannel diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/base.py deleted file mode 100644 index 49322134..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/base.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2021 The KubeEdge 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 ssl -import queue -import threading - -from robosdk.utils.logger import logging -from robosdk.utils.context import MessageConfig -from robosdk.utils.constant import MsgChannelItem - - -class MSGChannelBase(threading.Thread): - endpoint = MessageConfig.ENDPOINT - - def __init__(self): - threading.Thread.__init__(self) - self.logger = logging.bind(instance="message_channel", system=True) - self.mq = queue.Queue(maxsize=MessageConfig.QUEUE_MAXSIZE) - - @staticmethod - def build_ssl(): - context = ssl.SSLContext( - protocol=MessageConfig.SSL_VERSION - ) - if MessageConfig.CA_CERTS: - context.load_verify_locations(MessageConfig.CA_CERTS) - if MessageConfig.KEY_FILE and MessageConfig.CERT_FILE: - context.load_cert_chain(MessageConfig.CERT_FILE, - MessageConfig.KEY_FILE) - if MessageConfig.CERT_REQS: - context.verify_mode = MessageConfig.CERT_REQS - if MessageConfig.CHECK_HOSTNAME: - context.check_hostname = MessageConfig.CHECK_HOSTNAME - return context - - def get_data(self): - try: - data = self.mq.get(timeout=MsgChannelItem.GET_MESSAGE_TIMEOUT.value) - except queue.Empty: - data = None - return data - - def add_data(self, data: str): - try: - self.mq.put_nowait(data) - except queue.Full: - self.logger.warning('mq full, drop the message') - except Exception as e: - self.logger.error(f'mq add message fail: {e}') - - def run(self): - raise NotImplementedError diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/message_channel.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/message_channel.py deleted file mode 100644 index 7b7d95ce..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/message_channel/message_channel.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2021 The KubeEdge 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 asyncio - -import tenacity -import websockets -from websockets.exceptions import InvalidStatusCode, WebSocketException -from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK - -from robosdk.utils.constant import MsgChannelItem -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from .base import MSGChannelBase - - -__all__ = ("WSMessageChannel",) - - -@ClassFactory.register(ClassType.GENERAL) -class WSMessageChannel(MSGChannelBase): # noqa - - def __init__(self): - super(WSMessageChannel, self).__init__() - self.has_connect = False - self.ws = None - - def start(self): - loop = asyncio.get_event_loop() - loop.run_until_complete( - asyncio.wait_for( - self.connect(), - timeout=MsgChannelItem.GET_MESSAGE_TIMEOUT.value - ) - ) - self.run() - - def run(self): - while 1: - data = self.get_data() - if not data: - continue - loop = asyncio.get_event_loop() - try: - loop.run_until_complete(self._send(data)) - except Exception as err: - self.logger.error(err) - break - self.has_connect = False - self.start() - - @tenacity.retry( - stop=tenacity.stop_after_attempt(MsgChannelItem.CONNECT_INTERVAL.value), - retry=tenacity.retry_if_result(lambda x: x is None), - wait=tenacity.wait_fixed(3)) - async def _send(self, data): - try: - await asyncio.wait_for( - self.ws.send(data), - MsgChannelItem.CONNECT_INTERVAL.value - ) - return True - except Exception as err: - self.logger.error(f"{self.endpoint} send data failed - with {err}") - - @tenacity.retry( - stop=tenacity.stop_after_attempt(MsgChannelItem.CONNECT_INTERVAL.value), - retry=tenacity.retry_if_result(lambda x: x is None), - wait=tenacity.wait_fixed(3)) - async def connect(self): - self.logger.info(f'connecting to {self.endpoint}') - ssl_context = {"ssl": self.build_ssl()} if self.endpoint.startswith( - 'wss://') else {} - - try: - self.ws = await asyncio.wait_for(websockets.connect( - self.endpoint, **ssl_context - ), MsgChannelItem.CONNECT_INTERVAL.value) - except ConnectionRefusedError: - self.logger.warning(f"{self.endpoint} connection refused by server") - except ConnectionClosedError: - self.logger.warning(f"{self.endpoint} connection lost") - except ConnectionClosedOK: - self.logger.warning(f"{self.endpoint} connection closed") - except InvalidStatusCode as err: - self.logger.warning( - f"{self.endpoint} websocket failed - " - f"with invalid status code {err.status_code}") - except WebSocketException as err: - self.logger.warning(f"{self.endpoint} websocket failed: {err}") - except OSError as err: - self.logger.warning(f"{self.endpoint} connection failed: {err}") - else: - self.has_connect = True - return True diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/__init__.py deleted file mode 100644 index 237e1873..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .http import HttpTaskService -from .ros import RosActionService diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/base.py deleted file mode 100644 index aab55b5b..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/base.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import queue -import copy -import asyncio -import threading -from typing import Dict - -from robosdk.utils.logger import logging -from robosdk.utils.constant import ActionStatus -from robosdk.utils.schema import TaskNode - - -class RoboActionHandle: - - def __init__(self, seq: int = 0, task: TaskNode = None): - self.action_lock = threading.RLock() - self.state = ActionStatus.PENDING - self.task = task - self.seq = seq - - def get_state(self): - self.action_lock.acquire() - state = copy.copy(self.state) - self.action_lock.release() - return state - - def set_state(self, state): - self.action_lock.acquire() - self.state = state - self.action_lock.release() - - @property - def is_preempt(self): - return self.get_state() in ( - ActionStatus.PREEMPTING, - ActionStatus.RECALLED - ) - - @property - def is_available(self): - return self.get_state() not in ( - ActionStatus.ACTIVE, - ActionStatus.PREEMPTING, - ActionStatus.RECALLED - ) - - -class TaskAgent(metaclass=abc.ABCMeta): - - def __init__(self, name: str = "task_agent", max_task: int = 100): - self.seq = 0 - self.agent_name = name - self.logger = logging.bind(instance="taskAgent", system=True) - self.all_task = {} - self.mq = queue.Queue(maxsize=max_task) - self.executors = {} - - def initial_executors(self, executors: Dict): - self.executors = executors - - @abc.abstractmethod - def start(self): - ... - - @abc.abstractmethod - def stop(self): - ... - - def get_all_task(self): - return self.all_task - - def create_task(self): - pass - - def get_task_state(self): - pass - - def delete_task(self): - pass - - def _get(self): - try: - task_id = self.mq.get() - except queue.Empty: - return None - else: - return self.all_task.get(task_id, None) - - def _add(self, task_id: RoboActionHandle): - try: - self.mq.put_nowait(task_id) - except queue.Full: - self.logger.warning('mq full, drop the message') - except Exception as e: - self.logger.error(f'mq add message fail: {e}') - - def _run(self): - while 1: - data = self._get() - if not isinstance(data, RoboActionHandle): - continue - robot = self.executors.get(data.task.robotId, None) - if not getattr(robot, "has_connect", False): - self.logger.warning(f"Robot {robot} has not been initialized") - continue - task_type = data.task.taskType.lower() - task_instance = data.task.instance - parameter = data.task.parameter - loop = asyncio.get_event_loop() - self.logger.info( - f"Staring running task {data.seq}: {data.task.taskId}") - try: - robot.navigation.set_action_server(data) - driver = getattr(getattr(robot, task_type), task_instance) - loop.run_until_complete( - driver(**parameter) - ) - except Exception as err: - data.set_state(ActionStatus.ABORTED) - self.logger.error(err) - break - else: - data.set_state(ActionStatus.SUCCEEDED) - self.logger.info( - f"Complete task {data.seq}: {data.task.taskId}") - - def run(self): - mq = threading.Thread(target=self._run) - mq.setDaemon(True) - mq.start() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/http.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/http.py deleted file mode 100644 index a37420ef..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/http.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2021 The KubeEdge 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 threading - -from robosdk.utils.util import Config -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - -from .base import TaskAgent - - -@ClassFactory.register(ClassType.GENERAL) -class HttpTaskService(TaskAgent): # noqa - - def __init__(self, - name: str, max_task: int = 100, - host: str = "0.0.0.0", - port: int = 8080): - super(HttpTaskService, self).__init__(name=name, max_task=max_task) - - import uvicorn - from starlette.responses import JSONResponse - from fastapi import FastAPI - from fastapi.routing import APIRoute - from fastapi.middleware.cors import CORSMiddleware - - self.agent_name = self.agent_name.strip("/") - self._app = FastAPI( - title=self.agent_name.strip("/"), - root_path=f"/{self.agent_name}", - routes=[ - APIRoute( - f"/{self.agent_name}/info", - self.get_all_url, - response_class=JSONResponse, - methods=["GET"], - ), - APIRoute( - f"{self.agent_name}/list", - self.get_all_task, - response_class=JSONResponse, - methods=["GET"], - ), - APIRoute( - f"{self.agent_name}/create", - self.create_task, - response_class=JSONResponse, - methods=["PUT"], - ), - APIRoute( - f"{self.agent_name}/state", - self.get_task_state, - response_class=JSONResponse, - methods=["POST"], - ), - APIRoute( - f"{self.agent_name}/delete", - self.delete_task, - response_class=JSONResponse, - methods=["DELETE"], - ), - ] - ) - self._app.add_middleware( - CORSMiddleware, allow_origins=["*"], allow_credentials=True, - allow_methods=["*"], allow_headers=["*"] - ) - app_conf = uvicorn.Config( - app=self._app, - host=host, - port=port, - log_level="error" - ) - self.server = uvicorn.Server(config=app_conf) - self._run_thread = None - - def start(self): - self._run_thread = threading.Thread( - target=self._start_service, daemon=True) - self._run_thread.start() - - def stop(self): - self.server.should_exit = True - # self.server.shutdown() - self._run_thread.join() - - def _start_service(self): - self.logger.info(f"starting task service {self.agent_name}") - self.server.run() - self.logger.info(f"shutdown task service {self.agent_name}") - - def get_all_url(self): - return [ - {"path": route.path, "name": route.name} for route in - getattr(self._app, "routes", []) - ] diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/ros.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/ros.py deleted file mode 100644 index 45ea4c21..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/cloud_robotics/task_agent/ros.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2021 The KubeEdge 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 threading - -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.schema import TaskNode -from robosdk.utils.constant import ActionStatus - -from .base import TaskAgent -from .base import RoboActionHandle - - -__all__ = ("RosActionService", ) - - -@ClassFactory.register(ClassType.GENERAL) -class RosActionService(TaskAgent): # noqa - - def __init__(self, name: str, max_task: int = 100): - super(RosActionService, self).__init__(name=name, max_task=max_task) - - import rospy - - action_namespace = rospy.get_namespace() - self.namespace = f"{action_namespace}{self.agent_name}" - self._all_url = [] - - def stop(self): - return map(lambda x: x.shutdown(), self._all_url) - - def start(self): - import rospy - - from robosdk.msgs.cloud_msgs.srv import RobotActions # noqa - - self._all_url = [ - rospy.Service( - f"{self.namespace}/list", - RobotActions, - self.get_all_task - ), - rospy.Service( - f"{self.namespace}/create", - RobotActions, - self.create_task - ), - rospy.Service( - f"{self.namespace}/state", - RobotActions, - self.get_task_state - ), - rospy.Service( - f"{self.namespace}/delete", - RobotActions, - self.delete_task - ) - ] - - def create_task(self, request): # noqa - robo_id = request.robot_id - task_id = request.task_id - task_name = request.name - task_instance = request.instance - task_type = request.task_type - self.seq += 1 - task = TaskNode( - taskId=task_id, - robotId=robo_id, - name=task_name, - instance=task_instance, - taskType=task_type - ) - self.all_task[task_id] = { - "seq": self.seq, - "task": task, - "state": ActionStatus.PENDING.value - } - th = RoboActionHandle(seq=self.seq, task=task) - self._add(th) - return self.all_task[task_id] diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/battery/simplebattery.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/battery/simplebattery.yaml deleted file mode 100644 index 20557a2c..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/battery/simplebattery.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "battery" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_common_driver" -data: - support: true - target: "/battery_level" - actual_hz: 1 - origin_hz: 10 -requirement: # Used to generate roslaunch files. - - deep_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/camera/realsense435i.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/camera/realsense435i.yaml deleted file mode 100644 index b648d8b0..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/camera/realsense435i.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: "d435i" -manufacturer: "intel" -series: "stereo depth" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_camera_driver" -rgb: - support: true - encoding: "bgr8" - target: "/camera/color/image_raw" # Topic in ros or function in class - width: 320 - height: 240 - actual_hz: 30 - origin_hz: 30 - pan: # pan value allowed for the camera platform - min: -2.7 - max: 2.6 - tilt: - min: -1.4 - max: 1.75 -depth: - support: true - encoding: "passthrough" - map_factor: 1000 # Factor to scale depth image by to convert it into meters - target: "/camera/depth/image_rect_raw" - aligned_depth_to_color: "/camera/aligned_depth_to_color/image_raw" - width: 320 - height: 240 - actual_hz: 30 - origin_hz: 30 -info: - target: "/camera/color/camera_info" - actual_hz: 30 - origin_hz: 30 -pcd: - support: false -requirement: # Used to generate roslaunch files. - - cv_bridge - - std_msgs - - sensor_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/movebase.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/movebase.yaml deleted file mode 100644 index 1f9272bf..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/movebase.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: "movebase" -description: "" -driver: - version: "ros1" - type: "ros" - name: "MoveBase" -target: - goal: "/move_base_simple/goal" # goal to be pusblished - status: "/move_base/status" # topic used to get status of movebase - cancel: "/move_base/cancel" # topic used to cancel the goal sent to movebase - action: "/move_base" # Ros action topic for movebase - move_vel: "/cmd_vel" # topic used to set velocity - laserscan: "/scan" - mapframe: "map" # world frame name -localizer: - algorithm: "odom" - parameters: - - key: "mapframe" - value: "map" -limited: - min_distance: 0.1 - exec_time: 0 -requirement: # Used to generate roslaunch files. - - actionlib - - actionlib_msgs - - move_base_msgs - - geometry_msgs - - tf diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/taskagent.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/taskagent.yaml deleted file mode 100644 index 429b64de..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/common/taskagent.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: "task_agent" -description: "" -driver: - version: "ros1" - type: "ros" - name: "RosActionService" -service: - namespace: "/tasks" - url: - info: "/info" - list: "/list" - create: "/create" - state: "/state" - delete: "/delete" -limited: - exec_time: 0 -requirement: # Used to generate roslaunch files. - - actionlib - - actionlib_msgs - - move_base_msgs - - cloud_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/control/x20control.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/control/x20control.yaml deleted file mode 100644 index 88ed5c3b..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/control/x20control.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: "ysc_control" -description: "" -driver: - version: "0.0.1" - type: "ros" - name: "ysc_control" -parameter: - local_port: 20002 - ctrl_ip: '192.168.1.120' - ctrl_port: 43893 - gait_topic: "/gait_state" -requirement: # Used to generate roslaunch files. - - deep_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/imu/simpleimu.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/imu/simpleimu.yaml deleted file mode 100644 index f4db1d80..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/imu/simpleimu.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "imu" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_common_driver" -data: - support: true - target: "/imu" - actual_hz: 10 - origin_hz: 200 -requirement: # Used to generate roslaunch files. - - sensor_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/odom/simpleodom.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/odom/simpleodom.yaml deleted file mode 100644 index 7054ed99..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/odom/simpleodom.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: "odom" -manufacturer: "" -series: "" -description: "" -driver: - version: "ros1" - type: "ros" - name: "ros_common_driver" -data: - support: true - target: "/odom" - pose: "initialpose" - mapframe: "map" # world frame name - actual_hz: 10 - origin_hz: 200 -requirement: # Used to generate roslaunch files. - - nav_msgs diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/robots/ysc_x20.yaml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/robots/ysc_x20.yaml deleted file mode 100644 index 5221ac73..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/configs/robots/ysc_x20.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: "绝影x20" -manufacturer: "ysc" -series: "x20" -description: "quadruped robot dog" -environment: - backend: "ros" # ros / ros2 / harmony - requirement: - - rospy - - rostopic - - roslib -sensors: - camera: - - name: "camera_front_up" - config: "realsense435i" - rgb: - target: "/camera_front_up/color/image_raw" # Topic in ros or function in class - actual_hz: 10 - origin_hz: 30 - depth: - target: "/camera_front_up/depth/image_rect_raw" - aligned_depth_to_color: "/camera_front_up/aligned_depth_to_color/image_raw" - info: - target: "/camera_front_up/color/camera_info" - - name: "camera_front_down" - config: "realsense435i" - rgb: - target: "/camera_front_down/color/image_raw" - actual_hz: 10 - origin_hz: 30 - depth: - target: "/camera_front_down/depth/image_rect_raw" - aligned_depth_to_color: "/camera_front_down/aligned_depth_to_color/image_raw" - info: - target: "/camera_front_up/color/camera_info" - imu: - - name: "simple_imu" - config: "simpleimu" - data: - target: "/imu" - actual_hz: 10 - origin_hz: 199 - battery: - - name: "battery" - config: "simplebattery" - data: - target: "/battery_level" - actual_hz: 1 - origin_hz: 10 - odom: - - name: "odom" - config: "simpleodom" - data: - target: "/odom" - actual_hz: 10 - origin_hz: 200 -navigation: - name: "base_planner" - config: "movebase" - target: - goal: "/move_base_simple/goal" # get goal - status: "/move_base/status" # execution status is available - cancel: "/move_base/cancel" # cancel the goal sent to movebase - action: "/move_base" # base action command - planner: "/move_base/GlobalPlanner/make_plan" - move: "/cmd_vel" - laserscan: "/scan" - mapframe: "map" # world frame name - localizer: - algorithm: "odom" - parameter: - - key: "mapframe" - value: "map" - - key: "topic" - value: "/odom" - - key: "pose_pub" - value: "/initialpose" -control: - - legged: - name: "ysc_control" # control method supported by vendor - config: "x20control" diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/__init__.py deleted file mode 100644 index 66659cf3..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .robot import Robot -from .world import World diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/robot.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/robot.py deleted file mode 100644 index 77c64730..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/robot.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright 2021 The KubeEdge 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 asyncio -from importlib import import_module - -from robosdk.utils.logger import logging -from robosdk.utils.fileops import FileOps -from robosdk.utils.util import Config -from robosdk.utils.context import BaseConfig -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.exceptions import SensorError -from robosdk.sensors.base import SensorManage - -__all__ = ("_init_cfg", "Robot",) - - -def _init_cfg(config, kind="robots"): - if config and config.endswith((".yaml", ".yml")): - config = FileOps.download(config) - else: - config = os.path.join( - BaseConfig.configPath, kind, f"{config}.yaml" - ) - return config if os.path.isfile(config) else None - - -class Robot: - """ - This class builds robot specific objects by reading - a configuration and instantiating the necessary robot - module objects. - """ - - def __init__(self, name: str, config: str = None): - self.robot_name = name - cfg = _init_cfg(config=config, kind="robots") - self.config = Config(cfg) - self.logger = logging.bind(instance=self.robot_name) - self.control = None - self.all_sensors = {} - self.has_connect = False - - def connect(self): - if self.config.environment.backend == "ros": - import rospy - rospy.init_node(self.robot_name) - loop = asyncio.get_event_loop() - loop.run_until_complete(asyncio.gather( - self.initial_sensors(), - self.initial_navigation(), - self.initial_control(), - )) - self.has_connect = True - - def add_sensor(self, sensor: str, name: str, config: Config): - try: - _ = import_module(f"robosdk.sensors.{sensor.lower()}") - cls = getattr(ClassType, sensor.upper()) - except (ModuleNotFoundError, AttributeError): - cls = ClassType.GENERAL - if sensor not in self.all_sensors: - self.all_sensors[sensor] = SensorManage() - try: - driver_cls = ClassFactory.get_cls(cls, config['driver']['name']) - driver = driver_cls(name=name, config=config) - except: # noqa - raise SensorError(f"Initial sensor driver {name} failure, skip ...") - self.all_sensors[sensor].add(name=name, sensor=driver) - if len(self.all_sensors[sensor]) == 1: - setattr(self, sensor.lower(), driver) - - def add_sensor_cls(self, sensor: str): - try: - _ = import_module(f"robosdk.sensors.{sensor.lower()}") - cls = getattr(ClassType, sensor.upper()) - except (ModuleNotFoundError, AttributeError): - cls = ClassType.GENERAL - if sensor not in self.all_sensors: - self.all_sensors[sensor] = SensorManage() - for inx, cfg in enumerate(self.config.sensors[sensor]): - _cfg = _init_cfg(config=cfg['config'], kind=sensor) - sensor_cfg = Config(_cfg) - sensor_cfg.update_obj(cfg) - name = sensor_cfg["name"] or f"{sensor}{inx}" - try: - driver_cls = ClassFactory.get_cls( - cls, sensor_cfg['driver']['name']) - driver = driver_cls(name=name, config=sensor_cfg) - except Exception as err: # noqa - self.logger.error( - f"Initial sensor driver {name} failure : {err}, skip ...") - return - if inx == 0: - setattr(self, sensor.lower(), driver) - self.all_sensors[sensor].add(name=name, sensor=driver) - if len(self.all_sensors[sensor]) > 1: - self.logger.warning( - f"Multiple {sensor}s defined in Robot {self.robot_name}.\n" - f"In this case, {self.all_sensors[sensor].default_sensor} " - f"is set as default. Switch the sensors excepted to use by " - f"calling the `switch_sensor` method.") - self.logger.info(f"Sensor {sensor} added") - - async def initial_sensors(self): - for sensor in self.config.sensors: - self.add_sensor_cls(sensor) - - def switch_sensor(self, sensor: str, name: str): - driver = self.all_sensors[sensor][name] - if driver is None: - self.logger.error(f"Switch {sensor} fails because the " - f"device {name} cannot be located.") - return False - setattr(self, sensor.lower(), driver) - self.all_sensors[sensor].default_sensor = name - self.logger.info(f"Switch {sensor} to {name} as default.") - return True - - async def initial_control(self): - if "control" not in self.config: - return - for ctl_dict in self.config['control']: - ctl = list(ctl_dict.keys())[0] - cfg = ctl_dict[ctl] - _cfg = _init_cfg(config=cfg['config'], kind="control") - control = Config(_cfg) - try: - _ = import_module(f"robosdk.sensors.control.{ctl.lower()}") - driver_cls = ClassFactory.get_cls(ClassType.CONTROL, - control['driver']['name']) - driver = driver_cls(name=ctl, config=control) - except Exception as e: - self.logger.error(f"Initial control driver {ctl} failure, {e}") - continue - setattr(self, "control", driver) - - async def initial_navigation(self): - if "navigation" not in self.config: - return - cfg = _init_cfg(config=self.config["navigation"]['config'], - kind="common") - nav_cfg = Config(cfg) - nav_cfg.update_obj(self.config["navigation"]) - name = nav_cfg["name"] - try: - _ = import_module("robosdk.algorithms.navigation") - driver_cls = ClassFactory.get_cls(ClassType.NAVIGATION, - nav_cfg['driver']['name']) - driver = driver_cls(name=name, config=nav_cfg) - except Exception as e: - self.logger.error(f"Initial navigation driver {name} failure, {e}") - return - setattr(self, "navigation", driver) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/world.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/world.py deleted file mode 100644 index ebee3545..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/core/world.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2021 The KubeEdge 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 -from typing import Optional -from importlib import import_module - -from robosdk.utils.logger import logging -from robosdk.utils.fileops import FileOps -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.core.robot import Robot -from robosdk.algorithms.path_planning.base import GridMap - - -class World: - """ - Word instance defines the environment which the robot launch, such as map. - """ - - def __init__(self, name: str, - service: str = "RosActionService", - data_collect: str = "", - simulator: Optional = None): - self.world_name = name - self.simulator = simulator - self.logger = logging.bind(instance=self.world_name) - self.robots = [] - self.world_map = None - self.service = None - try: - _ = import_module("robosdk.cloud_robotics.task_agent") - driver_cls = ClassFactory.get_cls(ClassType.GENERAL, service) - self.service = driver_cls(name=self.world_name) - except Exception as e: - self.logger.error(f"Initial service {self.world_name} failure, {e}") - self.collector = None - if data_collect: - try: - _ = import_module("robosdk.cloud_robotics.data_collection") - driver_cls = ClassFactory.get_cls( - ClassType.GENERAL, data_collect) - self.collector = driver_cls() - except Exception as e: - self.logger.error(f"Initial data collection failure, {e}") - - def add_robot(self, robot: Robot): - if not robot.has_connect: - robot.connect() - self.robots.append(robot) - - def load_gridmap(self, map_file: str, panoptic: str = None): - """ - Initial word map by loading a 2D map with panoptic datas - :param map_file: map path, file - :param panoptic: semantic information, yaml - """ - map_file = FileOps.download(map_file, untar=True) - if os.path.isdir(map_file): - map_file = "" - for p in os.listdir(map_file): - if p.endswith(".pgm"): - map_file = os.path.join(map_file, p) - break - self.world_map = GridMap() - self.world_map.read_from_pgm(map_file) - if panoptic: - panoptic = FileOps.download(panoptic) - self.world_map.parse_panoptic(panoptic) - self.world_map.calc_obstacle_map() - - def run(self): - if self.service: - self.service.initial_executors(self.robots) - self.service.start() - self.service.run() - if self.collector: - self.collector.connect() - self.collector.start() diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/CMakeLists.txt b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/CMakeLists.txt deleted file mode 100644 index b397c17b..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/CMakeLists.txt +++ /dev/null @@ -1,209 +0,0 @@ -cmake_minimum_required(VERSION 2.8.3) -project(cloud_msgs) - -## Compile as C++11, supported in ROS Kinetic and newer -# add_compile_options(-std=c++11) - -## Find catkin macros and libraries -## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) -## is used, also find other catkin packages -find_package(catkin REQUIRED COMPONENTS - roscpp - rosmsg - rospy - actionlib - actionlib_msgs - message_generation - ) - -## System dependencies are found with CMake's conventions -# find_package(Boost REQUIRED COMPONENTS system) - - -## Uncomment this if the package has a setup.py. This macro ensures -## modules and global scripts declared therein get installed -## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html -# catkin_python_setup() - -################################################ -## Declare ROS messages, services and actions ## -################################################ - -## To declare and build messages, services or actions from within this -## package, follow these steps: -## * Let MSG_DEP_SET be the set of packages whose message types you use in -## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). -## * In the file package.xml: -## * add a build_depend tag for "message_generation" -## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET -## * If MSG_DEP_SET isn't empty the following dependency has been pulled in -## but can be declared for certainty nonetheless: -## * add a exec_depend tag for "message_runtime" -## * In this file (CMakeLists.txt): -## * add "message_generation" and every package in MSG_DEP_SET to -## find_package(catkin REQUIRED COMPONENTS ...) -## * add "message_runtime" and every package in MSG_DEP_SET to -## catkin_package(CATKIN_DEPENDS ...) -## * uncomment the add_*_files sections below as needed -## and list every .msg/.srv/.action file to be processed -## * uncomment the generate_messages entry below -## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) - -## Generate messages in the 'msg' folder -add_message_files( - FILES - RobotAction.msg -) - -## Generate services in the 'srv' folder -add_service_files( - FILES - RobotActionReq.srv -) - -## Generate actions in the 'action' folder -# add_action_files( -# FILES -# RobotAction.action -# LaserMark.action -# CarMove.action -# ) - -## Generate added messages and services with any dependencies listed here -generate_messages( - DEPENDENCIES - actionlib_msgs - std_msgs # Or other packages containing msgs -) - -################################################ -## Declare ROS dynamic reconfigure parameters ## -################################################ - -## To declare and build dynamic reconfigure parameters within this -## package, follow these steps: -## * In the file package.xml: -## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" -## * In this file (CMakeLists.txt): -## * add "dynamic_reconfigure" to -## find_package(catkin REQUIRED COMPONENTS ...) -## * uncomment the "generate_dynamic_reconfigure_options" section below -## and list every .cfg file to be processed - -## Generate dynamic reconfigure parameters in the 'cfg' folder -# generate_dynamic_reconfigure_options( -# cfg/DynReconf1.cfg -# cfg/DynReconf2.cfg -# ) - -################################### -## catkin specific configuration ## -################################### -## The catkin_package macro generates cmake config files for your package -## Declare things to be passed to dependent projects -## INCLUDE_DIRS: uncomment this if your package contains header files -## LIBRARIES: libraries you create in this project that dependent projects also need -## CATKIN_DEPENDS: catkin_packages dependent projects also need -## DEPENDS: system dependencies of this project that dependent projects also need -catkin_package( - # INCLUDE_DIRS include - # LIBRARIES itheima_msgs - CATKIN_DEPENDS roscpp rosmsg rospy message_runtime - # DEPENDS system_lib -) - -########### -## Build ## -########### - -## Specify additional locations of header files -## Your package locations should be listed before other locations -include_directories( - # include - ${catkin_INCLUDE_DIRS} -) - -## Declare a C++ library -# add_library(${PROJECT_NAME} -# src/${PROJECT_NAME}/itheima_msgs.cpp -# ) - -## Add cmake target dependencies of the library -## as an example, code may need to be generated before libraries -## either from message generation or dynamic reconfigure -# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) - -## Declare a C++ executable -## With catkin_make all packages are built within a single CMake context -## The recommended prefix ensures that target names across packages don't collide -# add_executable(${PROJECT_NAME}_node src/itheima_msgs_node.cpp) - -## Rename C++ executable without prefix -## The above recommended prefix causes long target names, the following renames the -## target back to the shorter version for ease of user use -## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" -# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") - -## Add cmake target dependencies of the executable -## same as for the library above -# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) - -## Specify libraries to link a library or executable target against -# target_link_libraries(${PROJECT_NAME}_node -# ${catkin_LIBRARIES} -# ) - -############# -## Install ## -############# - -# all install targets should use catkin DESTINATION variables -# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html - -## Mark executable scripts (Python etc.) for installation -## in contrast to setup.py, you can choose the destination -# catkin_install_python(PROGRAMS -# scripts/my_python_script -# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} -# ) - -## Mark executables for installation -## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html -# install(TARGETS ${PROJECT_NAME}_node -# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} -# ) - -## Mark libraries for installation -## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html -# install(TARGETS ${PROJECT_NAME} -# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} -# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} -# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} -# ) - -## Mark cpp header files for installation -# install(DIRECTORY include/${PROJECT_NAME}/ -# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} -# FILES_MATCHING PATTERN "*.h" -# PATTERN ".svn" EXCLUDE -# ) - -## Mark other files for installation (e.g. launch and bag files, etc.) -# install(FILES -# # myfile1 -# # myfile2 -# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} -# ) - -############# -## Testing ## -############# - -## Add gtest based cpp test target and link libraries -# catkin_add_gtest(${PROJECT_NAME}-test test/test_itheima_msgs.cpp) -# if(TARGET ${PROJECT_NAME}-test) -# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) -# endif() - -## Add folders to be run by python nosetests -# catkin_add_nosetests(test) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/msg/RobotAction.msg b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/msg/RobotAction.msg deleted file mode 100644 index a6584c50..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/msg/RobotAction.msg +++ /dev/null @@ -1,4 +0,0 @@ -Header header -string task_id -string name -uint8 task_type diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/package.xml b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/package.xml deleted file mode 100644 index 124b8282..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/package.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - cloud_msgs - 0.0.0 - The cloud_msgs package - - - - - joeyhwong - - - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - catkin - roscpp - rosmsg - rospy - roscpp - rosmsg - rospy - roscpp - rosmsg - rospy - - actionlib_msgs - actionlib_msgs - actionlib_msgs - - message_generation - message_runtime - - - - - - diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionList.srv b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionList.srv deleted file mode 100644 index 8f9044b3..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionList.srv +++ /dev/null @@ -1,2 +0,0 @@ ---- -cloud_msgs/RobotAction robot_action diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionReq.srv b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionReq.srv deleted file mode 100644 index 65c26cf7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActionReq.srv +++ /dev/null @@ -1,3 +0,0 @@ -string robot_id ---- -cloud_msgs/RobotAction robot_action diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActions.srv b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActions.srv deleted file mode 100644 index 8f9044b3..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/cloud_msgs/srv/RobotActions.srv +++ /dev/null @@ -1,2 +0,0 @@ ---- -cloud_msgs/RobotAction robot_action diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/__init__.py deleted file mode 100644 index 04e3d6e0..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2021 The KubeEdge 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. diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/base.py deleted file mode 100644 index aa6b86db..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/base.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc - -from robosdk.utils.logger import logging - - -class MessageSenderBase(metaclass=abc.ABCMeta): - def __init__(self, *args, **kwargs): - self.msg_mapper = {} - self.logger = logging.bind(instance="message_sender") - - @abc.abstractmethod - def register(self, *args, **kwargs): - ... - - @abc.abstractmethod - def unregister(self, *args, **kwargs): - ... - - @abc.abstractmethod - def send(self, *args, **kwargs): - ... diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/ros.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/ros.py deleted file mode 100644 index efbc3120..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/msgs/sender/ros.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -from typing import Any -from copy import deepcopy - -from robosdk.utils.exceptions import SensorError - -from .base import MessageSenderBase - - -class RosMessagePublish(MessageSenderBase): # noqa - def __init__(self): - super(RosMessagePublish, self).__init__() - - def register(self, - name: str, - topic="/image_result", - msg_type="sensor_msgs/Image", - queue_size=5, - converter=None, - convert_param=None): - import rospy - import roslib.message - - if name in self.msg_mapper: - self.logger.warning(f"{name} has been registered, try to replace") - message_class = roslib.message.get_message_class(msg_type) - if not message_class: - raise SensorError(f"fail to regis {name} with " - f"message type {msg_type}") - self.msg_mapper[name] = { - "sender": rospy.Publisher(topic, message_class, - queue_size=queue_size), - "count": 0, - "curr": None, - "converter": converter, - "convert_param": convert_param if isinstance( - convert_param, dict) else {} - } - - def send(self, name: str, data: Any): - if data is None: - return - if name not in self.msg_mapper: - self.logger.error(f"{name} has not been registered") - return - self.msg_mapper[name]["count"] += 1 - self.msg_mapper[name]["curr"] = deepcopy(data) - if callable(self.msg_mapper[name]["converter"]): - data = self.msg_mapper[name]["converter"]( - data, **self.msg_mapper[name]["convert_param"]) - self.msg_mapper[name]["sender"].publish(data) - self.logger.info(f"frame {self.msg_mapper[name]['count']} " - f"of {name} send complete") - - def unregister(self, name): - if name in self.msg_mapper: - del self.msg_mapper[name] diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/base.py deleted file mode 100644 index a5db9ea7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/base.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2021 The KubeEdge 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 abc -import copy -import threading - -from robosdk.utils.logger import logging -from robosdk.utils.util import Config -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - - -class SensorBase(metaclass=abc.ABCMeta): - """ - This class defines an interface for sensors, it defines - the basic functionality required by sensors being used in - an environment. - """ - - def __init__(self, name: str, config: Config): - self.sensor_name = name - self.config = config - self.interaction_mode = self.config.get("driver", {}).get("type", "UK") - self.logger = logging.bind(instance=self.sensor_name, sensor=True) - - def connect(self): - pass - - def close(self): - pass - - def reset(self): - """Reset the sensor data""" - raise NotImplementedError("Sensor object must reset") - - -@ClassFactory.register(ClassType.GENERAL, alias="ros_common_driver") -class RosCommonDriver(SensorBase): # noqa - - def __init__(self, name, config: Config = None): - super(RosCommonDriver, self).__init__(name=name, config=config) - - import rospy - import rostopic - import roslib.message - import message_filters - - self.data_lock = threading.RLock() - self.sensor_kind = name - self.data = None - try: - msg_type, _, _ = rostopic.get_topic_type(self.config.data.target) - self.message_class = roslib.message.get_message_class(msg_type) - except rostopic.ROSTopicIOException: - self.logger.error(f"message type - {name} were unable to load.") - self.message_class = rospy.msg.AnyMsg - self.sub = message_filters.Subscriber( - self.config.data.target, self.message_class) - self.sub.registerCallback(self.data_callback) - - def data_callback(self, data): - self.data = data - - def get_data(self): - return copy.deepcopy(self.data) - - def close(self): - self.sub.sub.unregister() - - -class SensorManage: - - def __init__(self): - self.default_sensor = "" - self._all_sensors = {} - - def add(self, name: str, sensor: SensorBase = None): - if not len(self._all_sensors): - self.default_sensor = name - self._all_sensors[name] = sensor - - def remove(self, name: str): - if name in self._all_sensors: - del self._all_sensors[name] - if self.default_sensor == name: - self.default_sensor = list(self._all_sensors.keys())[0] if len(self) else "" - - def __len__(self) -> int: - return len(self._all_sensors) - - def __getitem__(self, item: str) -> SensorBase: - return self._all_sensors.get(item, None) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/base.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/base.py deleted file mode 100644 index 301ff114..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/base.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2021 The KubeEdge 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 time -import threading -from importlib import import_module -from typing import Tuple, Optional, Any - -import cv2 -import numpy as np - -from robosdk.utils.util import Config -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory -from robosdk.sensors.base import SensorBase - - -__all__ = ("Camera", ) - - -class Camera(SensorBase): # noqa - """ - This is a parent class on which the robot - specific Camera classes would be built. - """ - - def __init__(self, name, config: Config = None): - super(Camera, self).__init__(name=name, config=config) - self.camera_info_lock = threading.RLock() - self.camera_img_lock = threading.RLock() - self.sensor_kind = "camera" - self.rgb_img = None - self.depth_img = None - self.camera_info = None - self.camera_P = None - - def get_rgb(self) -> Tuple[np.array, Any]: - """ - This function returns the RGB image perceived by the camera. - """ - raise NotImplementedError - - def get_depth(self) -> Tuple[np.array, Any]: - """ - This function returns the depth image perceived by the camera. - - The depth image is in meters. - - :rtype: np.ndarray or None - """ - raise NotImplementedError - - def get_rgb_depth(self) -> Tuple[np.array, Optional[np.array]]: - """ - This function returns both the RGB and depth - images perceived by the camera. - The depth image is in meters. - :rtype: np.ndarray or None - """ - raise NotImplementedError - - def get_intrinsics(self) -> Optional[np.array]: - """ - This function returns the camera intrinsics. - - :rtype: np.ndarray - """ - raise NotImplementedError - - def capture(self, save_path, algorithm="base_select", expose_time=10): - """ - This function capture the image by using the define algorithms - """ - try: - _ = import_module("robosdk.algorithms.image") - driver_cls = ClassFactory.get_cls(ClassType.IMAGE, algorithm) - driver = driver_cls(config=self.config) - imgs = [] - for _ in range(expose_time): - imgs.append(self.rgb_img) - time.sleep(0.1) - img = driver.inference(imgs) - except Exception as e: - self.logger.error( - f"Initial capture algorithm {algorithm} failure, {e}") - img = self.rgb_img - out_dir = os.path.dirname(save_path) - if not os.path.isdir(out_dir): - os.makedirs(out_dir) - _ = cv2.imwrite(save_path, img) - return save_path diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/ros.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/ros.py deleted file mode 100644 index f453bcf7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/ros.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2021 The KubeEdge 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 copy - -import cv2 -import numpy as np - -from robosdk.utils.util import Config -from robosdk.utils.logger import logging -from robosdk.utils.context import BaseConfig -from robosdk.utils.class_factory import ClassType -from robosdk.utils.class_factory import ClassFactory - -from .base import Camera - -__all__ = ("RosCameraDriver",) - - -@ClassFactory.register(ClassType.CAMERA, alias="ros_camera_driver") -class RosCameraDriver(Camera): # noqa - - def __init__(self, name, config: Config = None): - super(RosCameraDriver, self).__init__(name=name, config=config) - - import rospy - import message_filters - from cv_bridge import CvBridge - from sensor_msgs.msg import CameraInfo, Image - - self.cv_bridge = CvBridge() - self.get_time = rospy.get_rostime - rospy.Subscriber( - self.config.info.target, - CameraInfo, - self._camera_info_callback, - ) - - rgb_topic = self.config.rgb.target - self.rgb_sub = message_filters.Subscriber(rgb_topic, Image) - - depth_topic = self.config.depth.target - self.depth_sub = message_filters.Subscriber(depth_topic, Image) - - img_subs = [self.rgb_sub, self.depth_sub] - self.sync = message_filters.ApproximateTimeSynchronizer( - img_subs, queue_size=10, slop=0.2 - ) - self.sync.registerCallback(self._sync_callback) - - def _sync_callback(self, rgb, depth): - try: - if rgb is not None: - self.rgb_img = self.cv_bridge.imgmsg_to_cv2( - rgb, self.config.rgb.encoding) - if (self.config.rgb.encoding == "bgr8" and - BaseConfig.machineType.startswith("aarch")): - self.rgb_img = self.rgb_img[:, :, ::-1] - self.depth_img = self.cv_bridge.imgmsg_to_cv2( - depth, self.config.depth.encoding) - self.depth_img = np.nan_to_num(self.depth_img) - except Exception as e: - logging.error(f"get frame data from camera fail: {str(e)}") - - def _camera_info_callback(self, msg): - self.camera_info_lock.acquire() - self.camera_info = msg - self.camera_P = np.array(msg.P).reshape((3, 4)) - self.camera_info_lock.release() - - def get_rgb(self): - """ - This function returns the RGB image perceived by the camera. - """ - self.camera_img_lock.acquire() - ts = self.get_time() - rgb = copy.deepcopy(self.rgb_img) - self.camera_img_lock.release() - return rgb, ts - - def get_depth(self): - """ - This function returns the depth image perceived by the camera. - - The depth image is in meters. - - :rtype: np.ndarray or None - """ - self.camera_img_lock.acquire() - ts = self.get_time() - depth = copy.deepcopy(self.depth_img) - self.camera_img_lock.release() - if self.depth_img is None: - return None, ts - if self.config.depth.map_factor: - depth = depth / self.config.depth.map_factor - else: - depth = cv2.normalize(depth, depth, 0, 255, cv2.NORM_MINMAX) - return depth, ts - - def get_rgb_depth(self): - """ - This function returns both the RGB and depth - images perceived by the camera. - The depth image is in meters. - :rtype: np.ndarray or None - """ - self.camera_img_lock.acquire() - rgb = copy.deepcopy(self.rgb_img) - depth = copy.deepcopy(self.depth_img) - if depth is not None: - if self.config.depth.map_factor: - depth = depth / self.config.depth.map_factor - else: - depth = cv2.normalize(depth, depth, 0, 255, cv2.NORM_MINMAX) - self.camera_img_lock.release() - return rgb, depth - - def get_intrinsics(self): - """ - This function returns the camera intrinsics. - - :rtype: np.ndarray - """ - if self.camera_P is None: - return self.camera_P - self.camera_info_lock.acquire() - p = copy.deepcopy(self.camera_P) - self.camera_info_lock.release() - return p[:3, :3] diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/__init__.py deleted file mode 100644 index 938f57ca..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from .ysc_control import DeepRoboticsControl diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/ysc_control.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/ysc_control.py deleted file mode 100644 index 819560e7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/ysc_control.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -""" -Copyright (c) Deep Robotics Inc. - All Rights Reserved -Unauthorized copying of this file, via any medium is strictly prohibited -Proprietary and confidential -Author: Haoyi Han , Feb, 2020 -""" - -import time -import socket -import struct -import threading -from typing import Union - -from robosdk.utils.class_factory import ClassFactory -from robosdk.utils.class_factory import ClassType -from robosdk.utils.util import Config -from robosdk.utils.constant import GaitType - -from .base import LeggedController - -__all__ = ("DeepRoboticsControl",) - - -class RobotCommander: - """ - RobotCommander is resposible for command the robot to stop,tread or play. - """ - - _command_code = { - "STAND_UP_DOWN": 1, - "START_FORCE_MODE": 2, - "MOTION_START_STOP": 3, - "DANCE": 19, - "CHANGE_GAIT": 25, - "HEART_BEAT": 33 - } - - def __init__(self, - local_port=20001, - ctrl_ip='192.168.1.120', - ctrl_port=43893): - self.local_port = local_port - self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) - self.ctrl_addr = (ctrl_ip, ctrl_port) - self.comm_lock = threading.Lock() - - def __enter__(self): - self.server.bind(('0.0.0.0', self.local_port)) - self._keep_alive = True - - self.keep_alive_thread = threading.Thread(target=self.keep_alive, - name="keep_alive") - self.keep_alive_thread.setDaemon(True) - self.keep_alive_thread.start() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.server = None - self._keep_alive = False - self.keep_alive_thread.join() - - def keep_alive(self): - while self._keep_alive: - self.sendSimpleCommand("HEART_BEAT", verbose=False) - time.sleep(0.25) - - def sendSimple(self, command_code=25, command_value=0, command_type=0): - data = struct.pack('<3i', command_code, command_value, command_type) - self.comm_lock.acquire() - self.server.sendto(data, self.ctrl_addr) - self.comm_lock.release() - - def sendSimpleCommand(self, command_name, verbose=True): - self.sendSimple(self._command_code[command_name]) - - def stand_down_up(self): - self.sendSimpleCommand("STAND_UP_DOWN") - - def dance(self): - self.sendSimpleCommand("DANCE") - - def start_force_mode(self): - self.sendSimpleCommand("START_FORCE_MODE") - - def motion_start_stop(self): - self.sendSimpleCommand("MOTION_START_STOP") - - def yaw_adjust(self, adjust_rad): - self.sendSimple(33, int(adjust_rad * 1000)) - - def up_stair_trait(self): - self.sendSimple(7) - - def finish_up_stair_trait(self): - self.sendSimple(7) - - def down_stair_trait(self): - self.sendSimple(7) - time.sleep(0.1) - self.sendSimple(2) - - def finish_down_stair_trait(self): - self.sendSimple(2) - time.sleep(0.1) - self.sendSimple(7) - - -@ClassFactory.register(ClassType.CONTROL, alias="ysc_control") -class DeepRoboticsControl(LeggedController): # noqa - - def __init__(self, name: str = "ysc", config: Config = None): - super(DeepRoboticsControl, self).__init__(name=name, config=config) - - import rostopic - import message_filters - - self._GAIT_CODE = { - 11: GaitType.LIEON, - 3: GaitType.RUN, - 2: GaitType.FALL, - 0: GaitType.TROT, - 1: GaitType.UPSTAIR, - } - self.msg_lock = threading.RLock() - self.curr_gait = GaitType.UNKONWN - self.commander = RobotCommander( - local_port=self.config.parameter.local_port, - ctrl_port=self.config.parameter.ctrl_port, - ctrl_ip=self.config.parameter.ctrl_ip, - ) - msg_type, _, _ = rostopic.get_topic_class( - "/robot_gait_state") - self.gait_sub = message_filters.Subscriber( - "/robot_gait_state", msg_type - ) - self.gait_sub.registerCallback(self.gait_listen) - - def gait_listen(self, msg): - self.msg_lock.acquire() - if not msg: - self.curr_gait = GaitType.UNKONWN - else: - data = int(msg.data) - if data in self._GAIT_CODE: - self.curr_gait = self._GAIT_CODE[data] - else: - try: - self.curr_gait = GaitType(data) - except ValueError: - self.curr_gait = GaitType.UNKONWN - self.msg_lock.release() - - def get_curr_gait(self) -> GaitType: - return self.curr_gait - - def change_gait(self, gait: Union[str, GaitType]): - if isinstance(gait, str): - gait = getattr(GaitType, gait.upper()) - now_gait = self.get_curr_gait() - if now_gait == gait: - return - try_times = len(GaitType) - while try_times: - self.logger.info(f"change gait to {gait.name}, now {now_gait.name}") - - self.commander.sendSimple() - time.sleep(1.0) - now_gait = self.get_curr_gait() - if now_gait == gait: - break - try_times -= 1 - # time.sleep(0.2) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/__init__.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/class_factory.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/class_factory.py deleted file mode 100644 index 4ad29e86..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/class_factory.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from inspect import isfunction, isclass - - -class ClassType: - """Const class saved defined class type.""" - GENERAL = 'general' - - ROBOT = "robot" - WORLD = "world" - - NAVIGATION = "navigation" - CONTROL = "control" - PATHPLANNING = "path_planning" - LOCALIZE = "localize" - IMAGE = "image" - - CAMERA = "camera" - - -class ClassFactory(object): - """ - A Factory Class to manage all class need to register with config. - """ - - __registry__ = {} - - @classmethod - def register(cls, type_name=ClassType.GENERAL, alias=None): - """Register class into registry. - :param type_name: type_name: type name of class registry - :param alias: alias of class name - :return: wrapper - """ - - def wrapper(t_cls): - """Register class with wrapper function. - :param t_cls: class need to register - :return: wrapper of t_cls - """ - t_cls_name = alias if alias is not None else t_cls.__name__ - if type_name not in cls.__registry__: - cls.__registry__[type_name] = {t_cls_name: t_cls} - else: - if t_cls_name in cls.__registry__: - raise ValueError( - "Cannot register duplicate class ({})".format( - t_cls_name)) - cls.__registry__[type_name].update({t_cls_name: t_cls}) - return t_cls - - return wrapper - - @classmethod - def register_cls(cls, t_cls, type_name=ClassType.GENERAL, alias=None): - """Register class with type name. - :param t_cls: class need to register. - :param type_name: type name. - :param alias: class name. - :return: - """ - t_cls_name = alias if alias is not None else t_cls.__name__ - if type_name not in cls.__registry__: - cls.__registry__[type_name] = {t_cls_name: t_cls} - else: - if t_cls_name in cls.__registry__: - raise ValueError( - "Cannot register duplicate class ({})".format(t_cls_name)) - cls.__registry__[type_name].update({t_cls_name: t_cls}) - return t_cls - - @classmethod - def register_from_package(cls, package, type_name=ClassType.GENERAL): - """Register all public class from package. - :param package: package need to register. - :param type_name: type name. - :return: - """ - for _name in dir(package): - if _name.startswith("_"): - continue - _cls = getattr(package, _name) - if not isclass(_cls) and not isfunction(_cls): - continue - ClassFactory.register_cls(_cls, type_name) - - @classmethod - def is_exists(cls, type_name, cls_name=None): - """Determine whether class name is in the current type group. - :param type_name: type name of class registry - :param cls_name: class name - :return: True/False - """ - if cls_name is None: - return type_name in cls.__registry__ - return ( - type_name in cls.__registry__ - ) and ( - cls_name in cls.__registry__.get(type_name) - ) - - @classmethod - def get_cls(cls, type_name, t_cls_name=None): - """Get class and bind config to class. - :param type_name: type name of class registry - :param t_cls_name: class name - :return: t_cls - """ - if not cls.is_exists(type_name, t_cls_name): - raise ValueError( - f"can't find class type {type_name} class name" - f" {t_cls_name} in class registry") - # create instance without configs - if t_cls_name is None: - raise ValueError( - "can't find class. class type={}".format(type_name)) - t_cls = cls.__registry__.get(type_name).get(t_cls_name) - return t_cls diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/constant.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/constant.py deleted file mode 100644 index ba213b78..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/constant.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -from enum import Enum - - -class PgmItem(Enum): - UNKNOWN = -1 - FREE = 0 - OBSTACLE = 100 - - -class MsgChannelItem(Enum): - CONNECT_INTERVAL = 5 - GET_MESSAGE_TIMEOUT = 10 - - -class ActionStatus(Enum): - PENDING = 0 - ACTIVE = 1 - PREEMPTED = 2 - SUCCEEDED = 3 - ABORTED = 4 - REJECTED = 5 - PREEMPTING = 6 - RECALLING = 7 - RECALLED = 8 - LOST = 9 - UNKONWN = 99 - - -class GaitType(Enum): - RUN = 3 - TROT = 0 - FALL = 2 - UPSTAIR = 1 - LIEON = 11 - UNKONWN = 99 diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/context.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/context.py deleted file mode 100644 index 5a9767b7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/context.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -""" - Context/System configure manager, Environment variables obtain -""" - -import os -import ssl -from typing import AnyStr -from robosdk.utils.util import singleton -from robosdk.utils.util import get_machine_type - - -__all__ = ("Context", "BaseConfig", "MessageConfig") - -_sdk_path = os.path.abspath( - os.path.join( - os.path.dirname(__file__), - "..", - ) -) - - -class Context: - """The Context provides the capability of obtaining the context""" - parameters = os.environ - - @classmethod - def get(cls, param: AnyStr, default: AnyStr = None) -> AnyStr: - """get the value of the key `param` in `PARAMETERS`, - if not exist, the default value is returned""" - value = cls.parameters.get( - param) or cls.parameters.get(str(param).upper()) - return value or default - - -@singleton -class BaseConfig: - """ Base configure manager""" - ROS_MASTER_URI = Context.get('ROS_MASTER_URI', "http://localhost:11311") - ROBOT_ID = Context.get('ROBOT_ID', "") - taskId = Context.get('TASK_ID', "") - - logDir = Context.get("LOG_DIR", "/tmp") - logUri = Context.get("LOG_URI", "") - logLevel = Context.get("LOG_LEVEL", "INFO") - - configPath = Context.get("CFG_PATH", os.path.join(_sdk_path, "configs")) - - machineType = get_machine_type() - - -@singleton -class MessageConfig: - CA_CERTS = Context.get('CA_CERTS', "") - CERT_FILE = Context.get('CERT_FILE', "") - KEY_FILE = Context.get('KEY_FILE', "") - CHECK_HOSTNAME = Context.get('CA_CERTS', "False").upper() == "TRUE" - SSL_VERSION = int( - getattr(ssl, - Context.get('SSL_VERSION', "PROTOCOL_TLSv1_2"), - ssl.PROTOCOL_TLSv1_2)) - CERT_REQS = int( - getattr(ssl, - Context.get('CERT_REQS', "CERT_NONE"), - ssl.CERT_NONE)) - - ENDPOINT = Context.get('ENDPOINT', "wss://localhost:8443/ws") - QUEUE_MAXSIZE = int(Context.get('QUEUE_MAXSIZE', "1000")) diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/exceptions.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/exceptions.py deleted file mode 100644 index c7edb5e2..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/exceptions.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - - -class RoboError(Exception): - """Base class for APP exceptions""" - pass - - -class SensorError(Exception): - """Base class for sensor exceptions""" - pass diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/fileops.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/fileops.py deleted file mode 100644 index 9b7deeb8..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/fileops.py +++ /dev/null @@ -1,310 +0,0 @@ -# Copyright 2021 The KubeEdge 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 re -import glob -import gzip -import json -import shutil -import tempfile -import mimetypes -import concurrent.futures -from urllib.parse import urlparse - -import requests - -from robosdk.utils.context import Context -from robosdk.utils.util import singleton - - -@singleton -def _create_minio_client(): - import minio - - _url = Context.get("S3_ENDPOINT_URL", "http://s3.amazonaws.com") - if not (_url.startswith("http://") or _url.startswith("https://")): - _url = f"https://{_url}" - url = urlparse(_url) - use_ssl = url.scheme == 'https' if url.scheme else True - - s3 = minio.Minio( - url.netloc, - access_key=Context.get("ACCESS_KEY_ID", ""), - secret_key=Context.get("SECRET_ACCESS_KEY", ""), - secure=use_ssl - ) - return s3 - - -class FileOps: - """ - This is a class with some class methods to handle some files or folder. - """ - - _S3_PREFIX = "s3://" - _OBS_PREFIX = "obs://" - _LOCAL_PREFIX = "file://" - _URI_RE = "https?://(.+)/(.+)" - _HTTP_PREFIX = "http(s)://" - _HEADERS_SUFFIX = "-headers" - SUPPORT_PROTOCOLS = (_OBS_PREFIX, _S3_PREFIX, _LOCAL_PREFIX, _HTTP_PREFIX) - - @classmethod - def _normalize_uri(cls, uri: str) -> str: - for src, dst in [ - ("/", cls._LOCAL_PREFIX), - (cls._OBS_PREFIX, cls._S3_PREFIX) - ]: - if uri.startswith(src): - return uri.replace(src, dst, 1) - return uri - - @classmethod - def download(cls, uri: str, out_dir: str = None, - untar: bool = False) -> str: - """ - Download the uri to local directory. - Support protocols: http(s), s3. - """ - - uri = cls._normalize_uri(uri) - if out_dir is None: - out_dir = tempfile.mkdtemp() - elif not os.path.isdir(out_dir): - os.makedirs(out_dir) - - if uri.startswith(cls._S3_PREFIX): - dst = cls.download_s3(uri, out_dir) - elif uri.startswith(cls._LOCAL_PREFIX): - dst = cls.download_local(uri, out_dir) - elif re.search(cls._URI_RE, uri): - dst = cls.download_from_uri(uri, out_dir) - else: - raise Exception("Cannot recognize storage type for %s.\n" - "%r are the current available storage type." % - (uri, cls.SUPPORT_PROTOCOLS)) - if os.path.isdir(dst): - _dst = os.path.join(dst, os.path.basename(uri)) - if os.path.exists(_dst): - dst = _dst - if untar: - if os.path.isfile(dst): - return cls._untar(dst) - if os.path.isdir(dst): - _ = map(cls._untar, glob.glob(os.path.join(dst, "*"))) - return dst - - @classmethod - def upload(cls, src: str, dst: str, tar=False, clean=True) -> str: - basename = os.path.basename(src) - dst = dst.rstrip(basename) - if tar: - src = cls._tar(src, f"{src.rstrip(os.path.sep)}.tar.gz") - - if dst.startswith(cls._S3_PREFIX): - cls.upload_s3(src, dst) - else: - if not os.path.isdir(dst): - os.makedirs(dst) - cls.download_local(src, dst) - if clean and os.path.exists(src): - cls.delete(src) - return dst - - @classmethod - def upload_s3(cls, src, dst): - - s3 = _create_minio_client() - parsed = urlparse(dst, scheme='s3') - bucket_name = parsed.netloc - - def _s3_upload(_file, fname=""): - _file_handle = open(_file, 'rb') - _file_handle.seek(0, os.SEEK_END) - size = _file_handle.tell() - _file_handle.seek(0) - if not fname: - fname = os.path.basename(fname) - s3.put_object(bucket_name, fname, _file_handle, size) - _file_handle.close() - return size - - if os.path.isdir(src): - for root, _, files in os.walk(src): - for file in files: - filepath = os.path.join(root, file) - name = os.path.relpath(filepath, src) - _s3_upload(filepath, name) - elif os.path.isfile(src): - _s3_upload(src, parsed.path.lstrip("/")) - - @classmethod - def download_s3(cls, uri: str, out_dir: str = None) -> str: - client = _create_minio_client() - count = cls._download_s3(client, uri, out_dir) - if count == 0: - raise RuntimeError( - f"Failed to fetch files. The path {uri} does not exist.") - return out_dir - - @classmethod - def download_local(cls, uri: str, out_dir: str) -> str: - local_path = uri.replace(cls._LOCAL_PREFIX, "/", 1) - if not os.path.exists(local_path): - raise RuntimeError(f"Local path {uri} does not exist.") - - if os.path.isdir(local_path): - local_path = os.path.join(local_path, "*") - - for src in glob.glob(local_path): - _, tail = os.path.split(src) - dest_path = os.path.join(out_dir, tail) - if src == dest_path: - continue - shutil.copy(src, dest_path) - return out_dir - - @classmethod - def download_from_uri(cls, uri, out_dir=None) -> str: - url = urlparse(uri) - filename = os.path.basename(url.path) - mimetype, encoding = mimetypes.guess_type(url.path) - local_path = os.path.join(out_dir, filename) - - if not filename: - raise ValueError(f'No filename contained in URI: {uri}') - - host_uri = url.hostname - - headers_json = os.getenv(host_uri + cls._HEADERS_SUFFIX, "{}") - headers = json.loads(headers_json) - - with requests.get(uri, stream=True, headers=headers) as response: - if response.status_code != 200: - raise RuntimeError("URI: %s returned a %s response code." % - (uri, response.status_code)) - - if encoding == 'gzip': - stream = gzip.GzipFile(fileobj=response.raw) - local_path = os.path.join(out_dir, f'{filename}.tar') - else: - stream = response.raw - with open(local_path, 'wb') as out: - shutil.copyfileobj(stream, out) - - return local_path - - @classmethod - def download_s3_with_multi_files(cls, download_files, - base_uri, base_out_dir): - client = _create_minio_client() - total_count = 0 - with concurrent.futures.ThreadPoolExecutor() as executor: - todos = [] - for dfile in set(download_files): - dir_ = os.path.dirname(dfile) - uri = base_uri.rstrip("/") + "/" + dfile - out_dir = os.path.join(base_out_dir, dir_) - todos.append( - executor.submit(cls._download_s3, client, uri, out_dir)) - - for done in concurrent.futures.as_completed(todos): - count = done.result() - if count == 0: - continue - total_count += count - - @classmethod - def _download_s3(cls, client, uri, out_dir): - """ - The function downloads specified file or folder to local directory. - this function supports: - 1. when downloading the specified file, keep the name of the file. - 2. when downloading the specified folder, keep the name of the folder. - - Parameters: - client: s3 client - uri(string): url in s3, e.g. file url: s3://dev/data/data.txt - out_dir(string): local directory address, e.g. /tmp/data/ - - Returns: - int: files of number in s3_url - """ - bucket_args = uri.replace(cls._S3_PREFIX, "", 1).split("/", 1) - bucket_name = bucket_args[0] - bucket_path = len(bucket_args) > 1 and bucket_args[1] or "" - - objects = client.list_objects(bucket_name, - prefix=bucket_path, - recursive=True, - use_api_v1=True) - count = 0 - - root_path = os.path.split(os.path.normpath(bucket_path))[0] - for obj in objects: - # Replace any prefix from the object key with out_dir - subdir_object_key = obj.object_name[len(root_path):].strip("/") - # fget_object handles directory creation if does not exist - if not obj.is_dir: - local_file = os.path.join( - out_dir, - subdir_object_key or os.path.basename(obj.object_name) - ) - client.fget_object(bucket_name, obj.object_name, local_file) - count += 1 - return count - - @classmethod - def _untar(cls, src, dst=None): - import tarfile - import zipfile - if not (os.path.isfile(src) and str(src).endswith((".gz", ".zip"))): - return src - if dst is None: - dst = os.path.dirname(src) - _bname, _bext = os.path.splitext(os.path.basename(src)) - if _bext == ".zip": - with zipfile.ZipFile(src, 'r') as zip_ref: - zip_ref.extractall(dst) - else: - with tarfile.open(src, 'r:gz') as tar_ref: - tar_ref.extractall(path=dst) - if os.path.isfile(src): - cls.delete(src) - checkname = os.path.join(dst, _bname) - return checkname if os.path.exists(checkname) else dst - - @classmethod - def _tar(cls, src, dst) -> str: - import tarfile - with tarfile.open(dst, 'w:gz') as tar: - if os.path.isdir(src): - for root, _, files in os.walk(src): - for file in files: - filepath = os.path.join(root, file) - tar.add(filepath) - elif os.path.isfile(src): - tar.add(os.path.realpath(src)) - return dst - - @classmethod - def delete(cls, path): - try: - if os.path.isdir(path): - shutil.rmtree(path) - if os.path.isfile(path): - os.remove(path) - except Exception: - pass diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/logger.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/logger.py deleted file mode 100644 index 6a1ab789..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/logger.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -""" -logger provides a pre-instanced logger to the run logs -""" - -import os -import sys -import atexit -import loguru - -from robosdk.utils.fileops import FileOps -from robosdk.utils.context import BaseConfig - - -__all__ = ("logging", ) - - -class _Logger: - - logger: loguru.logger = loguru.logger - - def __init__(self, base: str = BaseConfig.taskId, - level: str = BaseConfig.logLevel): - self.logger.remove() - info_format = ( - '{time:YYYY-MM-DD HH:mm:ss.S} | {extra[taskBase]} ' - ': {extra[instance]} | {level: <8} | ' - '{name} - {message}' - ) - debug_format = ( - '{time:YYYY-MM-DD HH:mm:ss.SSSS} | {extra[taskBase]}' - ':{extra[instance]} | {level: <9} | ' - '{name}:{function} - {message}' - ' ' - ) - log_format = debug_format if level == 'DEBUG' else info_format - self.log_file = os.path.join( - BaseConfig.logDir, f"{base}_launch.log" - ) - self.sys_log_file = os.path.join( - BaseConfig.logDir, f"{base}_system.log" - ) - self.sensor_log_file = os.path.join( - BaseConfig.logDir, f"{base}_sensor.log" - ) - self.logger.add( - self.log_file, - format=log_format, - level=level, - enqueue=True, - rotation="00:00", - compression='tar.gz', - encoding="utf-8", - backtrace=True, - diagnose=True, - colorize=False - ) - self.logger.add( - self.sys_log_file, - format=debug_format, - level="DEBUG", - enqueue=True, - rotation="00:00", - compression='tar.gz', - encoding="utf-8", - backtrace=True, - diagnose=True, - colorize=False, - filter=lambda record: "system" in record["extra"] - ) - self.logger.add( - self.sensor_log_file, - format=debug_format, - level="DEBUG", - enqueue=True, - rotation="00:00", - compression='tar.gz', - encoding="utf-8", - backtrace=True, - diagnose=True, - colorize=False, - filter=lambda record: "sensor" in record["extra"] - ) - self.logger.add(sys.stderr, level=level, format=log_format, - backtrace=True, diagnose=True, colorize=True, ) - self.logger.configure(extra={"taskBase": base}) - atexit.register(self.close) - - def close(self): - """ - Synchronizing Logs to Remote OBS - """ - if BaseConfig.logUri: - for f in (self.sys_log_file, self.sensor_log_file, self.log_file): - log_save = FileOps.upload(f, BaseConfig.logUri, clean=True) - self.logger.debug(f"log files has upload to {log_save}") - - -logging = _Logger().logger diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/schema.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/schema.py deleted file mode 100644 index cbf5dfc0..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/schema.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2021 The KubeEdge 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 typing -import math -from pathlib import Path -from decimal import Decimal - -from pydantic import BaseModel - - -class BasePose(BaseModel): - x: float = 0.0 - y: float = 0.0 - z: float = 0.0 - w: float = 0.0 - - def __str__(self): - if self.w and self.w > 0.0: - return f"x: {self.x} y: {self.y} z: {self.z} w: {self.w}" - return f"x: {self.x} y: {self.y} z: {self.z}" - - def __sub__(self, other): - return math.sqrt( - math.pow(self.x - other.x, 2) + math.pow(self.y - other.y, 2) - ) - - -class PgmMap(BaseModel): - image: Path - resolution: typing.Union[float, Decimal] - origin: typing.List - reverse: typing.Union[int, bool] - occupied_thresh: Decimal - free_thresh: Decimal - - -class PathNode(BaseModel): - seq: int = 0 - point: typing.Union[typing.Tuple[float], typing.List[float]] - position: BasePose = BasePose() - prev: typing.Any = None - next: typing.Any = None - - def __next__(self): - return self.next - - def __iter__(self): - return self - - -class TaskNode(BaseModel): - taskId: str - robotId: str - name: str = "" - instance: str = None - taskType: str = "normal" - parameter: typing.Dict = {} diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/util.py b/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/util.py deleted file mode 100644 index 0fd17ea4..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/utils/util.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright 2021 The KubeEdge 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. -"""This script contains some common tools.""" -import os -import sys -import json -import platform -from typing import Dict -from copy import deepcopy -from importlib import import_module -from functools import wraps - -import cv2 -import yaml -import math -import numpy as np - - -def singleton(cls): - """Set class to singleton class. - - :param cls: class - :return: instance - """ - __instances__ = {} - - @wraps(cls) - def get_instance(*args, **kw): - """Get class instance and save it into glob list.""" - if cls not in __instances__: - __instances__[cls] = cls(*args, **kw) - return __instances__[cls] - - return get_instance - - -def get_machine_type() -> str: - return str(platform.machine()).lower() - - -def _url2dict(arg): - if arg.endswith('.yaml') or arg.endswith('.yml'): - with open(arg) as f: - raw_dict = yaml.load(f, Loader=yaml.FullLoader) - elif arg.endswith('.py'): - module_name = os.path.basename(arg)[:-3] - config_dir = os.path.dirname(arg) - sys.path.insert(0, config_dir) - mod = import_module(module_name) - sys.path.pop(0) - raw_dict = { - name: value - for name, value in mod.__dict__.items() - if not name.startswith('__') - } - sys.modules.pop(module_name) - elif arg.endswith(".json"): - with open(arg) as f: - raw_dict = json.load(f) - else: - try: - raw_dict = json.loads(arg, encoding="utf-8") - except json.JSONDecodeError: - raise Exception('config file must be yaml or py') - return raw_dict - - -def _dict2config(config, dic): - """Convert dictionary to config. - - :param Config config: config - :param dict dic: dictionary - - """ - if isinstance(dic, dict): - for key, value in dic.items(): - if isinstance(value, dict): - config[key] = Config() - _dict2config(config[key], value) - else: - config[key] = value - - -class Config(dict): - """A Config class is inherit from dict. - - Config class can parse arguments from a config file - of yaml, json or pyscript. - :param args: tuple of Config initial arguments - :type args: tuple of str or dict - :param kwargs: dict of Config initial argumnets - :type kwargs: dict - """ - - def __init__(self, *args, **kwargs): - """Init config class with multiple config files or dictionary.""" - super(Config, self).__init__() - for arg in args: - if isinstance(arg, str): - _dict2config(self, _url2dict(arg)) - elif isinstance(arg, dict): - _dict2config(self, arg) - else: - raise TypeError('args is not dict or str') - if kwargs: - _dict2config(self, kwargs) - - def update_obj(self, update: Dict): - - for k, v in update.items(): - orig = getattr(self, k, Config({})) - if isinstance(orig, dict): - orig = Config(orig) - target = deepcopy(v) - if isinstance(target, (Config, dict)): - orig.update_obj(target) - setattr(self, k, orig) - else: - setattr(self, k, target) - - def to_json(self, f_out): - with open(f_out, "w", encoding="utf-8") as fh: - json.dump(dict(self), fh, indent=4) - - def to_yaml(self, f_out): - with open(f_out, "w", encoding="utf-8") as fh: - yaml.dump(dict(self), fh, default_flow_style=False) - - def __call__(self, *args, **kwargs): - """Call config class to return a new Config object. - - :return: a new Config object. - :rtype: Config - - """ - return Config(self, *args, **kwargs) - - def __setstate__(self, state): - """Set state is to restore state from the unpickled state values. - - :param dict state: the `state` type should be the output of - `__getstate__`. - - """ - _dict2config(self, state) - - def __getstate__(self): - """Return state values to be pickled. - - :return: change the Config to a dict. - :rtype: dict - - """ - d = dict() - for key, value in self.items(): - if isinstance(value, Config): - value = value.__getstate__() - d[key] = value - return d - - def __getattr__(self, key): - """Get a object attr by its `key`. - - :param str key: the name of object attr. - :return: attr of object that name is `key`. - :rtype: attr of object. - - """ - if key in self: - return self[key] - else: - raise AttributeError(key) - - def __setattr__(self, key, value): - """Get a object attr `key` with `value`. - - :param str key: the name of object attr. - :param value: the `value` need to set to target object attr. - :type value: attr of object. - - """ - self[key] = value - - def __delattr__(self, key): - """Delete a object attr by its `key`. - - :param str key: the name of object attr. - - """ - del self[key] - - def __deepcopy__(self, memo): - """After `deepcopy`, return a Config object. - - :param dict memo: same to deepcopy `memo` dict. - :return: a deep copyed self Config object. - :rtype: Config object - - """ - return Config(deepcopy(dict(self))) - - -class ImageQualityEval: - - @classmethod - def brenner(cls, img): - shape = np.shape(img) - out = 0 - for x in range(0, shape[0] - 2): - for y in range(0, shape[1]): - out += (int(img[x + 2, y]) - int(img[x, y])) ** 2 - return out - - @classmethod - def laplacian(cls, img): - return cv2.Laplacian(img, cv2.CV_64F).var() - - @classmethod - def smd(cls, img): - shape = np.shape(img) - out = 0 - for x in range(1, shape[0] - 1): - for y in range(0, shape[1]): - out += math.fabs(int(img[x, y]) - int(img[x, y - 1])) - out += math.fabs(int(img[x, y] - int(img[x + 1, y]))) - return out - - @classmethod - def smd2(cls, img): - shape = np.shape(img) - out = 0 - for x in range(0, shape[0] - 1): - for y in range(0, shape[1] - 1): - out += math.fabs( - int(img[x, y]) - int(img[x + 1, y])) * math.fabs( - int(img[x, y] - int(img[x, y + 1]))) - return out - - @classmethod - def variance(cls, img): - out = 0 - u = np.mean(img) - shape = np.shape(img) - for x in range(0, shape[0]): - for y in range(0, shape[1]): - out += (img[x, y] - u) ** 2 - return out - - @classmethod - def energy(cls, img): - shape = np.shape(img) - out = 0 - for x in range(0, shape[0] - 1): - for y in range(0, shape[1] - 1): - out += ((int(img[x + 1, y]) - int(img[x, y])) ** 2) * ( - (int(img[x, y + 1] - int(img[x, y]))) ** 2) - return out - - @classmethod - def vollath(cls, img): - shape = np.shape(img) - u = np.mean(img) - out = -shape[0] * shape[1] * (u ** 2) - for x in range(0, shape[0] - 1): - for y in range(0, shape[1]): - out += int(img[x, y]) * int(img[x + 1, y]) - return out - - @classmethod - def entropy(cls, img): - out = 0 - count = np.shape(img)[0] * np.shape(img)[1] - p = np.bincount(np.array(img).flatten()) - for i in range(0, len(p)): - if p[i] != 0: - out -= p[i] * math.log(p[i] / count) / count - return out diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/x86.Dockerfile b/examples/lifelong_learning/robot_dog_delivery/robo_detection/x86.Dockerfile deleted file mode 100644 index 497459b7..00000000 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/x86.Dockerfile +++ /dev/null @@ -1,57 +0,0 @@ -FROM ros:noetic-ros-base - -RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list - -RUN apt-get clean && apt-get update\ - && apt-get install -q -y cmake git \ - python3-pip wget curl zip \ - ros-noetic-cv-bridge ros-noetic-tf \ - ros-noetic-move-base-msgs\ - libgl1-mesa-glx vim python3-opencv - -RUN pip3 install --upgrade pip - -WORKDIR /home -COPY ./requirements-sdk.txt /home/requirements-sdk.txt -COPY ./requirements.txt /home/requirements.txt - -ENV PYTHONHTTPSVERIFY "0" -ENV PROMPT_DIRTRIM "1" -ENV PYTHONPATH "/home/lib" -ENV HOLD_TIME 1 -ENV PIP "https://pypi.tuna.tsinghua.edu.cn/simple" -RUN pip3 install -i $PIP --no-cache-dir -r /home/requirements.txt -RUN pip3 install -i $PIP --no-cache-dir -r /home/requirements-sdk.txt - -COPY ./run.sh /usr/local/bin/run.sh -RUN chmod 755 /usr/local/bin/run.sh - -WORKDIR /home/lib -COPY ./robosdk /home/lib/robosdk -COPY ./ramp_detection /home/lib/ramp_detection -COPY ./configs /home/lib/configs - -WORKDIR /home/deep_msgs -COPY ./deep_msgs /home/deep_msgs/src -RUN /bin/bash -c "source /opt/ros/noetic/setup.bash && catkin_make && catkin_make install" -COPY ./package.xml /home/deep_msgs/src - -RUN echo ' \n\ -echo "Sourcing ROS1 packages..." \n\ -source /opt/ros/noetic/setup.bash \n\ -source /home/deep_msgs/devel/setup.bash ' >> ~/.bashrc - -# cleanup -RUN apt-get clean -RUN rm -rf /var/lib/apt/lists/* -ENV http_proxy "" -ENV https_proxy "" -ENV no_proxy "" - -RUN source /opt/ros/$ROS_DISTRO/setup.bash -RUN source /home/deep_msgs/devel/setup.bash - -WORKDIR /home/lib/ramp_detection - -# ENTRYPOINT ["bash"] -ENTRYPOINT ["python3"] diff --git a/examples/lifelong_learning/robot_dog_delivery/yaml/dataset.yaml b/examples/lifelong_learning/robot_dog_delivery/yaml/dataset.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/lifelong_learning/robot_dog_delivery/yaml/robot-dog-delivery.yaml b/examples/lifelong_learning/robot_dog_delivery/yaml/robot-dog-delivery.yaml deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/requirements.txt b/lib/requirements.txt index aaefd9f0..c71c6caa 100644 --- a/lib/requirements.txt +++ b/lib/requirements.txt @@ -7,8 +7,8 @@ setuptools~=54.2.0 fastapi~=0.68.1 # MIT pydantic>=1.8.1 # MIT tenacity~=8.0.1 # Apache-2.0 -joblib~=1.0.1 # BSD -pandas~=1.1.5 # BSD +joblib~=1.2.0 # BSD +pandas # BSD six~=1.15.0 # MIT minio~=7.0.3 # Apache-2.0 uvicorn~=0.14.0 # BSD diff --git a/lib/sedna/algorithms/__init__.py b/lib/sedna/algorithms/__init__.py index 12f6e7b1..99c7aa8f 100644 --- a/lib/sedna/algorithms/__init__.py +++ b/lib/sedna/algorithms/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/seen_task_learning/__init__.py b/lib/sedna/algorithms/seen_task_learning/__init__.py index 2ffe68f2..d63a73c1 100644 --- a/lib/sedna/algorithms/seen_task_learning/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/seen_task_learning/artifact.py b/lib/sedna/algorithms/seen_task_learning/artifact.py index fd7c1e9c..0ca92686 100644 --- a/lib/sedna/algorithms/seen_task_learning/artifact.py +++ b/lib/sedna/algorithms/seen_task_learning/artifact.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/seen_task_learning/inference_integration/__init__.py b/lib/sedna/algorithms/seen_task_learning/inference_integration/__init__.py index e94b6da0..7a0021e9 100644 --- a/lib/sedna/algorithms/seen_task_learning/inference_integration/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/inference_integration/__init__.py @@ -1,3 +1,15 @@ +# Copyright 2023 The KubeEdge 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. from . import inference_integrate -from . import inference_integrate_by_type diff --git a/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate_by_type.py b/lib/sedna/algorithms/seen_task_learning/inference_integration/base_inference_integrate.py similarity index 57% rename from lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate_by_type.py rename to lib/sedna/algorithms/seen_task_learning/inference_integration/base_inference_integrate.py index 666ce3a1..539fb06a 100644 --- a/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate_by_type.py +++ b/lib/sedna/algorithms/seen_task_learning/inference_integration/base_inference_integrate.py @@ -1,62 +1,48 @@ -# Copyright 2021 The KubeEdge 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. - -""" -Integrate the inference results of all related tasks -""" - -from typing import List - -import numpy as np - -from sedna.common.class_factory import ClassFactory, ClassType - -from ..artifact import Task - -__all__ = ('InferenceIntegrateByType', ) - - -@ClassFactory.register(ClassType.STP) -class InferenceIntegrateByType: - """ - Default calculation algorithm for inference integration - - Parameters - ---------- - models: All models used for sample inference - """ - - def __init__(self, models: list, **kwargs): - self.models = models - - def __call__(self, tasks: List[Task]): - """ - Parameters - ---------- - tasks: All tasks with sample result - - Returns - ------- - result: minimum result - """ - - curb_results, ramp_results = [], [] - for task in tasks: - curb_result, ramp_result = task.result - curb_results = curb_result if not curb_results else np.concatenate( - (curb_results, curb_result)) - ramp_results = ramp_result if not ramp_results else np.concatenate( - (ramp_results, ramp_result)) - - return curb_results, ramp_results +# Copyright 2023 The KubeEdge 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. + +""" +Integrate the inference results of all related tasks +""" + +from typing import List + +import numpy as np + +from ..artifact import Task + + +class BaseInferenceIntegrate: + """ + Base class for default calculation algorithm for inference integration + + Parameters + ---------- + models: All models used for sample inference + """ + + def __init__(self, models: list, **kwargs): + self.models = models + + def __call__(self, tasks: List[Task]): + """ + Parameters + ---------- + tasks: All tasks with sample result + + Returns + ------- + result: inference results for all the inference samples + """ + raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate.py b/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate.py index 949f8c8b..bf0d6091 100644 --- a/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate.py +++ b/lib/sedna/algorithms/seen_task_learning/inference_integration/inference_integrate.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,13 +22,14 @@ import numpy as np from sedna.common.class_factory import ClassFactory, ClassType +from .base_inference_integrate import BaseInferenceIntegrate from ..artifact import Task __all__ = ('DefaultInferenceIntegrate', ) @ClassFactory.register(ClassType.STP) -class DefaultInferenceIntegrate: +class DefaultInferenceIntegrate(BaseInferenceIntegrate): """ Default calculation algorithm for inference integration @@ -38,7 +39,7 @@ class DefaultInferenceIntegrate: """ def __init__(self, models: list, **kwargs): - self.models = models + super(DefaultInferenceIntegrate, self).__init__(models) def __call__(self, tasks: List[Task]): """ diff --git a/lib/sedna/algorithms/seen_task_learning/seen_task_learning.py b/lib/sedna/algorithms/seen_task_learning/seen_task_learning.py index f85d261a..88de8ea2 100644 --- a/lib/sedna/algorithms/seen_task_learning/seen_task_learning.py +++ b/lib/sedna/algorithms/seen_task_learning/seen_task_learning.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,10 +15,6 @@ """Multiple task transfer learning algorithms""" import json -import time - -import pandas as pd -from sklearn import metrics as sk_metrics from sedna.datasources import BaseDataSource from sedna.backend import set_backend @@ -394,7 +390,7 @@ class SeenTaskLearning: self.seen_task_groups.append(task) task_index = { - self.extractor_key: {"front": 0, "garden": 1}, + self.extractor_key: self.seen_extractor, self.task_group_key: self.seen_task_groups } @@ -460,11 +456,6 @@ class SeenTaskLearning: if post_process: callback = ClassFactory.get_cls(ClassType.CALLBACK, post_process)() - res = kwargs.get("prediction") - tasks = kwargs.get("tasks") - if res and tasks: - return res, tasks - tasks = [] for inx, df in enumerate(samples): m = models[inx] @@ -512,6 +503,10 @@ class SeenTaskLearning: tasks_detail : List[Object] all metric results in each task. """ + + import pandas as pd + from sklearn import metrics as sk_metrics + result, tasks = self.predict(data, **kwargs) m_dict = {} diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/__init__.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/__init__.py index a4d4ad62..8ef906d5 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_allocation/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/task_allocation/__init__.py @@ -1,5 +1,17 @@ +# Copyright 2023 The KubeEdge 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. from . import task_allocation from . import task_allocation_by_origin -from . import task_allocation_simple -from . import task_allocation_default +from . import task_allocation_stream diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/base_task_allocation.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/base_task_allocation.py new file mode 100644 index 00000000..43f01110 --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_allocation/base_task_allocation.py @@ -0,0 +1,44 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Mining tasks of inference sample based on task attribute extractor + +Parameters +---------- +samples : infer sample, see `sedna.datasources.BaseDataSource` for more detail. + +Returns +------- +allocations : tasks that assigned to each sample +""" + +from sedna.datasources import BaseDataSource + + +class BaseTaskAllocation: + """ + Base class of task allocation algorithm + + Parameters + ---------- + task_extractor : Model or dict + task extractor is used to predict target tasks + """ + + def __init__(self, task_extractor, **kwargs): + self.task_extractor = task_extractor + + def __call__(self, samples: BaseDataSource): + raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation.py index 08dec8ff..5f1a9e8c 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation.py +++ b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ # limitations under the License. """ -Mining tasks of inference sample base on task attribute extractor +Mining tasks of inference sample based on task attribute extractor Parameters ---------- diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_by_origin.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_by_origin.py index f92761df..558cc50b 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_by_origin.py +++ b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_by_origin.py @@ -1,23 +1,39 @@ +# Copyright 2023 The KubeEdge 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. + from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassFactory, ClassType +from .base_task_allocation import BaseTaskAllocation + @ClassFactory.register(ClassType.STP) -class TaskAllocationByOrigin: +class TaskAllocationByOrigin(BaseTaskAllocation): """ Corresponding to `TaskDefinitionByOrigin` Parameters ---------- task_extractor : Dict - used to match target tasks + used to predict target tasks for each inference samples origins: List[Metadata] metadata is usually a class feature label with a finite values. """ def __init__(self, task_extractor, **kwargs): - self.task_extractor = task_extractor + super(TaskAllocationByOrigin, self).__init__(task_extractor) self.default_origin = kwargs.get("default", None) def __call__(self, samples: BaseDataSource): diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_default.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_default.py deleted file mode 100644 index f3d07ae5..00000000 --- a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_default.py +++ /dev/null @@ -1,28 +0,0 @@ -import numpy as np -from sedna.datasources import BaseDataSource -from sedna.common.class_factory import ClassFactory, ClassType - - -@ClassFactory.register(ClassType.STP) -class TaskAllocationDefault: - """ - Corresponding to `TaskDefinitionByOrigin` - - Parameters - ---------- - task_extractor : Dict - used to match target tasks - origins: List[Metadata] - metadata is usually a class feature - label with a finite values. - """ - - def __init__(self, task_extractor, **kwargs): - self.task_extractor = task_extractor - - def __call__(self, samples: BaseDataSource): - import numpy.random as rand - allocations = [rand.randint(0, 2) - for _ in range(samples.num_examples())] - - return samples, allocations diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_simple.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_simple.py deleted file mode 100644 index 59790c24..00000000 --- a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_simple.py +++ /dev/null @@ -1,29 +0,0 @@ -import numpy as np -from sedna.datasources import BaseDataSource -from sedna.common.class_factory import ClassFactory, ClassType - - -@ClassFactory.register(ClassType.STP) -class TaskAllocationSimple: - """ - Corresponding to `TaskDefinitionByOrigin` - - Parameters - ---------- - task_extractor : Dict - used to match target tasks - origins: List[Metadata] - metadata is usually a class feature - label with a finite values. - """ - - def __init__(self, task_extractor, **kwargs): - self.task_extractor = task_extractor - - def __call__(self, samples: BaseDataSource): - allocations = np.zeros(samples.num_examples(), dtype=np.int8) - for (i, data) in enumerate(samples.x): - if "garden" in data[0]: - allocations[i] = 1 - - return samples, allocations diff --git a/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_stream.py b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_stream.py new file mode 100644 index 00000000..9118dcb8 --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_allocation/task_allocation_stream.py @@ -0,0 +1,45 @@ +# Copyright 2023 The KubeEdge 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 numpy as np +from sedna.datasources import BaseDataSource +from sedna.common.class_factory import ClassFactory, ClassType + +from .base_task_allocation import BaseTaskAllocation + +# TODO: this class is just for demonstrate + + +@ClassFactory.register(ClassType.STP) +class TaskAllocationStream(BaseTaskAllocation): + """ + Corresponding to `TaskDefinitionByOrigin` + + Parameters + ---------- + task_extractor : Dict + used to predict target tasks for each inference sample + origins: List[Metadata] + metadata is usually a class feature + label with a finite values. + """ + + def __init__(self, task_extractor, **kwargs): + super(TaskAllocationStream, self).__init__(task_extractor) + + def __call__(self, samples: BaseDataSource): + allocations = [np.random.randint(0, 1) + for _ in range(samples.num_examples())] + + return samples, allocations diff --git a/lib/sedna/algorithms/seen_task_learning/task_definition/__init__.py b/lib/sedna/algorithms/seen_task_learning/task_definition/__init__.py index 76cf4763..667a3397 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_definition/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/task_definition/__init__.py @@ -1,3 +1,16 @@ +# Copyright 2023 The KubeEdge 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. + from . import task_definition from . import task_definition_by_origin -from . import task_definition_simple diff --git a/lib/sedna/algorithms/seen_task_learning/task_definition/base_task_definition.py b/lib/sedna/algorithms/seen_task_learning/task_definition/base_task_definition.py new file mode 100644 index 00000000..f08c190f --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_definition/base_task_definition.py @@ -0,0 +1,47 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Divide multiple tasks based on data + +Parameters +---------- +samples: Train data, see `sedna.datasources.BaseDataSource` for more detail. + +Returns +------- +tasks: All tasks based on training data. +task_extractor: Model or dict with a method to predict target tasks +""" + +from typing import List, Any, Tuple + +from sedna.datasources import BaseDataSource + +from ..artifact import Task + + +class BaseTaskDefinition: + """ + Dividing datasets with all sorts of methods + """ + + def __init__(self, **kwargs): + pass + + def __call__(self, + samples: BaseDataSource) -> Tuple[List[Task], + Any, + BaseDataSource]: + raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition.py b/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition.py index 1b9bc2db..bb7d1dbe 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition.py +++ b/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -147,53 +147,3 @@ class TaskDefinitionByDataAttr: samples.x = x_data samples.y = y_data return tasks, task_index, samples - - -@ClassFactory.register(ClassType.STP) -class TaskDefinitionByCluster: - """ - Dividing datasets with all sorts of clustering methods. - - Parameters - ---------- - n_class: int or None - The number of clusters to find, default=1. - """ - - def __init__(self, **kwargs): - self.n_class = int(kwargs.get("n_class", 1)) - self.train_ratio = float(kwargs.get("train_ratio", 0.8)) - - def __call__(self, - samples: BaseDataSource, **kwargs) -> Tuple[List[Task], - Any, - BaseDataSource]: - from sklearn.svm import SVC - model = kwargs.get("model") - - tasks = [] - c2 = SVC(gamma=0.01) - partition_length = int(len(samples.x) / self.n_class) - - for i in range(self.n_class): - train_num = int(len(samples.x) * self.train_ratio) - train_samples = BaseDataSource(data_type="train") - train_samples.x = samples.x[:train_num] - train_samples.y = samples.y[:train_num] - - test_samples = BaseDataSource(data_type="eval") - test_samples.x = samples.x[train_num:] - test_samples.y = samples.y[train_num:] - - model_url = model.train(train_samples, test_samples) - model.load(model_url) - result = model.evaluate(test_samples, checkpoint_path=model_url) - - g_attr = f"svc_{i}_{time.time()}" - task_obj = Task(entry=g_attr, samples=train_samples) - task_obj.test_samples = test_samples - task_obj.model = model_url - task_obj.result = result - tasks.append(task_obj) - - return tasks, c2, samples diff --git a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_by_origin.py b/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_by_origin.py index fc208d42..14a3a1cc 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_by_origin.py +++ b/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_by_origin.py @@ -1,80 +1,73 @@ +# Copyright 2023 The KubeEdge 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. + from typing import List, Any, Tuple from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassType, ClassFactory from ..artifact import Task +from .base_task_definition import BaseTaskDefinition @ClassFactory.register(ClassType.STP) -class TaskDefinitionByOrigin: +class TaskDefinitionByOrigin(BaseTaskDefinition): """ Dividing datasets based on the their origins. Parameters ---------- - origins: List[Metadata] + attr_filed Tuple[Metadata] metadata is usually a class feature label with a finite values. """ def __init__(self, **kwargs): - self.origins = kwargs.get("origins", ["real", "sim"]) + super(TaskDefinitionByOrigin, self).__init__() + self.attribute = kwargs.get("attribute").split(", ") + self.city = kwargs.get("city") def __call__(self, samples: BaseDataSource, **kwargs) -> Tuple[List[Task], Any, BaseDataSource]: - cities = [ - "aachen", - "berlin", - "bochum", - "bremen", - "cologne", - "darmstadt", - "dusseldorf", - "erfurt", - "hamburg", - "hanover", - "jena", - "krefeld", - "monchengladbach", - "strasbourg", - "stuttgart", - "tubingen", - "ulm", - "weimar", - "zurich"] tasks = [] d_type = samples.data_type - x_data = samples.x - y_data = samples.y - - task_index = dict(zip(self.origins, range(len(self.origins)))) - real_df = BaseDataSource(data_type=d_type) - real_df.x, real_df.y = [], [] - sim_df = BaseDataSource(data_type=d_type) - sim_df.x, sim_df.y = [], [] + task_index = dict(zip(self.attribute, range(len(self.attribute)))) + sample_index = range(samples.num_examples()) - for i in range(samples.num_examples()): - is_real = False - for city in cities: - if city in x_data[i][0]: - is_real = True - real_df.x.append(x_data[i]) - real_df.y.append(y_data[i]) - break - if not is_real: - sim_df.x.append(x_data[i]) - sim_df.y.append(y_data[i]) + _idx = [i for i in sample_index if self.city in samples.y[i]] + _y = samples.y[_idx] + _x = samples.x[_idx] + _sample = BaseDataSource(data_type=d_type) + _sample.x, _sample.y = _x, _y - g_attr = "real_semantic_segamentation_model" - task_obj = Task(entry=g_attr, samples=real_df, meta_attr="real") + g_attr = f"{self.attribute[0]}.model" + task_obj = Task(entry=g_attr, samples=_sample, + meta_attr=self.attribute[0]) tasks.append(task_obj) - g_attr = "sim_semantic_segamentation_model" - task_obj = Task(entry=g_attr, samples=sim_df, meta_attr="sim") + _idx = list(set(sample_index) - set(_idx)) + _y = samples.y[_idx] + _x = samples.x[_idx] + _sample = BaseDataSource(data_type=d_type) + _sample.x, _sample.y = _x, _y + + g_attr = f"{self.attribute[-1]}.model" + task_obj = Task(entry=g_attr, samples=_sample, + meta_attr=self.attribute[-1]) tasks.append(task_obj) return tasks, task_index, samples diff --git a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_simple.py b/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_simple.py deleted file mode 100644 index 1011bdf6..00000000 --- a/lib/sedna/algorithms/seen_task_learning/task_definition/task_definition_simple.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import List, Any, Tuple - -from sedna.datasources import BaseDataSource -from sedna.common.class_factory import ClassType, ClassFactory - -from ..artifact import Task - - -@ClassFactory.register(ClassType.STP) -class TaskDefinitionSimple: - """ - Dividing datasets based on the their original sites. - - Parameters - ---------- - origins: List[Metadata] - metadata is usually a class feature label with a finite values. - """ - - def __init__(self, **kwargs): - self.origins = ["front", "garden"] - - def __call__(self, - samples: BaseDataSource, **kwargs) -> Tuple[List[Task], - Any, - BaseDataSource]: - - tasks = [] - d_type = samples.data_type - x_data = samples.x - y_data = samples.y - - task_index = dict(zip(self.origins, range(len(self.origins)))) - - front_data = BaseDataSource(data_type=d_type) - front_data.x, front_data.y = [], [] - garden_data = BaseDataSource(data_type=d_type) - garden_data.x, garden_data.y = [], [] - - for (i, data) in enumerate(x_data): - if "front" in data[0]: - front_data.x.append(data) - front_data.y.append(y_data[i]) - else: - garden_data.x.append(data) - garden_data.y.append(y_data[i]) - - g_attr_front = "front_semantic_segamentation_model" - front_task = Task(entry=g_attr_front, - samples=front_data, meta_attr="front") - tasks.append(front_task) - - g_attr_garden = "garden_semantic_segamentation_model" - garden_task = Task(entry=g_attr_garden, - samples=garden_data, meta_attr="garden") - tasks.append(garden_task) - - return tasks, task_index, samples diff --git a/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/__init__.py b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/__init__.py index 7f64dae5..8ef70d58 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/__init__.py @@ -1,2 +1,15 @@ +# Copyright 2023 The KubeEdge 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. from . import task_relation_discovery diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/base.py b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/base_task_relation_discovery.py similarity index 52% rename from examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/base.py rename to lib/sedna/algorithms/seen_task_learning/task_relation_discovery/base_task_relation_discovery.py index 5c8cc789..303656a5 100644 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/control/legged/base.py +++ b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/base_task_relation_discovery.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,23 +11,31 @@ # 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. -from typing import Union -from robosdk.utils.util import Config -from robosdk.utils.constant import GaitType -from robosdk.sensors.base import SensorBase +""" +Discover relationships between all tasks +Parameters +---------- +tasks :all tasks form `task_definition` -__all__ = ("LeggedController", ) +Returns +------- +task_groups : List of groups which including at least 1 task. +""" +from typing import List +from ..artifact import Task, TaskGroup -class LeggedController(SensorBase): # noqa - def __init__(self, name, config: Config = None): - super(LeggedController, self).__init__(name=name, config=config) - def get_curr_gait(self) -> GaitType: - raise NotImplementedError +class BaseTaskRelationDiscover: + """ + Assume that each task is independent of each other + """ + + def __init__(self, **kwargs): + pass - def change_gait(self, gait: Union[str, GaitType]): + def __call__(self, tasks: List[Task]) -> List[TaskGroup]: raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/task_relation_discovery.py b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/task_relation_discovery.py index bbbe8a06..4ae3928d 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/task_relation_discovery.py +++ b/lib/sedna/algorithms/seen_task_learning/task_relation_discovery/task_relation_discovery.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,19 +29,20 @@ from typing import List from sedna.common.class_factory import ClassType, ClassFactory from ..artifact import Task, TaskGroup +from .base_task_relation_discovery import BaseTaskRelationDiscover __all__ = ('DefaultTaskRelationDiscover',) @ClassFactory.register(ClassType.STP) -class DefaultTaskRelationDiscover: +class DefaultTaskRelationDiscover(BaseTaskRelationDiscover): """ Assume that each task is independent of each other """ def __init__(self, **kwargs): - pass + super(DefaultTaskRelationDiscover, self).__init__(**kwargs) def __call__(self, tasks: List[Task]) -> List[TaskGroup]: tgs = [] diff --git a/lib/sedna/algorithms/seen_task_learning/task_remodeling/__init__.py b/lib/sedna/algorithms/seen_task_learning/task_remodeling/__init__.py index 33df6b2c..2be80def 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_remodeling/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/task_remodeling/__init__.py @@ -1,2 +1,15 @@ +# Copyright 2023 The KubeEdge 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. from . import task_remodeling diff --git a/lib/sedna/algorithms/seen_task_learning/task_remodeling/base_task_remodeling.py b/lib/sedna/algorithms/seen_task_learning/task_remodeling/base_task_remodeling.py new file mode 100644 index 00000000..a632e2a1 --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_remodeling/base_task_remodeling.py @@ -0,0 +1,45 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Remodeling tasks based on their relationships + +Parameters +---------- +mappings :all assigned tasks get from the `task_allocation` +samples : input samples + +Returns +------- +models : List of groups which including at least 1 task. +""" + +from typing import List + +from sedna.datasources import BaseDataSource + + +class BaseTaskRemodeling: + """ + Assume that each task is independent of each other + """ + + def __init__(self, models: list, **kwargs): + self.models = models + + def __call__(self, samples: BaseDataSource, mappings: List): + """ + Grouping based on assigned tasks + """ + raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/task_remodeling/task_remodeling.py b/lib/sedna/algorithms/seen_task_learning/task_remodeling/task_remodeling.py index 7e7a9227..aa30ef34 100644 --- a/lib/sedna/algorithms/seen_task_learning/task_remodeling/task_remodeling.py +++ b/lib/sedna/algorithms/seen_task_learning/task_remodeling/task_remodeling.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -33,17 +33,19 @@ import pandas as pd from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassFactory, ClassType +from .base_task_remodeling import BaseTaskRemodeling + __all__ = ('DefaultTaskRemodeling',) @ClassFactory.register(ClassType.STP) -class DefaultTaskRemodeling: +class DefaultTaskRemodeling(BaseTaskRemodeling): """ Assume that each task is independent of each other """ def __init__(self, models: list, **kwargs): - self.models = models + super(DefaultTaskRemodeling, self).__init__(models) def __call__(self, samples: BaseDataSource, mappings: List): """ diff --git a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/__init__.py b/lib/sedna/algorithms/seen_task_learning/task_update_decision/__init__.py similarity index 86% rename from examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/__init__.py rename to lib/sedna/algorithms/seen_task_learning/task_update_decision/__init__.py index 6c3a9b92..eccb6c51 100644 --- a/examples/lifelong_learning/robot_dog_delivery/robo_detection/robosdk/sensors/camera/__init__.py +++ b/lib/sedna/algorithms/seen_task_learning/task_update_decision/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .ros import RosCameraDriver +from . import task_update_decision_finetune diff --git a/lib/sedna/algorithms/seen_task_learning/task_update_decision/base_task_update_decision.py b/lib/sedna/algorithms/seen_task_learning/task_update_decision/base_task_update_decision.py new file mode 100644 index 00000000..1818eb74 --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_update_decision/base_task_update_decision.py @@ -0,0 +1,63 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Divide multiple tasks based on data + +Parameters +---------- +samples: Train data, see `sedna.datasources.BaseDataSource` for more detail. + +Returns +------- +tasks: All tasks based on training data. +task_extractor: Model or dict with a method to predict target tasks +""" + +from typing import List, Dict, Tuple + +from sedna.common.file_ops import FileOps +from sedna.common.constant import KBResourceConstant +from sedna.datasources import BaseDataSource + +from ..artifact import Task + + +class BaseTaskUpdateDecision: + """ + Decide processing strategies for different tasks + with labeled unseen samples. + Turn unseen samples to be seen. + + Parameters + ---------- + task_index: str or Dict + """ + + def __init__(self, task_index, **kwargs): + if isinstance(task_index, str): + if not FileOps.exists(task_index): + raise Exception(f"{task_index} not exists!") + self.task_index = FileOps.load(task_index) + else: + self.task_index = task_index + + self.seen_task_key = KBResourceConstant.SEEN_TASK.value + self.unseen_task_key = KBResourceConstant.UNSEEN_TASK.value + self.task_group_key = KBResourceConstant.TASK_GROUPS.value + self.extractor_key = KBResourceConstant.EXTRACTOR.value + + def __call__(self, + samples: BaseDataSource) -> Tuple[List[Task], Dict]: + raise NotImplementedError diff --git a/lib/sedna/algorithms/seen_task_learning/task_update_decision/task_update_decision_finetune.py b/lib/sedna/algorithms/seen_task_learning/task_update_decision/task_update_decision_finetune.py new file mode 100644 index 00000000..85033a2d --- /dev/null +++ b/lib/sedna/algorithms/seen_task_learning/task_update_decision/task_update_decision_finetune.py @@ -0,0 +1,108 @@ +# Copyright 2023 The KubeEdge 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. + +from typing import List, Tuple, Dict + +from sedna.datasources import BaseDataSource +from sedna.common.class_factory import ClassType, ClassFactory + +from ..artifact import Task +from .base_task_update_decision import BaseTaskUpdateDecision + +__all__ = ('UpdateStrategyDefault', ) + + +@ClassFactory.register(ClassType.KM) +class UpdateStrategyByFinetune(BaseTaskUpdateDecision): + """ + Finetuning all the samples based on knowledgebase + to turn unseen samples to be seen. + + Parameters + ---------- + task_index: str or Dict + """ + + def __init__(self, task_index, **kwargs): + super(UpdateStrategyByFinetune, self).__init__(task_index) + self.attribute = kwargs.get("attribute").split(", ") + if not self.attribute: + self.attribute = ("real", "sim") + self.city = kwargs.get("city", "berlin") + + def __call__(self, samples, task_type) -> Tuple[List[Task], Dict]: + """ + Parameters + ---------- + samples: BaseDataSource + seen task samples or unseen task samples to be processed. + task_type: str + "seen_task" or "unseen_task". + See sedna.common.constant.KBResourceConstant for more details. + + Returns + ------- + self.tasks: List[Task] + tasks to be processed. + task_update_strategies: Dict + strategies to process each task. + """ + + if task_type == self.seen_task_key: + task_index = self.task_index[self.seen_task_key] + else: + task_index = self.task_index[self.unseen_task_key] + + task_groups = task_index[self.task_group_key] + tasks = [task_group.tasks[0] for task_group in task_groups] + + d_type = samples.data_type + sample_index = range(samples.num_examples()) + + task_update_strategies = {} + for task in tasks: + task_update_strategies[task.entry] = { + "raw_data_update": None, + "target_model_update": None, + "task_attr_update": None, + } + + _idx = [i for i in sample_index if self.city in samples.y[i]] + _y = samples.y[_idx] + _x = samples.x[_idx] + _sample = BaseDataSource(data_type=d_type) + _sample.x, _sample.y = _x, _y + task = tasks[[i for i, task in enumerate(tasks) if + task.meta_attr == self.attribute[0]]][0] + task.samples = _sample + task_update_strategies[task.entry] = { + "raw_data_update": _sample, + "target_model_update": True, + "task_attr_update": None, + } + + _idx = list(set(sample_index) - set(_idx)) + _y = samples.y[_idx] + _x = samples.x[_idx] + _sample = BaseDataSource(data_type=d_type) + _sample.x, _sample.y = _x, _y + task = tasks[[i for i, task in enumerate( + tasks) if task.meta_attr == self.attribute[1]]][0] + task.samples = _sample + task_update_strategies[task.entry] = { + "raw_data_update": _sample, + "target_model_update": True, + "task_attr_update": None, + } + return tasks, task_update_strategies diff --git a/lib/sedna/algorithms/unseen_task_detect/__init__.py b/lib/sedna/algorithms/unseen_task_detect/__init__.py index f31596a2..bd088d44 100644 --- a/lib/sedna/algorithms/unseen_task_detect/__init__.py +++ b/lib/sedna/algorithms/unseen_task_detect/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/unseen_task_detection/__init__.py b/lib/sedna/algorithms/unseen_task_detection/__init__.py index c5c18252..00901939 100644 --- a/lib/sedna/algorithms/unseen_task_detection/__init__.py +++ b/lib/sedna/algorithms/unseen_task_detection/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/__init__.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/__init__.py index fd9d4f54..ac7a09b9 100644 --- a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/__init__.py +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/base_unseen_sample_re_recognition.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/base_unseen_sample_re_recognition.py new file mode 100644 index 00000000..ec6c3702 --- /dev/null +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/base_unseen_sample_re_recognition.py @@ -0,0 +1,69 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Divide labeled unseen samples into seen tasks and unseen tasks. + +Parameters +---------- +task_index: str or Dict + knowledge base index which includes indexes of + tasks, samples, models, etc. + +Returns +------- +seen_task_samples: seen samples, see `sedna.datasources.BaseDataSource` +for more detail +unseen_task_samples: unseen samples, see `sedna.datasources.BaseDataSource` +for more detail +""" + +from sedna.common.file_ops import FileOps +from sedna.datasources import BaseDataSource + + +class BaseSampleReRegonition: + # TODO: to be completed + ''' + Divide labeled unseen samples into seen tasks and unseen tasks. + + Parameters + ---------- + task_index: str or Dict + knowledge base index which includes indexes + of tasks, samples, models, etc. + ''' + + def __init__(self, task_index, **kwargs): + if isinstance(task_index, str): + if not FileOps.exists(task_index): + raise Exception(f"{task_index} not exists!") + + self.task_index = FileOps.load(task_index) + else: + self.task_index = task_index + + def __call__(self, samples: BaseDataSource): + ''' + Parameters + ---------- + samples: training samples + + Returns + ------- + seen_task_samples: BaseDataSource + unseen_task_samples: BaseDataSource + ''' + + raise NotImplementedError diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/unseen_sample_re_recognition.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/unseen_sample_re_recognition.py index 3222b8f2..7db3a5fc 100644 --- a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/unseen_sample_re_recognition.py +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_re_recognition/unseen_sample_re_recognition.py @@ -1,22 +1,40 @@ +# Copyright 2023 The KubeEdge 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. + from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassFactory, ClassType +from .base_unseen_sample_re_recognition import BaseSampleReRegonition + __all__ = ('SampleReRegonitionDefault', ) @ClassFactory.register(ClassType.UTD) -class SampleReRegonitionDefault: +class SampleReRegonitionDefault(BaseSampleReRegonition): # TODO: to be completed ''' - Divide inference samples into seen tasks and unseen tasks. + Divide labeled unseen samples into seen tasks and unseen tasks. Parameters ---------- task_index: str or Dict + knowledge base index which includes indexes + of tasks, samples, models, etc. ''' def __init__(self, task_index, **kwargs): - pass + super(SampleReRegonitionDefault, self).__init__(task_index) def __call__(self, samples: BaseDataSource): ''' diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/__init__.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/__init__.py index e7db0c7d..803f1c76 100644 --- a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/__init__.py +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/base_unseen_sample_recognition.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/base_unseen_sample_recognition.py new file mode 100644 index 00000000..7d2b72c9 --- /dev/null +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/base_unseen_sample_recognition.py @@ -0,0 +1,68 @@ +# Copyright 2023 The KubeEdge 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. + +""" +Divide inference samples into seen samples and unseen samples + +Parameters +---------- +task_index: str or dict + knowledge base index which includes indexes of tasks, samples and etc. + +Returns +------- +seen_task_samples: seen samples, see `sedna.datasources.BaseDataSource` +for more detail +unseen_task_samples: unseen samples, see `sedna.datasources.BaseDataSource` +for more detail +""" + +from typing import Tuple + +from sedna.common.file_ops import FileOps +from sedna.datasources import BaseDataSource + + +class BaseSampleRegonition: + ''' + Divide inference samples into seen samples and unseen samples + + Parameters + ---------- + task_index: str or dict + knowledge base index which includes indexes of tasks, samples and etc. + ''' + + def __init__(self, task_index, **kwargs): + if isinstance(task_index, str) and FileOps.exists(task_index): + self.task_index = FileOps.load(task_index) + else: + self.task_index = task_index + + def __call__(self, + samples: BaseDataSource) -> Tuple[BaseDataSource, + BaseDataSource]: + ''' + Parameters + ---------- + samples : BaseDataSource + inference samples + + Returns + ------- + seen_task_samples: BaseDataSource + unseen_task_samples: BaseDataSource + ''' + + raise NotImplementedError diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_detection.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_detection.py index a60288db..76b77616 100644 --- a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_detection.py +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_detection.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 time import json diff --git a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_recognition.py b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_recognition.py index 0b80552f..8bb6c64d 100644 --- a/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_recognition.py +++ b/lib/sedna/algorithms/unseen_task_detection/unseen_sample_recognition/unseen_sample_recognition.py @@ -1,14 +1,29 @@ +# Copyright 2023 The KubeEdge 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. + from typing import Tuple -from sedna.common.file_ops import FileOps from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassFactory, ClassType +from .base_unseen_sample_recognition import BaseSampleRegonition + __all__ = ('SampleRegonitionDefault', 'SampleRegonitionByRFNet') @ClassFactory.register(ClassType.UTD) -class SampleRegonitionDefault: +class SampleRegonitionDefault(BaseSampleRegonition): ''' Divide inference samples into seen samples and unseen samples @@ -19,10 +34,7 @@ class SampleRegonitionDefault: ''' def __init__(self, task_index, **kwargs): - if isinstance(task_index, str) and FileOps.exists(task_index): - self.task_index = FileOps.load(task_index) - else: - self.task_index = task_index + super(SampleRegonitionDefault, self).__init__(task_index) def __call__(self, samples: BaseDataSource) -> Tuple[BaseDataSource, @@ -40,7 +52,7 @@ class SampleRegonitionDefault: ''' import random seen_task_samples = BaseDataSource(data_type=samples.data_type) - unseen_task_samples = BaseDataSource(data_type=samples.data_type)\ + unseen_task_samples = BaseDataSource(data_type=samples.data_type) if samples.num_examples() == 1: random_index = random.randint(0, 1) @@ -50,10 +62,10 @@ class SampleRegonitionDefault: else: seen_task_samples.x = samples.x unseen_task_samples.x = [] - return seen_task_samples, unseen_task_samples, None, None + return seen_task_samples, unseen_task_samples sample_num = int(len(samples.x) / 2) seen_task_samples.x = samples.x[:sample_num] unseen_task_samples.x = samples.x[sample_num:] - return seen_task_samples, unseen_task_samples, None, None + return seen_task_samples, unseen_task_samples diff --git a/lib/sedna/algorithms/unseen_task_processing/__init__.py b/lib/sedna/algorithms/unseen_task_processing/__init__.py index 431955b7..dc27b78e 100644 --- a/lib/sedna/algorithms/unseen_task_processing/__init__.py +++ b/lib/sedna/algorithms/unseen_task_processing/__init__.py @@ -1,2 +1,16 @@ +# Copyright 2023 The KubeEdge 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. + from . import unseen_task_allocation from .unseen_task_processing import UnseenTaskProcessing diff --git a/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/__init__.py b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/__init__.py index 281958c9..50848767 100644 --- a/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/__init__.py +++ b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/__init__.py @@ -1 +1,15 @@ +# Copyright 2023 The KubeEdge 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. + from . import unseen_task_allocation diff --git a/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/base_unseen_task_allocation.py b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/base_unseen_task_allocation.py new file mode 100644 index 00000000..4562715d --- /dev/null +++ b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/base_unseen_task_allocation.py @@ -0,0 +1,60 @@ +# Copyright 2023 The KubeEdge 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. + +''' +Mining tasks of inference unseen sample +base on unseen task attribute extractor + +Parameters +---------- +samples : infer unseen sample, +see `sedna.datasources.BaseDataSource` for more detail. + +Returns +------- +allocations : tasks that assigned to each sample +''' + +from sedna.datasources import BaseDataSource + + +class BaseUnseenTaskAllocation: + # TODO: to be completed + """ + Task allocation for unseen data + + Parameters + ---------- + task_extractor : Dict + used to match target tasks + """ + + def __init__(self, task_extractor, **kwargs): + self.task_extractor = task_extractor + + def __call__(self, samples: BaseDataSource): + ''' + Parameters + ---------- + samples: samples to be allocated + + Returns + ------- + samples: BaseDataSource + grouped samples based on allocations + allocations: List + allocation decision for actual inference + ''' + + raise NotImplementedError diff --git a/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/unseen_task_allocation.py b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/unseen_task_allocation.py index d49a8f1b..f383f8ea 100644 --- a/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/unseen_task_allocation.py +++ b/lib/sedna/algorithms/unseen_task_processing/unseen_task_allocation/unseen_task_allocation.py @@ -1,12 +1,28 @@ +# Copyright 2023 The KubeEdge 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. + from sedna.common.log import LOGGER from sedna.datasources import BaseDataSource from sedna.common.class_factory import ClassFactory, ClassType +from .base_unseen_task_allocation import BaseUnseenTaskAllocation + __all__ = ('UnseenTaskAllocationDefault', ) @ClassFactory.register(ClassType.UTP) -class UnseenTaskAllocationDefault: +class UnseenTaskAllocationDefault(BaseUnseenTaskAllocation): # TODO: to be completed """ Task allocation for unseen data @@ -18,7 +34,7 @@ class UnseenTaskAllocationDefault: """ def __init__(self, task_extractor, **kwargs): - self.task_extractor = task_extractor + super(UnseenTaskAllocationDefault, self).__init__(task_extractor) self.log = LOGGER def __call__(self, samples: BaseDataSource): diff --git a/lib/sedna/algorithms/unseen_task_processing/unseen_task_processing.py b/lib/sedna/algorithms/unseen_task_processing/unseen_task_processing.py index f7e8c1f4..de7f8e18 100644 --- a/lib/sedna/algorithms/unseen_task_processing/unseen_task_processing.py +++ b/lib/sedna/algorithms/unseen_task_processing/unseen_task_processing.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 json from sedna.backend import set_backend diff --git a/lib/sedna/core/lifelong_learning/__init__.py b/lib/sedna/core/lifelong_learning/__init__.py index faaadf9e..4d4b5149 100644 --- a/lib/sedna/core/lifelong_learning/__init__.py +++ b/lib/sedna/core/lifelong_learning/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/__init__.py b/lib/sedna/core/lifelong_learning/knowledge_management/__init__.py index 2fa270a4..d9087de1 100644 --- a/lib/sedna/core/lifelong_learning/knowledge_management/__init__.py +++ b/lib/sedna/core/lifelong_learning/knowledge_management/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,4 +15,3 @@ from .base_knowledge_management import BaseKnowledgeManagement from .cloud_knowledge_management import CloudKnowledgeManagement from .edge_knowledge_management import EdgeKnowledgeManagement -from . import task_update_decision diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/base_knowledge_management.py b/lib/sedna/core/lifelong_learning/knowledge_management/base_knowledge_management.py index d8db4ed4..29ee2612 100644 --- a/lib/sedna/core/lifelong_learning/knowledge_management/base_knowledge_management.py +++ b/lib/sedna/core/lifelong_learning/knowledge_management/base_knowledge_management.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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. + from sedna.backend import set_backend from sedna.common.log import LOGGER from sedna.common.constant import KBResourceConstant @@ -6,6 +20,22 @@ from sedna.service.client import KBClient class BaseKnowledgeManagement: + """ + Base class of knowledge management. + It includes model and sample update to knowledge base server. + + Parameters: + config: BaseConfig, see 'sedna.common.config.BaseConfig' for more details. + It sets basic configs for knowledge management. + seen_estimator: Instance + An instance with the high-level API that greatly simplifies + machine learning programming. Estimators encapsulate training, + evaluation, prediction, and exporting for a model. + unseen_estimator: Instance + An instance with the high-level API that greatly simplifies mechanism + model learning programming. Estimators encapsulate training, + evaluation, prediction, and exporting for a mechanism model. + """ def __init__(self, config, seen_estimator, unseen_estimator): self.config = BaseConfig() diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/cloud_knowledge_management.py b/lib/sedna/core/lifelong_learning/knowledge_management/cloud_knowledge_management.py index 27241efd..64608adc 100644 --- a/lib/sedna/core/lifelong_learning/knowledge_management/cloud_knowledge_management.py +++ b/lib/sedna/core/lifelong_learning/knowledge_management/cloud_knowledge_management.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 time import tempfile @@ -16,11 +30,6 @@ __all__ = ('CloudKnowledgeManagement', ) class CloudKnowledgeManagement(BaseKnowledgeManagement): """ Manage task processing, kb update and task deployment, etc., at cloud. - - Parameters: - ---------- - config: Dict - parameters to initialize an object """ def __init__(self, config, seen_estimator, unseen_estimator, **kwargs): diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/edge_knowledge_management.py b/lib/sedna/core/lifelong_learning/knowledge_management/edge_knowledge_management.py index cebc0041..cb67351b 100644 --- a/lib/sedna/core/lifelong_learning/knowledge_management/edge_knowledge_management.py +++ b/lib/sedna/core/lifelong_learning/knowledge_management/edge_knowledge_management.py @@ -1,3 +1,17 @@ +# Copyright 2023 The KubeEdge 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 time import tempfile @@ -20,15 +34,6 @@ __all__ = ('EdgeKnowledgeManagement', ) class EdgeKnowledgeManagement(BaseKnowledgeManagement): """ Manage inference, knowledge base update, etc., at the edge. - - Parameters: - ---------- - config: Dict - parameters to initialize an object - estimator: Instance - An instance with the high-level API that greatly simplifies - machine learning programming. Estimators encapsulate training, - evaluation, prediction, and exporting for your model. """ def __init__(self, config, seen_estimator, unseen_estimator, **kwargs): @@ -45,6 +50,8 @@ class EdgeKnowledgeManagement(BaseKnowledgeManagement): self.pinned_service_start = False self.unseen_sample_observer = None + self.current_index_version = None + self.lastest_index_version = None def update_kb(self, task_index): if isinstance(task_index, str): @@ -74,9 +81,12 @@ class EdgeKnowledgeManagement(BaseKnowledgeManagement): self.task_group_key: unseen_task_groups, self.extractor_key: unseen_extractor }, - "created_time": task_index.get("created_time", str(time.time())) + "create_time": task_index.get("create_time", str(time.time())) } + self.current_index_version = str(task_info.get("create_time")) + self.lastest_index_version = self.current_index_version + fd, name = tempfile.mkstemp() FileOps.dump(task_info, name) return FileOps.upload(name, self.task_index) @@ -112,6 +122,8 @@ class EdgeKnowledgeManagement(BaseKnowledgeManagement): _task.samples.data_url = FileOps.download( _task.samples.data_url, sample_dir) + self.log.info(f"Download {_task.entry} to the edge.") + save_extractor = FileOps.join_path( self.edge_output_url, task_type, KBResourceConstant.TASK_EXTRACTOR_NAME.value @@ -121,12 +133,12 @@ class EdgeKnowledgeManagement(BaseKnowledgeManagement): return extractor, task_groups def save_unseen_samples(self, samples, post_process): - if callable(post_process): - # customized sample saving function - post_process(samples.x, self.local_unseen_save_url) - return - for sample in samples.x: + if callable(post_process): + # customized sample saving function + post_process(sample, self.local_unseen_save_url) + continue + if isinstance(sample, dict): img = sample.get("image") image_name = "{}.png".format(str(time.time())) @@ -163,15 +175,11 @@ class ModelHotUpdateThread(threading.Thread): ) if model_check_time < 1: LOGGER.warning("Catch an abnormal value in " - "`MODEL_POLL_PERIOD_SECONDS`, fallback with 60") + "`MODEL_POLL_PERIOD_SECONDS`, fallback with 30") model_check_time = 30 - self.version = None self.edge_knowledge_management = edge_knowledge_management self.check_time = model_check_time self.callback = callback - task_index = edge_knowledge_management.task_index - if FileOps.exists(task_index): - self.version = str(FileOps.load(task_index).get("create_time")) super(ModelHotUpdateThread, self).__init__() @@ -180,36 +188,15 @@ class ModelHotUpdateThread(threading.Thread): def run(self): while True: time.sleep(self.check_time) - latest_task_index = Context.get_parameters("MODEL_URLS", None) - if not latest_task_index: + if not self.edge_knowledge_management.current_index_version: continue - latest_task_index = FileOps.load(latest_task_index) - latest_version = str(latest_task_index.get("create_time")) - - if latest_version == self.version: + latest_task_index = Context.get_parameters("MODEL_URLS") + if not latest_task_index: continue - self.version = latest_version - with self.MODEL_MANIPULATION_SEM: - LOGGER.info( - f"Update model start with version {self.version}") - try: - task_index = self.edge_knowledge_management.task_index - task_index_url = \ - FileOps.dump(latest_task_index, task_index) - # TODO: update local kb with the latest index.pkl - self.edge_knowledge_management.update_kb(task_index_url) - - status = K8sResourceKindStatus.COMPLETED.value - LOGGER.info(f"Update task index complete " - f"with version {self.version}") - except Exception as e: - LOGGER.error(f"fail to update task index: {e}") - status = K8sResourceKindStatus.FAILED.value - if self.callback: - self.callback( - task_info=None, status=status, kind="deploy" - ) + latest_task_index = FileOps.load(latest_task_index) + self.edge_knowledge_management.lastest_index_version = str( + latest_task_index.get("create_time")) class UnseenSampleUploadingHandler(FileSystemEventHandler): @@ -225,7 +212,7 @@ class UnseenSampleUploadingHandler(FileSystemEventHandler): LOGGER.info(f"Unseen sample uploading service starts.") def on_created(self, event): - time.sleep(2.0) + time.sleep(1.0) sample_name = os.path.basename(event.src_path) FileOps.upload(event.src_path, FileOps.join_path( self.unseen_save_url, sample_name)) diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/__init__.py b/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/__init__.py deleted file mode 100644 index 7b6f181d..00000000 --- a/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - -from . import task_update_decision diff --git a/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/task_update_decision.py b/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/task_update_decision.py deleted file mode 100644 index 6c8c104b..00000000 --- a/lib/sedna/core/lifelong_learning/knowledge_management/task_update_decision/task_update_decision.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2021 The KubeEdge 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. - -from sedna.common.file_ops import FileOps -from sedna.datasources import BaseDataSource -from sedna.common.class_factory import ClassType, ClassFactory - -__all__ = ('UpdateStrategyDefault', ) - - -@ClassFactory.register(ClassType.KM) -class UpdateStrategyDefault: - """ - Decide processing strategies for different tasks - with labeled unseen samples. - Turn unseen samples to be seen. - - Parameters - ---------- - task_index: str or Dict - """ - - def __init__(self, task_index, **kwargs): - if isinstance(task_index, str): - task_index = FileOps.load(task_index) - self.task_index = task_index - - def __call__(self, samples, task_type): - """ - Parameters - ---------- - samples: BaseDataSource - seen task samples or unseen task samples to be processed. - task_type: str - "seen_task" or "unseen_task". - See sedna.common.constant.KBResourceConstant for more details. - - Returns - ------- - self.tasks: List[Task] - tasks to be processed. - task_update_strategies: Dict - strategies to process each task. - """ - - if task_type == "seen_task": - task_index = self.task_index["seen_task"] - else: - task_index = self.task_index["unseen_task"] - - self.extractor = task_index["extractor"] - task_groups = task_index["task_groups"] - - tasks = [task_group.tasks[0] for task_group in task_groups] - - task_update_strategies = {} - for task in tasks: - task_update_strategies[task.entry] = { - "raw_data_update": None, - "target_model_update": None, - "task_attr_update": None, - } - - x_data = samples.x - y_data = samples.y - d_type = samples.data_type - - for task in tasks: - origin = task.meta_attr - _x = [x for x in x_data if origin in x[0]] - _y = [y for y in y_data if origin in y] - - task_df = BaseDataSource(data_type=d_type) - task_df.x = _x - task_df.y = _y - - task.samples = task_df - - task_update_strategies[task.entry] = { - "raw_data_update": samples, - "target_model_update": samples, - "task_attr_update": samples - } - - return tasks, task_update_strategies diff --git a/lib/sedna/core/lifelong_learning/lifelong_learning.py b/lib/sedna/core/lifelong_learning/lifelong_learning.py index 3722d4cb..13419a12 100644 --- a/lib/sedna/core/lifelong_learning/lifelong_learning.py +++ b/lib/sedna/core/lifelong_learning/lifelong_learning.py @@ -1,4 +1,4 @@ -# Copyright 2021 The KubeEdge Authors. +# Copyright 2023 The KubeEdge Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ from sedna.core.base import JobBase from sedna.common.file_ops import FileOps from sedna.common.constant import K8sResourceKind, K8sResourceKindStatus, \ KBResourceConstant -from sedna.common.config import Context +from sedna.common.config import Context, BaseConfig from sedna.common.class_factory import ClassType, ClassFactory from sedna.algorithms.seen_task_learning.seen_task_learning \ import SeenTaskLearning @@ -307,10 +307,14 @@ class LifelongLearning(JobBase): callback_func = ClassFactory.get_cls( ClassType.CALLBACK, post_process) - task_index_url = self.get_parameters( + task_index_url = Context.get_parameters( "CLOUD_KB_INDEX", self.cloud_knowledge_management.task_index) + task_index_url = FileOps.join_path( + BaseConfig.data_path_prefix, task_index_url) index_url = self.cloud_knowledge_management.local_task_index_url FileOps.download(task_index_url, index_url) + self.log.info( + f"Download last task index from {task_index_url} to {index_url}") unseen_sample_re_recognition = ClassFactory.get_cls( ClassType.UTD, self.unseen_sample_re_recognition["method"])( @@ -407,7 +411,11 @@ class LifelongLearning(JobBase): kind="eval") return callback_func(res) if callback_func else res - def inference(self, data=None, post_process=None, **kwargs): + def inference(self, + data=None, + post_process=None, + unseen_sample_postprocess=None, + **kwargs): """ predict the result for input data based on training knowledge. @@ -419,6 +427,9 @@ class LifelongLearning(JobBase): post_process: function function or a registered method, effected after `estimator` prediction, like: label transform. + unseen_sample_postprocess: function + function or a registered method, effected when unseen samples + need to be saved kwargs: Dict parameters for `estimator` predict, Like: `ntree_limit` in Xgboost.XGBClassifier @@ -428,13 +439,29 @@ class LifelongLearning(JobBase): """ res, tasks, is_unseen_task = None, [], False + index_url = self.edge_knowledge_management.task_index + current_version = self.edge_knowledge_management.current_index_version + lastest_version = self.edge_knowledge_management.lastest_index_version + + if not FileOps.exists(index_url) or (current_version and + lastest_version and + current_version != + lastest_version): + task_index_url = Context.get_parameters( + "MODEL_URLS", self.cloud_knowledge_management.task_index) + self.log.info( + f"Download kb index from {task_index_url} to {index_url}") + FileOps.download(task_index_url, index_url) + + self.log.info(f"Deploying tasks to the edge.") + self.edge_knowledge_management.update_kb(index_url) + if not self.start_inference_service: self._start_inference_service() self.start_inference_service = True - seen_samples, unseen_samples, prediction, allocated_seen_tasks = \ - self.recognize_unseen_samples( - data, **kwargs) + seen_samples, unseen_samples = self.recognize_unseen_samples( + data, **kwargs) if unseen_samples.x is not None and unseen_samples.num_examples() > 0: self.edge_knowledge_management.log.info( f"Unseen task is detected.") @@ -444,7 +471,7 @@ class LifelongLearning(JobBase): task_index=self.edge_knowledge_management.task_index) self.edge_knowledge_management.save_unseen_samples( - unseen_samples, post_process) + unseen_samples, post_process=unseen_sample_postprocess) res = unseen_res tasks.extend(unseen_tasks) @@ -461,8 +488,6 @@ class LifelongLearning(JobBase): data=seen_samples, post_process=post_process, task_index=self.edge_knowledge_management.task_index, task_type="seen_task", - prediction=prediction, - tasks=allocated_seen_tasks, **kwargs ) res = np.concatenate((res, seen_res)) if res else seen_res @@ -486,17 +511,6 @@ class LifelongLearning(JobBase): ) self.unseen_sample_detection.start() - task_index_url = Context.get_parameters( - "MODEL_URLS", self.cloud_knowledge_management.task_index) - index_url = self.edge_knowledge_management.task_index - if not FileOps.exists(index_url): - self.log.info( - f"Download kb index from {task_index_url} to {index_url}") - FileOps.download(task_index_url, index_url) - - self.log.info(f"Deploying tasks to the edge.") - self.edge_knowledge_management.update_kb(index_url) - if not callable(self.recognize_unseen_samples): self.recognize_unseen_samples = \ ClassFactory.get_cls( diff --git a/lib/sedna/datasources/__init__.py b/lib/sedna/datasources/__init__.py index 35f8502f..061885c5 100644 --- a/lib/sedna/datasources/__init__.py +++ b/lib/sedna/datasources/__init__.py @@ -17,7 +17,6 @@ from pathlib import Path import numpy as np import pandas as pd -from pycocotools.coco import COCO from sedna.common.file_ops import FileOps from sedna.common.class_factory import ClassFactory, ClassType @@ -122,6 +121,8 @@ class CSVDataParse(BaseDataSource, ABC): return pd.DataFrame.from_dict([lines], **kwargs) def parse(self, *args, **kwargs): + from pycocotools.coco import COCO + x_data = [] y_data = [] label = kwargs.pop("label") if "label" in kwargs else "" diff --git a/lib/sedna/service/server/base.py b/lib/sedna/service/server/base.py index 4ab39ac4..5b4a94fb 100644 --- a/lib/sedna/service/server/base.py +++ b/lib/sedna/service/server/base.py @@ -96,7 +96,7 @@ class BaseServer: """wait the stop flag to shutdown the server""" while 1: time.sleep(self.WAIT_TIME) - if not current.isAlive(): + if not current.is_alive(): return if getattr(self.app, "shutdown", False): return diff --git a/lib/sedna/service/server/knowledgeBase/server.py b/lib/sedna/service/server/knowledgeBase/server.py index a0590303..0259a357 100644 --- a/lib/sedna/service/server/knowledgeBase/server.py +++ b/lib/sedna/service/server/knowledgeBase/server.py @@ -47,8 +47,8 @@ class TaskItem(BaseModel): # pylint: disable=too-few-public-methods class KBServer(BaseServer): """ - As knowledge base stored in sqlite, this class realized creation, - update and query of sqlite. + As knowledge base stored in sqlite, this class realizes creation, + update and query of the sqlite. """ def __init__(self, host: str, http_port: int = 8080, workers: int = 1, save_dir=""):