From 96af897e6db384e49837fa0018fb011695835429 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidl Date: Mon, 20 Nov 2023 14:21:48 +0100 Subject: [PATCH] Build and host algorithm images on GitHub (base images) (#20) * wip: first version of PR test workflow * feat: adapt first algorithm to new infrastructure * fix: job generation script * feat: adapt second algorithm to new infrastructure * fix: python version * feat: allow matrix generation script to run in different contexts (folders) * refactor: split up base images and intermediate images; rename folders * feat: adjust workflow to build images in order * fix: build matrix computation script * test empty matrix * feat: prepare image publishing and adapt docker images * chore: restore lof and sublof algorithms and use kmeans; also add licenses to base images * feat: adjust r base image * chore: cleanup workflow definition * refactor: revert changes to intermediate images and algos (later PR) * feat: test image push * feat: test image push again * fix: image license information * feat: fix version information in image labels and finish PR --- .ci/check_output.py | 96 +++++++ .ci/generate-build-matrix.sh | 58 ++++ .ci/get-image-version.sh | 31 ++ .ci/get_dataset_name.py | 23 ++ .github/workflows/check-and-build.yml | 265 ++++++++++++++++++ .gitignore | 1 + 0-base-images/pyod/Dockerfile | 14 - 0-base-images/python3-base/Dockerfile | 3 +- 0-base-images/python3-base/LICENSE | 21 ++ 0-base-images/python3-base/entrypoint.sh | 11 +- 0-base-images/python3-base/version.txt | 1 + 0-base-images/r-base/LICENSE | 21 ++ 0-base-images/r-base/entrypoint.sh | 11 +- 0-base-images/r-base/version.txt | 1 + .../timeeval-test-algorithm/Dockerfile | 7 - .../timeeval-test-algorithm/algorithm.py | 41 --- 0-base-images/tsmp/Dockerfile | 12 - {3-scripts => 2-scripts}/analyze_log.py | 0 {3-scripts => 2-scripts}/check_losses.py | 0 {3-scripts => 2-scripts}/plot-scores.py | 0 {3-scripts => 2-scripts}/reverse-windowing.py | 0 README.md | 51 ++-- {1-data => data}/dataset.csv | 0 {1-data => data}/multi-dataset.csv | 0 {2-results => results}/.gitkeep | 0 25 files changed, 563 insertions(+), 105 deletions(-) create mode 100755 .ci/check_output.py create mode 100755 .ci/generate-build-matrix.sh create mode 100755 .ci/get-image-version.sh create mode 100755 .ci/get_dataset_name.py create mode 100644 .github/workflows/check-and-build.yml delete mode 100644 0-base-images/pyod/Dockerfile create mode 100644 0-base-images/python3-base/LICENSE create mode 100644 0-base-images/python3-base/version.txt create mode 100644 0-base-images/r-base/LICENSE create mode 100644 0-base-images/r-base/version.txt delete mode 100644 0-base-images/timeeval-test-algorithm/Dockerfile delete mode 100644 0-base-images/timeeval-test-algorithm/algorithm.py delete mode 100644 0-base-images/tsmp/Dockerfile rename {3-scripts => 2-scripts}/analyze_log.py (100%) rename {3-scripts => 2-scripts}/check_losses.py (100%) rename {3-scripts => 2-scripts}/plot-scores.py (100%) rename {3-scripts => 2-scripts}/reverse-windowing.py (100%) rename {1-data => data}/dataset.csv (100%) rename {1-data => data}/multi-dataset.csv (100%) rename {2-results => results}/.gitkeep (100%) diff --git a/.ci/check_output.py b/.ci/check_output.py new file mode 100755 index 0000000..ca57a1b --- /dev/null +++ b/.ci/check_output.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +import json +import sys + +from pathlib import Path + +MODEL_FILEPATH = Path("./results/model.pkl") +SCORES_FILEPATH = Path("./results/scores.csv") + + +def parse_manifest(algorithm: str) -> dict: + manifest_path = Path(".") / algorithm / "manifest.json" + with manifest_path.open("r") as fh: + manifest = json.load(fh) + return manifest + + +def is_readable(filename: Path) -> bool: + stat = filename.stat() + return stat.st_uid == 1000 and stat.st_gid == 1000 + + +def has_postprocessing(algorithm: str) -> bool: + readme_path = Path(".") / algorithm / "README.md" + if not readme_path.exists(): + return False + + with readme_path.open("r") as fh: + readme = fh.readlines() + + marker = ["", ""] + return any([m in l for m in marker for l in readme]) + + +def main(algorithm): + manifest = parse_manifest(algorithm) + errors = [] + + if manifest["learningType"].lower() in ["supervised", "semi-supervised"]: + # check model.pkl + if not is_readable(MODEL_FILEPATH): + errors.append("Model file was written with the wrong user and/or group. Do you use a TimeEval base image?") + + # check scores.csv + if not is_readable(SCORES_FILEPATH): + errors.append("Scoring was written with the wrong user and/or group. Do you use a TimeEval base image?") + + with SCORES_FILEPATH.open("r") as fh: + lines = fh.readlines() + + + # if not post-processing, check length + if has_postprocessing(algorithm): + print("Skipping scoring (scores.csv) check, because algorithm uses post-processing!") + else: + # only a single column/dimension: + if any(["," in l for l in lines]): + errors.append("Scoring contains multiple dimensions (found a ',' in the file). " + "Only a single anomaly score is allowed per time step!") + + # there should be no header + try: + float(lines[0]) + except ValueError as e: + errors.append(f"No header allowed for the scoring file! First value is not a number! {e}") + + # same length as dataset + if manifest["inputDimensionality"].lower() == "univariate": + data_path = Path("./data/dataset.csv") + else: + data_path = Path("./data/multi-dataset.csv") + + n_data = 0 + with data_path.open("r") as fh: + for _ in fh: + n_data += 1 + # substract header + n_data -= 1 + + if len(lines) != n_data: + errors.append("Scoring has wrong length; each input time step needs an anomaly score " + f"(expected={n_data}, found={len(lines)})!") + + for error in errors: + print(error, file=sys.stderr) + + if len(errors) > 0: + exit(1) + + +if __name__ == "__main__": + args = sys.argv + if len(args) != 2: + raise ValueError("You have to spacify an algorithm name (directory / docker image name)!") + + main(args[1]) diff --git a/.ci/generate-build-matrix.sh b/.ci/generate-build-matrix.sh new file mode 100755 index 0000000..9ac7503 --- /dev/null +++ b/.ci/generate-build-matrix.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -e + +default_branch=main +folder="${1:-.}" +ignore_pattern="0-base-images|1-intermediate-images|2-scripts|data|results|Dockerfile|README.md|\..*|.*\.py|.*\.yml|.*\.sh|.*\.png" +changes_in_basedir="" + +function echoerr () { + echo "$@" >&2 +} + +# GITHUB_EVENT_NAME=pull_request +# GITHUB_BASE_REF=PR target branch (probably default branch) +# GITHUB_HEAD_REF=PR source branch +# GITHUB_REF=refs/pull//merge +# GITHUB_REF_TYPE=tag or branch +# RUNNER_ARCH=X86, X64, ARM, or ARM64 +# RUNNER_OD=Linux, Windows, or macOS + +# if this is a workflow for a PR targeting the default branch +if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]] && [[ "$GITHUB_BASE_REF" == "$default_branch" ]]; then + # build diff to main + echoerr "Detected pipeline for a non-default branch (assuming pull request with target $GITHUB_BASE_REF)" + git fetch origin || echoerr "Could not update remote 'origin'! Repository might be out of date." + changes_in_basedir=$( git diff --name-only "refs/remotes/origin/$GITHUB_BASE_REF..HEAD" -- "$folder" | sed "s#${folder//\./\\.}/##" | cut -d '/' -f 1 ) + #changes_in_basedir=$( git diff --name-only "$GITHUB_BASE_REF..HEAD" | cut -d '/' -f 1 ) + +# if this is a workflow for the default branch +elif [[ "$GITHUB_EVENT_NAME" == "push" ]] && [[ "$GITHUB_BASE_REF" == "$default_branch" ]]; then + # build latest commit for the default branch + echoerr "Detected pipeline for default branch" + #changes_in_basedir=$( git diff --name-only "$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA" ) + changes_in_basedir=$( git diff --name-only HEAD~1..HEAD -- "$folder" | sed "s#${folder//\./\\.}/##" | cut -d '/' -f 1 ) + +# if this is a tag-workflow: build all algorithm images +elif [[ "$GITHUB_EVENT_NAME" == "push" ]] && [[ "$GITHUB_REF_TYPE" == "tag" ]]; then + echoerr "Detected pipeline for a tag" + changes_in_basedir=$( ls -1 ) + +else + echoerr "Cannot determine algorithm images to build! Please check the environment variables:" + env | grep "GITHUB" >&2 && true + echoerr "" +fi + +# filter changes: remove non-algorithm-files/-folders and allow grep to find nothing (exit code 1) +changed_algos=$( echo "$changes_in_basedir" | sort | uniq | grep -x -v -E "${ignore_pattern}" || [[ $? == 1 ]] ) +# filter changes: remove non-existing algos (e.g. when branch is not up-to-date with default branch or an algorithm was removed) +changed_algos=$( echo "$changed_algos" | while read -r f; do [[ -d "$folder/$f" ]] && echo "$f" || true; done ) + +if [[ -z "$changed_algos" ]]; then + echoerr "No algorithm changed!" +fi + +echoerr "Generating pipeline for algorithms: $(xargs <<<$changed_algos)" +(jq -Rc '[.]' | jq -sc '{"algorithm_name": add}') <<<"${changed_algos}" diff --git a/.ci/get-image-version.sh b/.ci/get-image-version.sh new file mode 100755 index 0000000..491047f --- /dev/null +++ b/.ci/get-image-version.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e + +folder="${1:-}" +SEMVER_REGEX="^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$" + +trim-and-validate() { + local var="$*" + # remove leading whitespace characters + var="${var#"${var%%[![:space:]]*}"}" + # remove trailing whitespace characters + var="${var%"${var##*[![:space:]]}"}" + + # validate semver version string + if [[ "$var" =~ $SEMVER_REGEX ]]; then + printf '%s' "$var" + else + echo "Version $var is not a proper version string according to SemVer 'X.Y.Z(-PRERELEASE)(+BUILD)'!" >&2 + exit 1 + fi +} + +if [[ -f "$folder/version.txt" ]]; then + trim-and-validate "$( cat "$folder/version.txt" )" +elif [[ -f "$folder/manifest.json" ]]; then + trim-and-validate "$( jq -r '.version' "$folder/manifest.json" )" +else + echo "No version.txt or manifest.json present. Cannot determine Docker image version!" >&2 + exit 1 +fi diff --git a/.ci/get_dataset_name.py b/.ci/get_dataset_name.py new file mode 100755 index 0000000..ed76753 --- /dev/null +++ b/.ci/get_dataset_name.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import json +import sys + +from pathlib import Path + +if __name__ == "__main__": + args = sys.argv + if len(args) != 2: + raise ValueError("You have to specify an algorithm name (directory / docker image name)!") + + algorithm = args[1] + manifest_path = Path(".") / algorithm / "manifest.json" + with manifest_path.open("r") as fh: + manifest = json.load(fh) + + value = manifest["inputDimensionality"] + if value.lower() == "univariate": + print("data/dataset.csv") + elif value.lower() == "multivariate": + print("data/multi-dataset.csv") + else: + raise ValueError(f"Input dimensionality ({value}) of {algorithm}'s manifest is unknown!") diff --git a/.github/workflows/check-and-build.yml b/.github/workflows/check-and-build.yml new file mode 100644 index 0000000..52cf7af --- /dev/null +++ b/.github/workflows/check-and-build.yml @@ -0,0 +1,265 @@ +name: Build images and test algorithms + +on: + pull_request: + branches: main + push: + branches: main + +defaults: + run: + shell: 'bash -Eeuo pipefail -xl {0}' + +jobs: + init: + name: Generate Jobs + runs-on: ubuntu-latest + outputs: + base_matrix: ${{ steps.generate-jobs.outputs.base_matrix }} + intermediate_matrix: ${{ steps.generate-jobs.outputs.intermediate_matrix }} + algo_matrix: ${{ steps.generate-jobs.outputs.algo_matrix }} + steps: + - uses: actions/checkout@v4 + - id: generate-jobs + name: Generate Jobs for modified base images or algorithms + run: | + base_matrix="$(./.ci/generate-build-matrix.sh 0-base-images)" + echo "base_matrix=$base_matrix" >> "$GITHUB_OUTPUT" + jq . <<<"$base_matrix" # print generated json for debugging + + intermediate_matrix="$(./.ci/generate-build-matrix.sh 1-intermediate-images)" + echo "intermediate_matrix=$intermediate_matrix" >> "$GITHUB_OUTPUT" + jq . <<<"$intermediate_matrix" # print generated json for debugging + + algo_matrix="$(./.ci/generate-build-matrix.sh)" + echo "algo_matrix=$algo_matrix" >> "$GITHUB_OUTPUT" + jq . <<<"$algo_matrix" # print generated json for debugging + + build-base-images: + name: Build base images + runs-on: ubuntu-latest + needs: init + permissions: + contents: read + packages: write + if: fromJson(needs.init.outputs.base_matrix).algorithm_name[0] != null + strategy: + max-parallel: 3 + matrix: ${{ fromJson(needs.init.outputs.base_matrix) }} + fail-fast: false + + steps: + - uses: actions/checkout@v4 + - name: Compute (and check) version + id: version + run: | + version="$(./.ci/get-image-version.sh 0-base-images/${{ matrix.algorithm_name }})" + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Compute Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/timeeval/${{ matrix.algorithm_name }} + tags: | + type=raw,value=latest + type=raw,value=${{ steps.version.outputs.version }} + labels: | + org.opencontainers.image.licenses=MIT + org.opencontainers.image.title=TimeEval ${{ matrix.algorithm_name }} base image + org.opencontainers.image.version=${{ steps.version.outputs.version }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build algorithm image + uses: docker/build-push-action@v5 + with: + context: "./0-base-images/${{ matrix.algorithm_name }}" + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + pull: true + push: ${{ github.event_name != 'pull_request' }} + cache-from: type=gha + cache-to: type=gha,mode=max + + build-intermediate-images: + name: Build intermediate images + runs-on: ubuntu-latest + needs: init + permissions: + contents: read + packages: write + if: fromJson(needs.init.outputs.intermediate_matrix).algorithm_name[0] != null + strategy: + max-parallel: 3 + matrix: ${{ fromJson(needs.init.outputs.intermediate_matrix) }} + fail-fast: false + + steps: + - uses: actions/checkout@v4 + - name: Compute (and check) version + id: version + run: | + version="$(./.ci/get-image-version.sh 1-intermediate-images/${{ matrix.algorithm_name }})" + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Compute Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/timeeval/${{ matrix.algorithm_name }} + tags: | + type=raw,value=latest + type=raw,value=${{ steps.version.outputs.version }} + labels: | + org.opencontainers.image.licenses=MIT + org.opencontainers.image.title=TimeEval ${{ matrix.algorithm_name }} intermediate image + org.opencontainers.image.version=${{ steps.version.outputs.version }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build algorithm image + uses: docker/build-push-action@v5 + with: + context: "./1-intermediate-images/${{ matrix.algorithm_name }}" + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + pull: true + push: ${{ github.event_name != 'pull_request' }} + cache-from: type=gha + cache-to: type=gha,mode=max + + test-algorithms: + name: Build and test algorithm images + runs-on: ubuntu-latest + needs: + - init + permissions: + contents: read + packages: write + if: fromJson(needs.init.outputs.algo_matrix).algorithm_name[0] != null + strategy: + max-parallel: 3 + matrix: ${{ fromJson(needs.init.outputs.algo_matrix) }} + fail-fast: false + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Validate manifest + run: python validate_manifest.py --path ${{ matrix.algorithm_name }}/manifest.json + - name: Determine correct test dataset + run: | + dataset_name="$(python .ci/get_dataset_name.py ${{ matrix.algorithm_name }})" + echo "${{ matrix.algorithm_name }}_dataset_name=$dataset_name" >> "$GITHUB_OUTPUT" + + - name: Compute (and check) version + id: version + run: | + version="$(./.ci/get-image-version.sh ${{ matrix.algorithm_name }})" + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Compute Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/timeeval/${{ matrix.algorithm_name }} + tags: | + type=raw,value=latest + type=raw,value=${{ steps.version.outputs.version }} + labels: | + org.opencontainers.image.title=TimeEval algorithm ${{ matrix.algorithm_name }} + org.opencontainers.image.version=${{ steps.version.outputs.version }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build algorithm image + uses: docker/build-push-action@v5 + with: + context: "./${{ matrix.algorithm_name }}" + tags: ${{ steps.meta.outputs.tags }} + # filter out license label, because it is set in the Dockerfile + labels: | + org.opencontainers.image.title=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.title'] }} + org.opencontainers.image.description=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.description'] }} + org.opencontainers.image.url=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.url'] }} + org.opencontainers.image.source=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.source'] }} + org.opencontainers.image.version=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} + org.opencontainers.image.created=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} + org.opencontainers.image.revision=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} + pull: true + load: true + push: false + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Prepare result folder + run: mkdir results && chmod -R 777 results + - name: Check manifest available in container + uses: addnab/docker-run-action@v3 + with: + image: "${{ matrix.algorithm_name }}:${{ github.sha }}" + options: -e LOCAL_UID=1000 -e LOCAL_GID=1000 + run: manifest + + - name: Test training call + uses: addnab/docker-run-action@v3 + with: + image: "${{ matrix.algorithm_name }}:${{ github.sha }}" + options: -e LOCAL_UID=1000 -e LOCAL_GID=1000 -v "${${{ matrix.algorithm_name }}_dataset_name}:/data/dataset.csv:ro" -v "$(pwd)/results:/results:rw" + run: | + execute-algorithm '{ + "dataInput": "/data/dataset.csv", "dataOutput": "/results/scores.csv", + "modelInput": "/results/model.pkl", "modelOutput": "/results/model.pkl", + "executionType": "train", + "customParameters": {"epochs": 1} + }' + + - name: Test execution call + uses: addnab/docker-run-action@v3 + with: + image: "${{ matrix.algorithm_name }}:${{ github.sha }}" + options: -e LOCAL_UID=1000 -e LOCAL_GID=1000 -v "${${{ matrix.algorithm_name }}_dataset_name}:/data/dataset.csv:ro" -v "$(pwd)/results:/results:rw" + run: | + execute-algorithm '{ + "dataInput": "/data/dataset.csv", "dataOutput": "/results/scores.csv", + "modelInput": "/results/model.pkl", "modelOutput": "/results/model.pkl", + "executionType": "execute", + "customParameters": {"epochs": 1} + }' + + - name: Validate output + run: | + ls -alh results/* + python .ci/check_output.py "${{ matrix.algorithm_name }}" + + # deployment for non-PRs and if all checks are successfull: + - name: Login to registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push algorithm image + if: github.event_name != 'pull_request' + uses: docker/build-push-action@v5 + with: + context: "./${{ matrix.algorithm_name }}" + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + load: false + push: true + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 7b2b8dd..fea3fee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ results **/__pycache__/ +!results/.gitkeep ######################################## # JetBrains.gitignore from github/gitignore diff --git a/0-base-images/pyod/Dockerfile b/0-base-images/pyod/Dockerfile deleted file mode 100644 index 0c2ac54..0000000 --- a/0-base-images/pyod/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM registry.gitlab.hpi.de/akita/i/python3-base - -LABEL maintainer="sebastian.schmidl@hpi.de" - -# install pyod library and cleanup afterwards -RUN set -eux; \ - pip install --no-cache-dir pyod==0.9.2; \ - find /usr/local -depth \ - \( \ - \( -type d -a \( -name test -o -name tests -o -name idle_test \) \) \ - -o \ - \( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \) \ - \) -exec rm -rf '{}' +; \ - rm -rf /tmp/* /var/tmp/* ~/.cache/pip diff --git a/0-base-images/python3-base/Dockerfile b/0-base-images/python3-base/Dockerfile index 92624e4..e6ebd0f 100644 --- a/0-base-images/python3-base/Dockerfile +++ b/0-base-images/python3-base/Dockerfile @@ -12,8 +12,6 @@ VOLUME ["/data", "/results"] WORKDIR /app -COPY entrypoint.sh /entrypoint.sh - COPY requirements.txt /tmp/ # install requirements and cleanup afterwards (also removes tests and cached cython files of the dependencies) RUN set -eux; \ @@ -26,6 +24,7 @@ RUN set -eux; \ \) -exec rm -rf '{}' +; \ rm -rf /tmp/* /var/tmp/* ~/.cache/pip +COPY entrypoint.sh /entrypoint.sh ENTRYPOINT [ "/entrypoint.sh" ] CMD [ "execute-algorithm" ] diff --git a/0-base-images/python3-base/LICENSE b/0-base-images/python3-base/LICENSE new file mode 100644 index 0000000..739212c --- /dev/null +++ b/0-base-images/python3-base/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2023 Phillip Wenig and Sebastian Schmidl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/0-base-images/python3-base/entrypoint.sh b/0-base-images/python3-base/entrypoint.sh index 6b51262..0c379d1 100755 --- a/0-base-images/python3-base/entrypoint.sh +++ b/0-base-images/python3-base/entrypoint.sh @@ -23,11 +23,18 @@ if [[ ! -z "$LOCAL_UID" ]] && [[ ! -z "$LOCAL_GID" ]]; then chown -R "$Z_UID:$Z_GID" . fi -# Either run algorithm or the supplied executable -if [[ "$1" = "execute-algorithm" ]]; then +# check and execute command +if [[ "$1" == "manifest" ]]; then + # output the algorithm manifest + cat /app/manifest.json + +elif [[ "$1" == "execute-algorithm" ]]; then + # run algorithm shift exec setpriv --reuid=$Z_UID --regid=$Z_GID --init-groups -- python "$ALGORITHM_MAIN" "$@" + else + # just run supplied command inside container exec setpriv --reuid=$Z_UID --regid=$Z_GID --init-groups -- "$@" fi diff --git a/0-base-images/python3-base/version.txt b/0-base-images/python3-base/version.txt new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/0-base-images/python3-base/version.txt @@ -0,0 +1 @@ +0.3.0 diff --git a/0-base-images/r-base/LICENSE b/0-base-images/r-base/LICENSE new file mode 100644 index 0000000..739212c --- /dev/null +++ b/0-base-images/r-base/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2023 Phillip Wenig and Sebastian Schmidl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/0-base-images/r-base/entrypoint.sh b/0-base-images/r-base/entrypoint.sh index 059d349..d1ceb21 100755 --- a/0-base-images/r-base/entrypoint.sh +++ b/0-base-images/r-base/entrypoint.sh @@ -23,11 +23,18 @@ if [[ ! -z "$LOCAL_UID" ]] && [[ ! -z "$LOCAL_GID" ]]; then chown -R "$Z_UID:$Z_GID" . fi -# Either run algorithm or the supplied executable -if [[ "$1" = "execute-algorithm" ]]; then +# check and execute command +if [[ "$1" == "manifest" ]]; then + # output the algorithm manifest + cat /app/manifest.json + +elif [[ "$1" = "execute-algorithm" ]]; then + # run algorithm shift exec setpriv --reuid=$Z_UID --regid=$Z_GID --init-groups -- Rscript "$ALGORITHM_MAIN" "$@" + else + # just run supplied command inside container exec setpriv --reuid=$Z_UID --regid=$Z_GID --init-groups -- "$@" fi diff --git a/0-base-images/r-base/version.txt b/0-base-images/r-base/version.txt new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/0-base-images/r-base/version.txt @@ -0,0 +1 @@ +0.3.0 diff --git a/0-base-images/timeeval-test-algorithm/Dockerfile b/0-base-images/timeeval-test-algorithm/Dockerfile deleted file mode 100644 index 135283b..0000000 --- a/0-base-images/timeeval-test-algorithm/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM registry.gitlab.hpi.de/akita/i/python3-base - -LABEL maintainer="phillip.wenig@hpi.de" - -ENV ALGORITHM_MAIN=/app/algorithm.py - -COPY algorithm.py /app/ diff --git a/0-base-images/timeeval-test-algorithm/algorithm.py b/0-base-images/timeeval-test-algorithm/algorithm.py deleted file mode 100644 index d4da8a0..0000000 --- a/0-base-images/timeeval-test-algorithm/algorithm.py +++ /dev/null @@ -1,41 +0,0 @@ -import numpy as np -import pandas as pd -import json -import time -import argparse -import sys - - -class AlgorithmArgs(argparse.Namespace): - @property - def ts(self) -> np.ndarray: - dataset = pd.read_csv(self.dataInput) - return dataset.values[:, 1:-1] - - @staticmethod - def from_sys_args() -> 'AlgorithmArgs': - args = json.loads(sys.argv[1]) - return AlgorithmArgs(**args) - - -def main(): - args = AlgorithmArgs.from_sys_args() - will_raise = args.customParameters.get("raise", False) - sleep_seconds = args.customParameters.get("sleep", 10) - write_preliminary_results = args.customParameters.get("write_prelim_results", False) - - results = np.zeros(args.ts.shape[0]) - - if write_preliminary_results: - results.tofile(args.dataOutput, sep="\n") - - if will_raise: - raise Exception("from within") - - time.sleep(sleep_seconds) - - results.tofile(args.dataOutput, sep="\n") - - -if __name__ == "__main__": - main() diff --git a/0-base-images/tsmp/Dockerfile b/0-base-images/tsmp/Dockerfile deleted file mode 100644 index da69c1f..0000000 --- a/0-base-images/tsmp/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM registry.gitlab.hpi.de/akita/i/r-base - -LABEL maintainer="sebastian.schmidl@hpi.de" - -# install tsmp library and cleanup afterwards -RUN set -eux; \ - R -e 'install.packages("tsmp")'; \ - find /usr/lib/R/library -depth \ - \( \ - -type d -a \( -name doc -o -name html \) \ - \) -exec rm -rf '{}' +; \ - rm -rf /tmp/* /var/tmp/* diff --git a/3-scripts/analyze_log.py b/2-scripts/analyze_log.py similarity index 100% rename from 3-scripts/analyze_log.py rename to 2-scripts/analyze_log.py diff --git a/3-scripts/check_losses.py b/2-scripts/check_losses.py similarity index 100% rename from 3-scripts/check_losses.py rename to 2-scripts/check_losses.py diff --git a/3-scripts/plot-scores.py b/2-scripts/plot-scores.py similarity index 100% rename from 3-scripts/plot-scores.py rename to 2-scripts/plot-scores.py diff --git a/3-scripts/reverse-windowing.py b/2-scripts/reverse-windowing.py similarity index 100% rename from 3-scripts/reverse-windowing.py rename to 2-scripts/reverse-windowing.py diff --git a/README.md b/README.md index ff1d160..86517e7 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@ The namespace prefix (repository) for the built Docker images is `registry.gitla | [baseline_increasing](./baseline_increasing) | `registry.gitlab.hpi.de/akita/i/baseline_increasing` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [baseline_normal](./baseline_normal) | `registry.gitlab.hpi.de/akita/i/baseline_normal` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [baseline_random](./baseline_random) | `registry.gitlab.hpi.de/akita/i/baseline_random` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [cblof](./cblof) | `registry.gitlab.hpi.de/akita/i/cblof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [cof](./cof) | `registry.gitlab.hpi.de/akita/i/cof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [copod](./copod) | `registry.gitlab.hpi.de/akita/i/copod` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [cblof](./cblof) | `registry.gitlab.hpi.de/akita/i/cblof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [cof](./cof) | `registry.gitlab.hpi.de/akita/i/cof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [copod](./copod) | `registry.gitlab.hpi.de/akita/i/copod` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [dae](./dae) (DeNoising Autoencoder) | `registry.gitlab.hpi.de/akita/i/dae` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [damp](./damp) | `registry.gitlab.hpi.de/akita/i/damp` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [dbstream](./dbstream) | `registry.gitlab.hpi.de/akita/i/dbstream` | R 4.0.5 | [`registry.gitlab.hpi.de/akita/i/r4-base`](./0-base-images/r4-base) | unsupervised | multivariate @@ -44,19 +44,19 @@ The namespace prefix (repository) for the built Docker images is `registry.gitla | [generic_xgb](./generic_xgb) | `registry.gitlab.hpi.de/akita/i/generic_xgb` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | | [grammarviz3](./grammarviz3) | `registry.gitlab.hpi.de/akita/i/grammarviz3` | Java| [`registry.gitlab.hpi.de/akita/i/java-base`](./0-base-images/java-base) | unsupervised | univariate | | [grammarviz3_multi](./grammarviz3_multi) | `registry.gitlab.hpi.de/akita/i/grammarviz3_multi` | Java| [`registry.gitlab.hpi.de/akita/i/java-base`](./0-base-images/java-base) | unsupervised | multivariate | -| [hbos](./hbos) | `registry.gitlab.hpi.de/akita/i/hbos` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [hbos](./hbos) | `registry.gitlab.hpi.de/akita/i/hbos` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [health_esn](./health_esn) | `registry.gitlab.hpi.de/akita/i/health_esn` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [hif](./hif) | `registry.gitlab.hpi.de/akita/i/hif` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | supervised | multivariate | | [hotsax](./hotsax) | `registry.gitlab.hpi.de/akita/i/hotsax` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [hybrid_knn](./hybrid_knn) | `registry.gitlab.hpi.de/akita/i/hybrid_knn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [if_lof](./if_lof) | `registry.gitlab.hpi.de/akita/i/if_lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [iforest](./iforest) | `registry.gitlab.hpi.de/akita/i/iforest` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [iforest](./iforest) | `registry.gitlab.hpi.de/akita/i/iforest` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [img_embedding_cae](./img_embedding_cae) | `registry.gitlab.hpi.de/akita/i/img_embedding_cae` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | | [kmeans](./kmeans) | `registry.gitlab.hpi.de/akita/i/kmeans` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [knn](./knn) | `registry.gitlab.hpi.de/akita/i/knn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [knn](./knn) | `registry.gitlab.hpi.de/akita/i/knn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [laser_dbn](./laser_dbn) | `registry.gitlab.hpi.de/akita/i/laser_dbn` | Python 3.7 |[`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [left_stampi](./left_stampi) | `registry.gitlab.hpi.de/akita/i/left_stampi` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | -| [lof](./lof) | `registry.gitlab.hpi.de/akita/i/lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [lof](./lof) | `registry.gitlab.hpi.de/akita/i/lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [lstm_ad](./lstm_ad) | `registry.gitlab.hpi.de/akita/i/lstm_ad` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [lstm_vae](./lstm_vae) | `registry.gitlab.hpi.de/akita/i/lstm_vae` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | | [median_method](./median_method) | `registry.gitlab.hpi.de/akita/i/median_method` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | @@ -64,15 +64,15 @@ The namespace prefix (repository) for the built Docker images is `registry.gitla | [mstamp](./mstamp) | `registry.gitlab.hpi.de/akita/i/mstamp` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [mtad_gat](./mtad_gat) | `registry.gitlab.hpi.de/akita/i/mtad_gat` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [multi_hmm](./multi_hmm) | `registry.gitlab.hpi.de/akita/i/multi_hmm` | Python 3.7 |[`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | supervised | multivariate | -| [multi_subsequence_lof](./multi_subsquence_lof) | `registry.gitlab.hpi.de/akita/i/multi_subsequence_lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [mvalmod](./mvalmod) | `registry.gitlab.hpi.de/akita/i/mvalmod` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./0-base-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | multivariate | +| [multi_subsequence_lof](./multi_subsquence_lof) | `registry.gitlab.hpi.de/akita/i/multi_subsequence_lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [mvalmod](./mvalmod) | `registry.gitlab.hpi.de/akita/i/mvalmod` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./1-intermediate-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | multivariate | | [norma](./norma) (_restricted access_) | `registry.gitlab.hpi.de/akita/i/norma` | Python 3.7 |[`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [normalizing_flows](./normalizing_flows) | `registry.gitlab.hpi.de/akita/i/normalizing_flows` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | supervised | multivariate | | [novelty_svr](./novelty_svr) | `registry.gitlab.hpi.de/akita/i/novelty_svr` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [numenta_htm](./numenta_htm) | `registry.gitlab.hpi.de/akita/i/numenta_htm` | Python 2.7 |[`registry.gitlab.hpi.de/akita/i/python2-base`](./0-base-images/python2-base) | unsupervised | univariate | | [ocean_wnn](./ocean_wnn) | `registry.gitlab.hpi.de/akita/i/ocean_wnn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | | [omnianomaly](./omnianomaly) | `registry.gitlab.hpi.de/akita/i/omnianomaly` | Python 3.6 |[`registry.gitlab.hpi.de/akita/i/python36-base`](./0-base-images/python36-base) | semi-supervised | multivariate | -| [pcc](./pcc) | `registry.gitlab.hpi.de/akita/i/pcc` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [pcc](./pcc) | `registry.gitlab.hpi.de/akita/i/pcc` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [pci](./pci) | `registry.gitlab.hpi.de/akita/i/pci` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [phasespace_svm](./phasespace_svm) | `registry.gitlab.hpi.de/akita/i/phasespace_svm` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [pst](./pst) | `registry.gitlab.hpi.de/akita/i/pst` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | | @@ -85,19 +85,19 @@ The namespace prefix (repository) for the built Docker images is `registry.gitla | [sr](./sr) | `registry.gitlab.hpi.de/akita/i/sr` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [sr_cnn](./sr_cnn) | `registry.gitlab.hpi.de/akita/i/sr_cnn` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-base) | semi-supervised | univariate | | [ssa](./ssa) (_restricted access_) | `registry.gitlab.hpi.de/akita/i/ssa` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | -| [stamp](./stamp) | `registry.gitlab.hpi.de/akita/i/stamp` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./0-base-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | -| [stomp](./stomp) | `registry.gitlab.hpi.de/akita/i/stomp` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./0-base-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | +| [stamp](./stamp) | `registry.gitlab.hpi.de/akita/i/stamp` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./1-intermediate-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | +| [stomp](./stomp) | `registry.gitlab.hpi.de/akita/i/stomp` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./1-intermediate-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | | [subsequence_fast_mcd](./subsequence_fast_mcd) | `registry.gitlab.hpi.de/akita/i/subsequence_fast_mcd` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | univariate | -| [subsequence_knn](./subsequence_knn) | `registry.gitlab.hpi.de/akita/i/subsequence_knn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | -| [subsequence_if](./subsequence_if) | `registry.gitlab.hpi.de/akita/i/subsequence_if` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | -| [subsequence_lof](./subsequence_lof) | `registry.gitlab.hpi.de/akita/i/subsequence_lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./0-base-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | +| [subsequence_knn](./subsequence_knn) | `registry.gitlab.hpi.de/akita/i/subsequence_knn` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | +| [subsequence_if](./subsequence_if) | `registry.gitlab.hpi.de/akita/i/subsequence_if` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | +| [subsequence_lof](./subsequence_lof) | `registry.gitlab.hpi.de/akita/i/subsequence_lof` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/pyod`](./1-intermediate-images/pyod) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [tanogan](./tanogan) | `registry.gitlab.hpi.de/akita/i/tanogan` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-torch) -> [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [tarzan](./tarzan) | `registry.gitlab.hpi.de/akita/i/tarzan` | Python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-torch`](./0-base-images/python3-base) | semi-supervised | univariate | | [telemanom](./telemanom) | `registry.gitlab.hpi.de/akita/i/telemanom` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | semi-supervised | multivariate | | [torsk](./torsk) | `registry.gitlab.hpi.de/akita/i/torsk` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | multivariate | | [triple_es](./triple_es) | `registry.gitlab.hpi.de/akita/i/triple_es` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | | [ts_bitmap](./ts_bitmap) | `registry.gitlab.hpi.de/akita/i/ts_bitmap` | python 3.7 | [`registry.gitlab.hpi.de/akita/i/python3-base`](./0-base-images/python3-base) | unsupervised | univariate | -| [valmod](./valmod) | `registry.gitlab.hpi.de/akita/i/valmod` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./0-base-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | +| [valmod](./valmod) | `registry.gitlab.hpi.de/akita/i/valmod` | R 3.5.2 | [`registry.gitlab.hpi.de/akita/i/tsmp`](./1-intermediate-images/tsmp) -> [`registry.gitlab.hpi.de/akita/i/r-base`](./0-base-images/r-base) | unsupervised | univariate | ## Usage @@ -150,9 +150,10 @@ Follow the below steps to test your algorithm using Docker (examples assume that docker tag registry.gitlab.hpi.de/akita/i/python3-base:0.2.5 registry.gitlab.hpi.de/akita/i/python3-base:latest ``` - - build derived base image: + - build intermediate image: ```bash + cd ../1-intermediate-images docker build -t registry.gitlab.hpi.de/akita/i/pyod:0.2.5 ./pyod ``` @@ -174,10 +175,10 @@ Follow the below steps to test your algorithm using Docker (examples assume that If your algorithm is supervised or semi-supervised, execute the following command to perform the training step (_not necessary for LOF_): ```bash - mkdir -p 2-results + mkdir -p results docker run --rm \ - -v $(pwd)/1-data:/data:ro \ - -v $(pwd)/2-results:/results:rw \ + -v $(pwd)/data:/data:ro \ + -v $(pwd)/results:/results:rw \ # -e LOCAL_UID= \ # -e LOCAL_GID= \ registry.gitlab.hpi.de/akita/i/:latest execute-algorithm '{ @@ -190,17 +191,17 @@ Follow the below steps to test your algorithm using Docker (examples assume that }' ``` - Be warned that the result and model files will be written to the `2-results`-directory as the root-user if you do not pass the optional environment variables `LOCAL_UID` and `LOCAL_GID` to the container. + Be warned that the result and model files will be written to the `results`-directory as the root-user if you do not pass the optional environment variables `LOCAL_UID` and `LOCAL_GID` to the container. 4. **Execute your algorithm** Run the following command to perform the execution step of your algorithm: ```bash - mkdir -p 2-results + mkdir -p results TIMEEVAL_ALGORITHM=lof docker run --rm \ - -v $(pwd)/1-data:/data:ro \ - -v $(pwd)/2-results:/results:rw \ + -v $(pwd)/data:/data:ro \ + -v $(pwd)/results:/results:rw \ # -e LOCAL_UID= \ # -e LOCAL_GID= \ registry.gitlab.hpi.de/akita/i/${TIMEEVAL_ALGORITHM}:latest execute-algorithm '{ @@ -213,4 +214,4 @@ Follow the below steps to test your algorithm using Docker (examples assume that }' ``` - Be warned that the result and model files will be written to the `2-results`-directory as the root-user if you do not pass the optional environment variables `LOCAL_UID` and `LOCAL_GID` to the container. + Be warned that the result and model files will be written to the `results`-directory as the root-user if you do not pass the optional environment variables `LOCAL_UID` and `LOCAL_GID` to the container. diff --git a/1-data/dataset.csv b/data/dataset.csv similarity index 100% rename from 1-data/dataset.csv rename to data/dataset.csv diff --git a/1-data/multi-dataset.csv b/data/multi-dataset.csv similarity index 100% rename from 1-data/multi-dataset.csv rename to data/multi-dataset.csv diff --git a/2-results/.gitkeep b/results/.gitkeep similarity index 100% rename from 2-results/.gitkeep rename to results/.gitkeep