diff --git a/.github/actions/release/action.yml b/.github/actions/release/action.yml new file mode 100644 index 00000000..ace21602 --- /dev/null +++ b/.github/actions/release/action.yml @@ -0,0 +1,8 @@ +name: 'Tag or Release' +description: 'tag or release from a given branch' + +runs: + using: "composite" + steps: + - run: ${{ github.action_path }}/tag_or_release.sh + shell: bash \ No newline at end of file diff --git a/.github/actions/release/tag_or_release.sh b/.github/actions/release/tag_or_release.sh new file mode 100755 index 00000000..8ccf0674 --- /dev/null +++ b/.github/actions/release/tag_or_release.sh @@ -0,0 +1,16 @@ +git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" +git config --local user.name "github-actions[bot]" + +if [[ "$tag_or_release" == "tag" ]]; then + git checkout ${source_branch} + git tag -f "${name}" -m "tagged ${source_branch} to ${name} via manual github action" + # will fail if tag already exists; intentional + git push origin ${name} + +elif [[ "$tag_or_release" == "release" ]]; then + echo ${token} | gh auth login --with-token + gh release create ${name} -F changelog.md --target ${source_branch} --title ${name} + +else + echo "bad input" +fi diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 9090bf1b..e61962da 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -7,10 +7,10 @@ jobs: name: run flake8 runs-on: ubuntu-18.04 steps: - - name: set up python 3.8 + - name: set up python 3.7 uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.7 - name: checkout code uses: actions/checkout@v2 @@ -25,10 +25,10 @@ jobs: name: run black runs-on: ubuntu-18.04 steps: - - name: set up python 3.8 + - name: set up python 3.7 uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.7 - name: checkout code uses: actions/checkout@v2 @@ -43,10 +43,10 @@ jobs: name: run bandit runs-on: ubuntu-18.04 steps: - - name: set up python 3.8 + - name: set up python 3.7 uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.7 - name: checkout code uses: actions/checkout@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..089cdc56 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,33 @@ +name: tag-or-release +on: + workflow_dispatch: + inputs: + tag_or_release: + description: 'must be string of either "tag" or "release"' + required: true + default: 'tag' + name: + description: 'the tag or release name, i.e. v1.0.0' + required: true + source_branch: + description: 'the branch to tag or release' + required: true + default: "main" + +jobs: + tag_or_release: + runs-on: ubuntu-latest + name: tag or release the given branch with the given name + steps: + - name: checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: release + id: release + uses: ./.github/actions/release + env: + tag_or_release: "${{ github.event.inputs.tag_or_release }}" + name: "${{ github.event.inputs.name }}" + source_branch: "${{ github.event.inputs.source_branch }}" + token: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file diff --git a/README.md b/README.md index 3f010078..c9bacc43 100644 --- a/README.md +++ b/README.md @@ -308,7 +308,12 @@ These are distinguished as either "retryable" or "not retryable". 3. Job Cancelled - An operator cancelled the job so it should not be retried. -4. Other errors - No automatic rescue +4. Job timeout - The job exceeded it's maximum permitted/modeled compute time. This can be manually + rescued by putting the string 'timeout_scale: 1.25' into a rescue message + which will trigger reprocessing the job with 25% extra time. Any postive floating + point scale should work, included fractional scales < 1.0. + +5. Other errors - No automatic rescue Blackboard @@ -322,23 +327,75 @@ In our current implementation, the blackboard lambda runs on a 7 minute schedule To speed up this sync, we could capture Batch state change events in CloudWatch and send them to lambda for ingestion into a dynamodb, which could then be either hooked up directly to the GUIs, or replicated in a more efficient fashion to the on-prem databases. -Job Memory Model +Job Memory Models ================ Overview -------- -... describe key aspects of the ML here such as features and network layout ... +Pre-trained artificial neural networks are implemented in the pipeline to predict job resource requirements for HST. All three network architectures are built using the Keras functional API from the Tensorflow library. + +1. Memory Classifier +1D Convolutional Neural Network performs multi-class classification on 8 features to predict which of 4 possible "memory bins" is the most appropriate for a given dataset. An estimated probability score is assigned to each of the four possible target classes, i.e. Memory Bins, represented by an integer from 0 to 3. The memory size thresholds are categorized as follow: + + - `0: < 2GB` + - `1: <= 8GB` + - `2: <= 16GB` + - `3: < 64GB` + +2. Memory Regressor +1D-CNN performs logistic regression to estimate how much memory (in Gigabytes) a given dataset will require for processing. This prediction is not used directly by the pipeline because AWS compute doesn't require an exact number (hence the bin classification). We retain this model for the purpose of additional analysis of the datasets and their evolving characteristics. + +3. Wallclock Regressor +1D-CNN performs logistic regression to estimate the job's execution time in wallclock seconds. AWS Batch requires a minimum threshold of 60 seconds to be set on each job, although many jobs take less than one minute to complete. The predicted value from this model is used by JobSubmit to set a maximum execution time in which the job has to be completed, after which a job is killed (regardless of whether or not it has finished). -Job Submission +JobPredict -------------- -Describe model execution, lambda, image, etc. +The JobPredict lambda is invoked by JobSubmit to determine resource allocation needs pertaining to memory and execution time. Upon invocation, a container is created on the fly using a docker image stored in the caldp ECR. The container then loads pre-trained models along with their learned parameters (e.g. weights) from saved keras files. + +The model's inputs are scraped from a text file in the calcloud-processing s3 bucket (`control/ipppssoot/MemoryModelFeatures.txt`) and converted into a numpy array. An additional preprocessing step applies a Yeo-Johnson power transform to the first two indices of the array (`n_files`, `total_mb`) using pre-calculated statistical values (mean, standard deviation and lambdas) representative of the entire training data "population". This transformation restricts all values into a 5-value range (-2 to 3) - see Model Training (below) for more details. + +The resulting 2D-array of transformed inputs are then fed into the models which generate predictions for minimum memory size and wallclock (execution) time requirements. Predicted outputs are formatted into JSON and returned back to the JobSubmit lambda to acquire the compute resources necessary for completing calibration processing on that particular ipppssoot's data. + + +Model Ingest +------------ + +When a job finishes successfully, its status message (in s3) changes to `processed-$ipppssoot.trigger`, and the `model-ingest` lambda is automatically triggered. Similar to JobPredict lambda, the job's inputs/features are scraped from the control file in s3, in addition to the actual measured values for memory usage and wallclock time as recorded in the s3 outputs log files `process_metrics.txt | preview_metrics.txt`. The latter serve as ground truth target class labels for training the model. The features and targets are combined into a python dictionary, which is then formatted into a DynamoDB-compatible json object and ingested into the `calcloud-model` DynamoDB table for inclusion in the next model training iteration. + Model Training -------------- -Describe training, scraping, architecture +Keeping the models performative requires periodic retraining with the latest available data. Unless revisions are otherwise deemed necessary, the overall architecture and tuned hyperparameters of each network are re-built from scratch using the Keras functional API, then trained and validated using all available data. Model training iterations are manually submitted via AWS batch, which fires up a Docker container from the `training` image stored in CALDP elastic container repository (ECR) and runs through the entire training process as a standalone job (separate from the main calcloud processing runs): -Dashboard? ----------- + 1. Download training data from DynamoDB table + 2. Preprocess (calculate statisics and re-run the PowerTransform on `n_files` and `total_mb`) + 3. Build and compile models using Keras Functional API + 4. Split data into train and test (validation) sets + 5. Run batch training for each model + 6. Calculate metrics and scores for evaluation + 7. Save and upload models, training results, and training data CSV backup file to s3 + 8. (optional) Run KFOLD cross-validation (10 splits) + + +Calcloud ML Dashboard +--------------------- + +Analyze model performance, compare training iterations and explore statistical attributes of the continually evolving dataset with an interactive dashboard built specifically for Calcloud's prediction and classification models. The dashboard is maintained in a separate repository which can be found here: [CALCLOUD-ML-DASHBOARD](https://github.com/alphasentaurii/calcloud-ml-dashboard.git). + + +Migrating Data Across Environments +---------------------------------- + +In some cases, there may be a need to migrate existing data from the DynamoDB table of one environment into that of another (e.g. DDB-Test to DDB-Ops, DDB-Ops to DDB-Sandbox, etc). Included in this repo are two helper scripts (located in calcloud/scripts folder)to simplify this process: + + - `scrape_dynamo.py` downloads data from source DDB table and saves to local .csv file + - `import_dynamo.py` ingests data from local .csv file into DDB of destination DDB + +```bash +$ cd calcloud/scripts +$ python dynamo_scrape.py -t $SOURCE_TABLE_NAME -k latest.csv +$ python dynamo_import.py -t $DESTINATION_TABLE_NAME -k latest.csv +``` diff --git a/ami_rotation/ami_rotation_userdata.sh b/ami_rotation/ami_rotation_userdata.sh new file mode 100755 index 00000000..1c5e4e81 --- /dev/null +++ b/ami_rotation/ami_rotation_userdata.sh @@ -0,0 +1,168 @@ +Content-Type: multipart/mixed; boundary="==BOUNDARY==" +MIME-Version: 1.0 + +--==BOUNDARY== +MIME-Version: 1.0 +Content-Type: text/x-shellscript; charset="us-ascii" + +#!/bin/bash -ex +exec &> >(while read line; do echo "$(date +'%Y-%m-%dT%H.%M.%S%z') $line" >> /var/log/user-data.log; done;) +# ensures instance will shutdown even if we don't reach the end +shutdown -h +20 +log_stream="`date +'%Y-%m-%dT%H.%M.%S%z'`" +sleep 5 + +cat << EOF > /home/ec2-user/log_listener.py +import boto3 +import time +import sys +from datetime import datetime + +client = boto3.client('logs') + +log_group = sys.argv[1] +log_stream = sys.argv[2] + +pushed_lines = [] + +while True: + response = client.describe_log_streams( + logGroupName=log_group, + logStreamNamePrefix=log_stream + ) + try: + nextToken = response['logStreams'][0]['uploadSequenceToken'] + except KeyError: + nextToken = None + with open("/var/log/user-data.log", 'r') as f: + lines = f.readlines() + new_lines = [] + for line in lines: + if line in pushed_lines: + continue + timestamp = line.split(" ")[0].strip() + try: + dt = datetime.strptime(timestamp, "%Y-%m-%dT%H.%M.%S%z") + dt_ts = int(dt.timestamp())*1000 #milliseconds + if nextToken is None: + response = client.put_log_events( + logGroupName = log_group, + logStreamName = log_stream, + logEvents = [ + { + 'timestamp': dt_ts, + 'message': line + } + ] + ) + nextToken = response['nextSequenceToken'] + else: + response = client.put_log_events( + logGroupName = log_group, + logStreamName = log_stream, + logEvents = [ + { + 'timestamp': dt_ts, + 'message': line + } + ], + sequenceToken=nextToken + ) + nextToken = response['nextSequenceToken'] + except Exception as e: + # print(e) + continue + + pushed_lines.append(line) + time.sleep(0.21) #AWS throttles at 5 calls/second + time.sleep(2) + +EOF + +echo BEGIN +pwd +date '+%Y-%m-%d %H:%M:%S' + +yum install -y -q gcc libpng-devel libjpeg-devel unzip yum-utils +yum update -y -q && yum upgrade -q +cd /home/ec2-user +curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" +unzip -qq awscliv2.zip +./aws/install --update +curl -s "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "session-manager-plugin.deb" +mkdir /home/ec2-user/.aws +yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo +yum install terraform-0.15.4-1 -y -q +yum install git -y -q +chown -R ec2-user:ec2-user /home/ec2-user/ + +echo "export REQUESTS_CA_BUNDLE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" >> /home/ec2-user/.bashrc +echo "export CURL_CA_BUNDLE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" >> /home/ec2-user/.bashrc +mkdir -p /usr/lib/ssl +mkdir -p /etc/ssl/certs +mkdir -p /etc/pki/ca-trust/extracted/pem +ln -s /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-certificates.crt +ln -s /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /usr/lib/ssl/cert.pem + +yum install python3 -y -q + +sudo -i -u ec2-user bash << EOF +mkdir ~/bin ~/tmp +cd ~/tmp +curl -s -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash +bash ~/.nvm/nvm.sh +source ~/.bashrc +nvm install node +npm config set registry http://registry.npmjs.org/ +npm config set cafile /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem +npm install -g awsudo@1.5.0 +python3 -m pip install -q --upgrade pip && python3 -m pip install boto3 -q +cd ~ +rm -rf ~/tmp +EOF + +chown -R ec2-user:ec2-user /home/ec2-user/ + +echo "export ADMIN_ARN=${admin_arn}" >> /home/ec2-user/.bashrc +echo "export AWS_DEFAULT_REGION=us-east-1" >> /home/ec2-user/.bashrc +echo "export aws_env=${environment}" >> /home/ec2-user/.bashrc + +# get cloudwatch logging going +sudo -i -u ec2-user bash << EOF +cd /home/ec2-user +source .bashrc +aws logs create-log-stream --log-group-name "${log_group}" --log-stream-name $log_stream +python3 /home/ec2-user/log_listener.py "${log_group}" $log_stream & +EOF + +# calcloud checkout, need right tag +cd /home/ec2-user +mkdir ami_rotate && cd ami_rotate +git clone https://github.com/spacetelescope/calcloud.git +cd calcloud +git remote set-url origin DISABLED --push +git fetch +git fetch --all --tags && git checkout tags/v${calcloud_ver} && cd .. +git_exit_status=$? +if [[ $git_exit_status -ne 0 ]]; then + # try without the v + cd calcloud && git fetch --all --tags && git checkout tags/${calcloud_ver} && cd .. + git_exit_status=$? +fi +if [[ $git_exit_status -ne 0 ]]; then + echo "could not checkout ${calcloud_ver}; exiting" + exit 1 +fi + +sudo -i -u ec2-user bash << EOF +cd /home/ec2-user +source .bashrc +cd ami_rotate/calcloud/terraform +./deploy_ami_rotate.sh +EOF + +sleep 120 #let logs catch up + +shutdown -h now + +--==BOUNDARY==-- diff --git a/ami_rotation/parse_image_json.py b/ami_rotation/parse_image_json.py new file mode 100644 index 00000000..82d3d3b1 --- /dev/null +++ b/ami_rotation/parse_image_json.py @@ -0,0 +1,23 @@ +import sys +import json +from collections import OrderedDict +from datetime import datetime + +response = json.loads(str(sys.argv[1])) +images = response["Images"] +image_name_filter = sys.argv[2] + +stsciLinux2Ami = {} +for image in images: + creationDate = image["CreationDate"] + imageId = image["ImageId"] + name = image["Name"] + # Only look at particular AMIs + if name.startswith(image_name_filter): + stsciLinux2Ami.update({creationDate: imageId}) +# Order the list most recent date first +orderedAmi = OrderedDict( + sorted(stsciLinux2Ami.items(), key=lambda x: datetime.strptime(x[0], "%Y-%m-%dT%H:%M:%S.%f%z"), reverse=True) +) +# Print first element in the ordered dict +print(list(orderedAmi.values())[0]) diff --git a/calcloud/exit_codes.py b/calcloud/exit_codes.py index d2b0f084..ba9eef2a 100644 --- a/calcloud/exit_codes.py +++ b/calcloud/exit_codes.py @@ -9,7 +9,8 @@ generic values of 0 or 1 to prevent conflicts with these codes. """ -_MEMORY_ERROR_NAMES = ["SUBPROCESS_MEMORY_ERROR", "CALDP_MEMORY_ERROR", "CONTAINER_MEMORY_ERROR"] + +_MEMORY_ERROR_NAMES = ["SUBPROCESS_MEMORY_ERROR", "CALDP_MEMORY_ERROR", "CONTAINER_MEMORY_ERROR", "OS_MEMORY_ERROR"] _EXIT_CODES = dict( @@ -27,6 +28,7 @@ SUBPROCESS_MEMORY_ERROR=31, # See caldp-process for this CALDP_MEMORY_ERROR=32, CONTAINER_MEMORY_ERROR=33, + OS_MEMORY_ERROR=34, ) @@ -47,6 +49,7 @@ CALDP_MEMORY_ERROR="CALDP generated a Python MemoryError during processing or preview creation.", # This is never directly returned. It's intended to be used to trigger a container memory limit CONTAINER_MEMORY_ERROR="The Batch/ECS container runtime killed the job due to memory limits.", + OS_MEMORY_ERROR="Python raised OSError(Cannot allocate memory...), possibly fork failure.", ) _CODE_TO_NAME = dict() @@ -58,6 +61,8 @@ _CODE_TO_NAME[str(code)] = name assert name in _NAME_EXPLANATIONS +# ----------------------------------------------------------------------------------------------- + def explain(exit_code): """Return the text explanation for the specified `exit_code`. @@ -115,6 +120,9 @@ def is_memory_error(exit_code): return (exit_code in [globals()[name] for name in _MEMORY_ERROR_NAMES]) or (exit_code in _MEMORY_ERROR_NAMES) +# ----------------------------------------------------------------------------------------------- + + def test(): # pragma: no cover from doctest import testmod from . import exit_codes diff --git a/calcloud/io.py b/calcloud/io.py index 4953e2a8..1c5c6788 100644 --- a/calcloud/io.py +++ b/calcloud/io.py @@ -7,9 +7,11 @@ import doctest import json import uuid +import yaml from calcloud import s3 from calcloud import hst +from calcloud import batch from calcloud import log # ------------------------------------------------------------- @@ -237,8 +239,11 @@ def ids(self, prefixes="all"): # ------------------------------------------------------------- -class JsonIo(S3Io): - """Serializes/deserializes objects to JSON when putting/getting from S3.""" +class PayloadIo(S3Io): + """Abstract serializes/deserializes objects when putting/getting from S3.""" + + loader = None + _dumper = None def get(self, prefixes): """Return the decoded message object fetched from literal message name `prefixes` if @@ -247,7 +252,7 @@ def get(self, prefixes): """ if isinstance(prefixes, str): text = super().get(prefixes) - return json.loads(text) + return self.loader(text) else: return {prefix: self.get(prefix) for prefix in prefixes} @@ -264,10 +269,31 @@ def put(self, msgs, payload="", encoding="utf-8"): JsonIo, including handling of `encoding`. """ msgs = self.normalize_put_parameters(msgs, payload) - super().put({msg: json.dumps(value) for (msg, value) in msgs.items()}, encoding=encoding) + super().put({msg: self.dumper(value) for (msg, value) in msgs.items()}, encoding=encoding) + + def dumper(self, value): + """Ensure the empty string is dumped as an empty string, not serialization of empty string.""" + if value != "": + return self._dumper(value) + else: + return "" + + +class JsonIo(PayloadIo): + """Serialize to/from JSON before storing/loading message payloads.""" + + loader = staticmethod(json.loads) + _dumper = staticmethod(json.dumps) + + +class YamlIo(PayloadIo): + """Serialize to/from YAML before storing/loading message payloads.""" + + loader = staticmethod(yaml.safe_load) + _dumper = staticmethod(yaml.dump) -class MessageIo(JsonIo): +class MessageIo(YamlIo): """The MessageIo class provides put/get/list/delete operations for messages of various types used to track the state of dataset processing. @@ -429,11 +455,13 @@ def get_id(self): """Return a unique message ID, nominally for broadcast messages.""" return str(uuid.uuid4()).replace("-", "_") - def broadcast(self, type, ipppssoots): + def broadcast(self, type, ipppssoots, payload=None): """Output a `type` message for each dataset in `ipppssoots`. This is nominally done by sending a list of messages to the broadcast lambda which then sends them using a divide-and-conquer approach. + A yaml-serializable `payload` may also be sent for all messages. + >>> comm = get_io_bundle() Calling the broadcast method writes a single broadcast message containing a payload of messages to send. @@ -443,19 +471,38 @@ def broadcast(self, type, ipppssoots): >>> comm.messages.listl() #doctest: +ELLIPSIS ['broadcast-..._..._..._..._...'] - The contents of a broadcast message is a list of no-payload messages which will later be sent + The contents of a broadcast message is a dictionary defining: + + 1. A list of messages which will be written to S3. + 2. A single optional payload object which is sent for all messages. + by the lambda which processes broadcast messages: >>> comm.messages.pop(msg) - ['cancel-lcw303cjq', 'cancel-lcw304cjq', 'cancel-lcw305cjq'] + {'messages': ['cancel-lcw303cjq', 'cancel-lcw304cjq', 'cancel-lcw305cjq'], 'payload': None} - When the payload of a broadcast message contains large numbers of messages, the message list is + When the messages list a broadcast message contains large numbers of messages, the message list is partitioned into two half-length lists and re-broadcast. - When the payload of a broadcast message is sufficiently small, each message is sent serially and + When the message list is sufficiently small, each message is sent serially and requires ~50-200 msec each. So e.g. 100 serial messages might take 5-20 seconds. + A key purpose of message payloads is to pass override parameters into lambda handlers for messages + such as 'place' or 'rescue': + + >>> comm.messages.put('rescue-lcw303cjq', { "timeout_scale" : 1.25 }) + >>> comm.messages.get('rescue-lcw303cjq') + {'timeout_scale': 1.25} + + While it could be individualized, for simplicity broadcast nominally sends the same payload + to all child messages. + + >>> msg = comm.messages.broadcast("rescue", ['lcw303cjq', 'lcw304cjq', 'lcw305cjq'], {"timeout_scale" : 1.3}) + >>> comm.messages.pop(msg) + {'messages': ['rescue-lcw303cjq', 'rescue-lcw304cjq', 'rescue-lcw305cjq'], 'payload': {'timeout_scale': 1.3}} + >>> comm.messages.delete("all") + """ assert type in MESSAGE_TYPES assert type != "broadcast" # don't broadcast broadcasts.... @@ -464,9 +511,33 @@ def broadcast(self, type, ipppssoots): assert "all" not in ipppssoots # don't broadcast message tails of "all" assert len(ipppssoots) < MAX_BROADCAST_MSGS msg = f"broadcast-{self.get_id()}" - self.put(msg, [f"{type}-{ipst}" for ipst in ipppssoots]) + self.put(msg, dict(messages=[f"{type}-{ipst}" for ipst in ipppssoots], payload=payload)) return msg + def bifurcate_broadcast(self, messages, payload): + """Given the `messages` and object `payload` of a broadcast message, send two new + broadcast messages, each with half the original messages and same payload. + + Returns (broadcast_msg_name1, broadcast_msg_name2) + + >>> comm = get_io_bundle() + + >>> msg1, msg2 = comm.messages.bifurcate_broadcast( + ... ['rescue-lcw303cjq', 'rescue-lcw304cjq', 'rescue-lcw305cjq'], {'timeout_scale' : 1.3}) + + >>> comm.messages.listl() #doctest: +ELLIPSIS + ['broadcast-..._..._..._..._...', 'broadcast-..._..._..._..._...'] + + >>> comm.messages.pop(msg1) + {'messages': ['rescue-lcw303cjq'], 'payload': {'timeout_scale': 1.3}} + >>> comm.messages.pop(msg2) + {'messages': ['rescue-lcw304cjq', 'rescue-lcw305cjq'], 'payload': {'timeout_scale': 1.3}} + """ + msg1, msg2 = f"broadcast-{self.get_id()}", f"broadcast-{self.get_id()}" + self.put(msg1, dict(messages=messages[: len(messages) // 2], payload=payload)) + self.put(msg2, dict(messages=messages[len(messages) // 2 :], payload=payload)) + return msg1, msg2 + def ids(self, message_types="all"): """Given a list of `message_types`, return the list of unique ipppssoots such that each ipppssoot has at least one message @@ -616,6 +687,67 @@ def path(self, ipppssoot): return super().path(prefix) +# Control values can be sent as part of message override payloads or can be recorded in comm.xdata. +# XXXX NOTE: value checks are not currently active, only field name and type. +CONTROL_KEYWORDS = { + "cancel_type": ((str,), lambda x: x in ("job_id", "ipppssoot")), + "job_id": ((str,), batch.JOB_ID_RE.match), + "memory_bin": ((int, type(None)), lambda x: x in (0, 1, 2, 3, None)), + "terminated": ((bool,), lambda x: True), + "timeout_scale": ((int, float), lambda x: x > 0), + "ipppssoot": ((str,), hst.IPPPSSOOT_RE.match), + "bucket": ((str,), lambda x: True), + "job_name": ((str,), lambda x: True), + "exit_code": ((int, str), lambda x: True), + "exit_reason": ((str,), lambda x: True), + "exit_status": ((str,), lambda x: True), + "status_reason": ( + ( + int, + str, + ), + lambda x: True, + ), + "container_reason": ( + ( + int, + str, + ), + lambda x: True, + ), + "memory_retries": ((int,), lambda x: x >= 0), + "retries": ((int,), lambda x: x >= 0), +} + + +def validate_control(metadata): + """Check the `metadata` dictionary for valid keywords and value types.""" + log.info("Validating control metadata", metadata) + if metadata is None: + return {} + if not isinstance(metadata, dict): + raise ValueError("Job metadata isn't a dict.") + for key, value in metadata.items(): + defined = CONTROL_KEYWORDS.get(key) + if defined: + valid_types = defined[0] + if not isinstance(value, valid_types): + raise ValueError(f"Control value for {key} should be one of these types: {valid_types}.") + # f_valid_value = defined[1] + # if not f_valid_value(value): + # raise ValueError(f"Control value for {key} is not valid.") + else: + raise ValueError(f"Control keyword {key} is not one of {sorted(list(CONTROL_KEYWORDS))}.") + return metadata + + +def get_default_metadata(): + """Return the default metadata needed to run the planner if no corresponding overrides or control data + are defined. + """ + return dict(retries=0, memory_retries=0, memory_bin=None, job_id="undefined", terminated=False, timeout_scale=1.0) + + # ------------------------------------------------------------- diff --git a/calcloud/lambda_submit.py b/calcloud/lambda_submit.py index 8c30dfbc..edf30144 100644 --- a/calcloud/lambda_submit.py +++ b/calcloud/lambda_submit.py @@ -17,14 +17,17 @@ from . import plan from . import submit +from . import log +from . import io class CalcloudInputsFailure(RuntimeError): """The inputs needed to plan and run this job were not ready in time.""" -def main(comm, ipppssoot, bucket_name): +def main(comm, ipppssoot, bucket_name, overrides): """Submit the job for `ipppssoot` using `bucket_name` and io bundle `comm`. + Control parameters can be overridden by dictionary `overrides`. 1. Deletes all messages for `ipppssoot`. 2. Creates a metadata file for `ipppssoot` if it doesn't exist already. @@ -39,21 +42,25 @@ def main(comm, ipppssoot, bucket_name): """ try: terminated = comm.messages.listl(f"terminated-{ipppssoot}") - _main(comm, ipppssoot, bucket_name) + _main(comm, ipppssoot, bucket_name, overrides) except Exception as exc: - print(f"Exception in lambda_submit.main for {ipppssoot} = {exc}") + log.error(f"Exception in lambda_submit.main for {ipppssoot} = {exc}") if terminated: - status = "terminated-" + ipppssoot + msg_name = "terminated-" + ipppssoot else: - status = "error-" + ipppssoot + msg_name = "error-" + ipppssoot comm.messages.delete(f"all-{ipppssoot}") - comm.messages.put({status: "submit lambda exception handler " + bucket_name}) + comm.messages.put( + msg_name, payload=dict(where="submit lambda exception handler " + bucket_name, exception=str(exc)) + ) -def _main(comm, ipppssoot, bucket_name): +def _main(comm, ipppssoot, bucket_name, overrides): """Core job submission function factored out of main() to clarify exception handling.""" - wait_for_inputs(comm, ipppssoot) + overrides = io.validate_control(overrides) + + _wait_for_inputs(comm, ipppssoot) comm.messages.delete(f"all-{ipppssoot}") comm.outputs.delete(f"{ipppssoot}") @@ -62,21 +69,23 @@ def _main(comm, ipppssoot, bucket_name): try: metadata = comm.xdata.get(ipppssoot) # retry/rescue path except comm.xdata.client.exceptions.NoSuchKey: - metadata = dict(retries=0, memory_retries=0, job_id=None, terminated=False) + metadata = io.get_default_metadata() + metadata = io.validate_control(metadata) + metadata.update(overrides) # get_plan() raises AllBinsTriedQuit when retries exhaust higher memory job definitions - p = plan.get_plan(ipppssoot, bucket_name, f"{bucket_name}/inputs", metadata["memory_retries"]) + p = plan.get_plan(ipppssoot, bucket_name, f"{bucket_name}/inputs", metadata) # Only reached if get_plan() defines a viable job plan - print("Job Plan:", p) + log.info("Job Plan:", p) response = submit.submit_job(p) - print("Submitted job for", ipppssoot, "as ID", response["jobId"]) + log.info("Submitted job for", ipppssoot, "as ID", response["jobId"]) metadata["job_id"] = response["jobId"] comm.xdata.put(ipppssoot, metadata) comm.messages.put(f"submit-{ipppssoot}") -def wait_for_inputs(comm, ipppssoot): +def _wait_for_inputs(comm, ipppssoot): """Ensure that the inputs required to plan and run the job for `ipppssoot` are available. Each iteration, check for the S3 message files which trigger submissions and abort if none @@ -95,7 +104,7 @@ def wait_for_inputs(comm, ipppssoot): f"Both the 'placed' and 'rescue' messages for {ipppssoot} have been deleted. Aborting input wait and submission." ) if not input_tarball or not memory_modeling: - print( + log.info( f"Waiting for inputs for {ipppssoot} time remaining={seconds_to_fail}. input_tarball={len(input_tarball)} memory_modeling={len(memory_modeling)}" ) time.sleep(poll_seconds) @@ -104,4 +113,4 @@ def wait_for_inputs(comm, ipppssoot): raise CalcloudInputsFailure( f"Wait for inputs for {ipppssoot} timeout, aborting submission. input_tarball={len(input_tarball)} memory_modeling={len(memory_modeling)}" ) - print(f"Inputs for {ipppssoot} found.") + log.info(f"Inputs for {ipppssoot} found.") diff --git a/calcloud/log.py b/calcloud/log.py index 385e624d..b7ababdd 100644 --- a/calcloud/log.py +++ b/calcloud/log.py @@ -66,7 +66,7 @@ class HstdpLogger: - def __init__(self, name="HSTDP", enable_console=True, level=logging.DEBUG, enable_time=True): + def __init__(self, name="HSTDP", enable_console=True, level=logging.DEBUG, enable_time=False): self.name = name self.handlers = [] # logging handlers, used e.g. to add console or file output streams @@ -75,7 +75,7 @@ def __init__(self, name="HSTDP", enable_console=True, level=logging.DEBUG, enabl self.logger = logging.getLogger(name) self.logger.setLevel(level) self.logger.propagate = False - self.formatter = self.set_formatter() + self.formatter = self.set_formatter(enable_time=enable_time) self.console = None if enable_console: self.add_console_handler(level) diff --git a/calcloud/model_ingest.py b/calcloud/model_ingest.py index cc25df33..687bbdc4 100644 --- a/calcloud/model_ingest.py +++ b/calcloud/model_ingest.py @@ -10,8 +10,6 @@ import json from decimal import Decimal from pprint import pprint -from sklearn.preprocessing import PowerTransformer - from . import common s3 = boto3.resource("s3", config=common.retry_config) @@ -64,8 +62,7 @@ def __init__(self, ipst, bucket): def scrape_features(self): self.input_data = self.download_inputs() - self.inputs = self.scrub_keys() - self.features = self.transformer() + self.features = self.scrub_keys() return self.features def download_inputs(self): @@ -81,7 +78,7 @@ def download_inputs(self): body = None print(e) if body is None: - print("Unable to download inputs") + print(f"Unable to download inputs: {self.ipst}") input_data = None sys.exit(3) else: @@ -149,7 +146,7 @@ def scrub_keys(self): elif i[0] == "i": instr = 3 - inputs = { + features = { "n_files": n_files, "total_mb": total_mb, "drizcorr": drizcorr, @@ -160,41 +157,6 @@ def scrub_keys(self): "dtype": dtype, "instr": instr, } - return inputs - - def transformer(self): - """applies yeo-johnson power transform to first two indices of array (n_files, total_mb) using lambdas, mean and standard deviation calculated for each variable prior to model training. - Returns: X inputs as 2D-array for generating predictions - """ - X = self.inputs - n_files = X["n_files"] - total_mb = X["total_mb"] - # apply power transformer normalization to continuous vars - x = np.array([[n_files], [total_mb]]).reshape(1, -1) - pt = PowerTransformer(standardize=False) - # normalization (zero mean, unit variance) - pt.lambdas_ = np.array([-1.05989146, 0.1691683]) - xt = pt.transform(x) - # normalization (zero mean, unit variance) - f_mean, f_sigma = 0.7313458816815209, 0.09209684806404451 - s_mean, s_sigma = 4.18491577280472, 2.4467903663338366 - x_files = np.round(((xt[0, 0] - f_mean) / f_sigma), 5) - x_size = np.round(((xt[0, 1] - s_mean) / s_sigma), 5) - # print(f"Power Transformed variables: {x_files}, {x_size}") - features = { - "x_files": x_files, - "x_size": x_size, - "n_files": n_files, - "total_mb": total_mb, - "drizcorr": X["drizcorr"], - "pctecorr": X["pctecorr"], - "crsplit": X["crsplit"], - "subarray": X["subarray"], - "detector": X["detector"], - "dtype": X["dtype"], - "instr": X["instr"], - } - print("Features:\n ", features) return features @@ -296,8 +258,6 @@ def create_payload(job_data, timestamp): data = { "ipst": ipst, "timestamp": int(timestamp), - "x_files": float(features["x_files"]), - "x_size": float(features["x_size"]), "total_mb": float(features["total_mb"]), "n_files": int(features["n_files"]), "drizcorr": int(features["drizcorr"]), diff --git a/calcloud/plan.py b/calcloud/plan.py index 4a06928b..5089d64e 100644 --- a/calcloud/plan.py +++ b/calcloud/plan.py @@ -14,13 +14,14 @@ from . import hst from . import log -from . import s3 from . import common import json import boto3 +from boto3.dynamodb.conditions import Key client = boto3.client("lambda", config=common.retry_config) +dynamodb = boto3.resource("dynamodb", config=common.retry_config, region_name="us-east-1") # ---------------------------------------------------------------------- @@ -51,33 +52,48 @@ class AllBinsTriedQuit(Exception): # This is the top level entrypoint called from calcloud.lambda_submit.main # It returns a Plan() tuple which is passed to the submit function. -# -# It's the expectation that most/all of this file will be re-written during -# the integration of new memory requirements modelling and new AWS Batch -# infrastructure allocation strategies. The signature of the get_plan() -# function is the main thing to worry about changing externally. -def get_plan(ipppssoot, output_bucket, input_path, memory_retries=0): +def get_plan(ipppssoot, output_bucket, input_path, metadata): """Given the resource requirements for a job, map them onto appropriate requirements and Batch infrastructure needed to process the job. ipppssoot dataset ID to plan output_bucket S3 output bucket, top level input_path - memory_retries increasing counter of retries with 0 being first try, - intended to drive increasing memory for each subsequent retry - with the maximum retry value set in Terraform. + metadata dictionary of parameters sent in message override payloads or + recorded in the control file. Relevant here: + memory_retries increasing counter of retries with 0 being first try, + intended to drive increasing memory for each subsequent retry + with the maximum retry value set in Terraform. + memory_bin absolute memory bin number or None + timeout_scale factor to multiply kill time by Returns Plan (named tuple) """ - job_resources = _get_resources(ipppssoot, output_bucket, input_path) - env = _get_environment(job_resources, memory_retries) + timeout_scale = metadata["timeout_scale"] + memory_retries = metadata["memory_retries"] + memory_bin = metadata["memory_bin"] + job_resources = _get_resources(ipppssoot, output_bucket, input_path, timeout_scale) + env = _get_environment(job_resources, memory_retries, memory_bin) return Plan(*(job_resources + env)) +def query_ddb(ipppssoot): + table_name = os.environ["DDBTABLE"] + table = dynamodb.Table(table_name) + response = table.query(KeyConditionExpression=Key("ipst").eq(ipppssoot)) + db_clock, wc_std = 20 * 60, 5 + if len(response["Items"]) > 0: + data = response["Items"][0] + db_clock = float(data["wallclock"]) + if "wc_std" in data: + wc_std = float(data["wc_std"]) + return db_clock, wc_std + + def invoke_lambda_predict(ipppssoot, output_bucket): - # invoke calcloud-ai lambda + """Invoke calcloud-ai lambda to compute baseline memory bin and kill time.""" bucket = output_bucket.replace("s3://", "") key = f"control/{ipppssoot}/{ipppssoot}_MemModelFeatures.txt" inputParams = {"Bucket": bucket, "Key": key, "Ipppssoot": ipppssoot} @@ -89,10 +105,13 @@ def invoke_lambda_predict(ipppssoot, output_bucket): ) predictions = json.load(response["Payload"]) print(f"Predictions for {ipppssoot}: \n {predictions}") - return predictions + # defaults: db_clock=20 minutes, wc_std=5 + db_clock, wc_std = query_ddb(ipppssoot) + clockTime = predictions["clockTime"] * (1 + wc_std) + return clockTime, db_clock, predictions["memBin"] -def _get_resources(ipppssoot, output_bucket, input_path): +def _get_resources(ipppssoot, output_bucket, input_path, timeout_scale): """Given an HST IPPPSSOOT ID, return information used to schedule it as a batch job. Conceptually resource requirements can be tailored to individual IPPPSSOOTs. @@ -108,24 +127,27 @@ def _get_resources(ipppssoot, output_bucket, input_path): job_name = ipppssoot input_path = input_path crds_config = "caldp-config-aws" - # invoke calcloud-ai lambda - predictions = invoke_lambda_predict(ipppssoot, output_bucket) - initial_bin = predictions["memBin"] # 0 - kill_time = min(max(predictions["clockTime"] * 5, 20 * 60), 48 * 60 * 60) # between 20 minutes and 2 days + # default: predicted time * 6 or * 1+std_err + clockTime, db_clock, initial_bin = invoke_lambda_predict(ipppssoot, output_bucket) + # clip between 20 minutes and 2 days, * timeout_scale + kill_time = int(min(max(clockTime, db_clock), 48 * 60 * 60) * timeout_scale) + # minimum Batch requirement 60 seconds + kill_time = int(max(kill_time, 60)) return JobResources(ipppssoot, instr, job_name, s3_output_uri, input_path, crds_config, initial_bin, kill_time) -def _get_environment(job_resources, memory_retries): - """Based on a resources tuple and a memory_retries counter, determine: +def _get_environment(job_resources, memory_retries, memory_bin): + """Based on a resources tuple and a memory_retries counter or memory_bin, determine: - (queue, job_definition_for_memory, kill seconds) + (queue, job_definition_for_memory, caldp_entrypoint) """ job_defs = os.environ["JOBDEFINITIONS"].split(",") job_queues = os.environ["JOBQUEUES"].split(",") job_resources = JobResources(*job_resources) - final_bin = job_resources.initial_modeled_bin + memory_retries + final_bin = memory_bin if memory_bin is not None else job_resources.initial_modeled_bin + final_bin += memory_retries if final_bin < len(job_defs): log.info( "Selecting resources for", @@ -134,14 +156,24 @@ def _get_environment(job_resources, memory_retries): job_resources.initial_modeled_bin, "Memory retries", memory_retries, + "Memory bin", + memory_bin, "Final bin index", final_bin, ) job_definition = job_defs[final_bin] job_queue = job_queues[final_bin] else: - log.info("No higher memory job definition for", job_resources.ipppssoot, "after", memory_retries) - raise AllBinsTriedQuit("No higher memory job definition for", job_resources.ipppssoot, "after", memory_retries) + msg = ( + "No higher memory job definition for", + job_resources.ipppssoot, + "after", + memory_retries, + "and", + memory_bin, + ) + log.info(*msg) + raise AllBinsTriedQuit(*msg) return JobEnv(job_queue, job_definition, "caldp-process") @@ -159,33 +191,6 @@ def test(): # ---------------------------------------------------------------------- -def _planner(ipppssoots_file, output_bucket=s3.DEFAULT_BUCKET, input_path=s3.DEFAULT_BUCKET, retries=0): - """Given a set of ipppssoots in `ipppssoots_file` separated by spaces or newlines, - as well as an `output_bucket` to define how the jobs are named and - where outputs should be stored, print out the associated batch resources tuples which - can be submitted. - """ - for line in open(ipppssoots_file).readlines(): - if line.strip().startswith("#"): - continue - for ipst in line.split(): - print( - tuple(get_plan(ipst, "s3://" + output_bucket, "s3://" + input_path, retries)) - ) # Drop type to support literal_eval() vs. eval() - - if __name__ == "__main__": - if len(sys.argv) in [2, 3, 4, 5]: - if sys.argv[1] == "test": - print(test()) - else: - # ipppssoots_file = sys.argv[1] # filepath listing ipppssoots to plan - # output_bucket = sys.argv[2] # 's3://calcloud-processing' - # inputs = sys.argv[3] # astroquery: or S3 inputs - # retries = sys.argv[4] # 0..N - _planner(*sys.argv[1:]) - else: - print( - "usage: python -m calcloud.plan [] [input_path] [retry]", - file=sys.stderr, - ) + if sys.argv[1] == "test": + print(test()) diff --git a/calcloud/requirements.txt b/calcloud/requirements.txt new file mode 100644 index 00000000..c3726e8b --- /dev/null +++ b/calcloud/requirements.txt @@ -0,0 +1 @@ +pyyaml diff --git a/changelog.md b/changelog.md new file mode 100644 index 00000000..0ac0b9d7 --- /dev/null +++ b/changelog.md @@ -0,0 +1,8 @@ +- readme updates regarding modeling of job resource requirements +- automated AMI rotation via lambda launching EC2 with user-data that runs terraform +- messages can now contain payloads to override certain job params +- various cert fixes (order of some installations in docker and user-data had to be moved around) +- job predict lambda now uses data from dynamodb for an ipppssoot, if it is present already from a previous processing run +- tensorflow update to 2.6.2 +- various bugfixes for the ML model in the lambda and training (feature params were not guaranteed to be in the same order) +- re-introduced tainting off JobPredict lambda, which uses docker backend, to prevent cached image being used by lambda \ No newline at end of file diff --git a/lambda/AmiRotation/ami_rotation.py b/lambda/AmiRotation/ami_rotation.py new file mode 100644 index 00000000..f56e3498 --- /dev/null +++ b/lambda/AmiRotation/ami_rotation.py @@ -0,0 +1,15 @@ +import os + +import boto3 + +ec2 = boto3.client("ec2") + + +def lambda_handler(event, context): + print(event) + ec2.run_instances( + LaunchTemplate={"LaunchTemplateName": os.environ["LAUNCH_TEMPLATE_NAME"]}, + MinCount=1, + MaxCount=1, + SubnetId=os.environ["SUBNET"], + ) diff --git a/lambda/JobDelete/delete_handler.py b/lambda/JobDelete/delete_handler.py index 99a862ba..36abdf89 100644 --- a/lambda/JobDelete/delete_handler.py +++ b/lambda/JobDelete/delete_handler.py @@ -44,7 +44,7 @@ def lambda_handler(event, context): comm.messages.delete_literal(f"cancel-{job_id}") with log.trap_exception("Handling messages + control for", job_id): ipst = batch.get_job_name(job_id) - print("Handlign messages and control for", ipst) + print("Handling messages and control for", ipst) comm.messages.delete(f"all-{ipst}") comm.messages.put(f"terminated-{ipst}", "cancel lambda " + bucket_name) try: @@ -62,6 +62,7 @@ def lambda_handler(event, context): comm.messages.put(f"terminated-{ipst}", "cancel lambda " + bucket_name) metadata = comm.xdata.get(ipst) metadata["terminated"] = True + metadata["cancel_type"] = "ipppssoot" comm.xdata.put(ipst, metadata) job_id = metadata["job_id"] with log.trap_exception("Terminating", job_id): diff --git a/lambda/JobPredict/Dockerfile b/lambda/JobPredict/Dockerfile index f54cb829..54fcda6c 100644 --- a/lambda/JobPredict/Dockerfile +++ b/lambda/JobPredict/Dockerfile @@ -10,6 +10,6 @@ RUN mkdir -p /etc/ssl/certs && mkdir -p /etc/pki/ca-trust/extracted/pem COPY certs/tls-ca-bundle.pem /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem RUN mv /etc/ssl/certs/ca-bundle.crt /etc/ssl/certs/ca-bundle.crt.org && ln -s /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-bundle.crt && ln -s /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-certificates.crt && mkdir -p /etc/pki/ca-trust/extracted/openssl -RUN python3.7 -m pip install --upgrade pip && python3.7 -m pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.5.0-cp37-cp37m-manylinux2010_x86_64.whl && python3.7 -m pip install -r requirements.txt +RUN python3.7 -m pip install --upgrade pip && python3.7 -m pip install -r requirements.txt && python3.7 -m pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.6.2-cp37-cp37m-manylinux2010_x86_64.whl ADD models ./models/ CMD ["predict_handler.lambda_handler"] diff --git a/lambda/JobPredict/models/mem_clf/keras_metadata.pb b/lambda/JobPredict/models/mem_clf/keras_metadata.pb index 09f144dd..b26eaa2f 100644 --- a/lambda/JobPredict/models/mem_clf/keras_metadata.pb +++ b/lambda/JobPredict/models/mem_clf/keras_metadata.pb @@ -1,12 +1,12 @@ -Iroot"_tf_keras_network*I{"name": "memory_classifier", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "memory_classifier", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "1_dense18", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "2_dense32", "inbound_nodes": [[["1_dense18", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "3_dense64", "inbound_nodes": [[["2_dense32", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "4_dense32", "inbound_nodes": [[["3_dense64", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "5_dense18", "inbound_nodes": [[["4_dense32", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "6_dense9", "inbound_nodes": [[["5_dense18", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "output_mem_clf", "inbound_nodes": [[["6_dense9", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["output_mem_clf", 0, 0]]}, "shared_object_id": 22, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.5.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "memory_classifier", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "1_dense18", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "2_dense32", "inbound_nodes": [[["1_dense18", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "3_dense64", "inbound_nodes": [[["2_dense32", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "4_dense32", "inbound_nodes": [[["3_dense64", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "5_dense18", "inbound_nodes": [[["4_dense32", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "6_dense9", "inbound_nodes": [[["5_dense18", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "output_mem_clf", "inbound_nodes": [[["6_dense9", 0, 0, {}]]], "shared_object_id": 21}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["output_mem_clf", 0, 0]]}}, "training_config": {"loss": "categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "categorical_accuracy"}, "shared_object_id": 24}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 - root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 -root.layer_with_weights-0"_tf_keras_layer*{"name": "1_dense18", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 25}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -root.layer_with_weights-1"_tf_keras_layer*{"name": "2_dense32", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["1_dense18", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 26}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 -root.layer_with_weights-2"_tf_keras_layer*{"name": "3_dense64", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["2_dense32", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 27}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 -root.layer_with_weights-3"_tf_keras_layer*{"name": "4_dense32", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["3_dense64", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 28}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 -root.layer_with_weights-4"_tf_keras_layer*{"name": "5_dense18", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["4_dense32", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 29}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 -root.layer_with_weights-5"_tf_keras_layer*{"name": "6_dense9", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["5_dense18", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 30}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 -root.layer_with_weights-6"_tf_keras_layer*{"name": "output_mem_clf", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["6_dense9", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 31}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -froot.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 32}2 -groot.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "categorical_accuracy"}, "shared_object_id": 24}2 \ No newline at end of file +Kroot"_tf_keras_network*K{"name": "memory_classifier", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "memory_classifier", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "1_dense18", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "2_dense32", "inbound_nodes": [[["1_dense18", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "3_dense64", "inbound_nodes": [[["2_dense32", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "4_dense32", "inbound_nodes": [[["3_dense64", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "5_dense18", "inbound_nodes": [[["4_dense32", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "6_dense9", "inbound_nodes": [[["5_dense18", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "output_mem_clf", "inbound_nodes": [[["6_dense9", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["output_mem_clf", 0, 0]]}, "shared_object_id": 22, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "full_save_spec": {"class_name": "__tuple__", "items": [[{"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}], {}]}, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.6.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "memory_classifier", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "1_dense18", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "2_dense32", "inbound_nodes": [[["1_dense18", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "3_dense64", "inbound_nodes": [[["2_dense32", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "4_dense32", "inbound_nodes": [[["3_dense64", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "5_dense18", "inbound_nodes": [[["4_dense32", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "6_dense9", "inbound_nodes": [[["5_dense18", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "output_mem_clf", "inbound_nodes": [[["6_dense9", 0, 0, {}]]], "shared_object_id": 21}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["output_mem_clf", 0, 0]]}}, "training_config": {"loss": "categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "categorical_accuracy"}, "shared_object_id": 24}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 + root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 +root.layer_with_weights-0"_tf_keras_layer*{"name": "1_dense18", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "1_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 25}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +root.layer_with_weights-1"_tf_keras_layer*{"name": "2_dense32", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "2_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["1_dense18", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 26}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 +root.layer_with_weights-2"_tf_keras_layer*{"name": "3_dense64", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "3_dense64", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["2_dense32", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 27}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 +root.layer_with_weights-3"_tf_keras_layer*{"name": "4_dense32", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "4_dense32", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["3_dense64", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 28}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 +root.layer_with_weights-4"_tf_keras_layer*{"name": "5_dense18", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "5_dense18", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["4_dense32", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 29}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 +root.layer_with_weights-5"_tf_keras_layer*{"name": "6_dense9", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "6_dense9", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["5_dense18", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 30}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 +root.layer_with_weights-6"_tf_keras_layer*{"name": "output_mem_clf", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "output_mem_clf", "trainable": true, "dtype": "float32", "units": 4, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["6_dense9", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 31}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +froot.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 32}2 +groot.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "categorical_accuracy"}, "shared_object_id": 24}2 \ No newline at end of file diff --git a/lambda/JobPredict/models/mem_clf/saved_model.pb b/lambda/JobPredict/models/mem_clf/saved_model.pb index 9c7ad040..6081432a 100644 Binary files a/lambda/JobPredict/models/mem_clf/saved_model.pb and b/lambda/JobPredict/models/mem_clf/saved_model.pb differ diff --git a/lambda/JobPredict/models/mem_clf/variables/variables.data-00000-of-00001 b/lambda/JobPredict/models/mem_clf/variables/variables.data-00000-of-00001 index 807630ec..a9e961d8 100644 Binary files a/lambda/JobPredict/models/mem_clf/variables/variables.data-00000-of-00001 and b/lambda/JobPredict/models/mem_clf/variables/variables.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/mem_clf/variables/variables.index b/lambda/JobPredict/models/mem_clf/variables/variables.index index 2be14c6b..3c4aae28 100644 Binary files a/lambda/JobPredict/models/mem_clf/variables/variables.index and b/lambda/JobPredict/models/mem_clf/variables/variables.index differ diff --git a/lambda/JobPredict/models/mem_clf/weights/ckpt.data-00000-of-00001 b/lambda/JobPredict/models/mem_clf/weights/ckpt.data-00000-of-00001 index 143ae58f..6da98c76 100644 Binary files a/lambda/JobPredict/models/mem_clf/weights/ckpt.data-00000-of-00001 and b/lambda/JobPredict/models/mem_clf/weights/ckpt.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/mem_clf/weights/ckpt.index b/lambda/JobPredict/models/mem_clf/weights/ckpt.index index dedf4c95..fbe4c317 100644 Binary files a/lambda/JobPredict/models/mem_clf/weights/ckpt.index and b/lambda/JobPredict/models/mem_clf/weights/ckpt.index differ diff --git a/lambda/JobPredict/models/mem_reg/keras_metadata.pb b/lambda/JobPredict/models/mem_reg/keras_metadata.pb index cc6bd482..d16e76f0 100644 --- a/lambda/JobPredict/models/mem_reg/keras_metadata.pb +++ b/lambda/JobPredict/models/mem_reg/keras_metadata.pb @@ -1,12 +1,12 @@ -Hroot"_tf_keras_network*H{"name": "memory_regressor", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "memory_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "memory_reg", "inbound_nodes": [[["dense_6", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["memory_reg", 0, 0]]}, "shared_object_id": 22, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.5.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "memory_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "memory_reg", "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["memory_reg", 0, 0]]}}, "training_config": {"loss": "mean_squared_error", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 24}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 - root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 -root.layer_with_weights-0"_tf_keras_layer*{"name": "dense_1", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 25}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -root.layer_with_weights-1"_tf_keras_layer*{"name": "dense_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 26}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 -root.layer_with_weights-2"_tf_keras_layer*{"name": "dense_3", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 27}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 -root.layer_with_weights-3"_tf_keras_layer*{"name": "dense_4", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 28}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 -root.layer_with_weights-4"_tf_keras_layer*{"name": "dense_5", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 29}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 -root.layer_with_weights-5"_tf_keras_layer*{"name": "dense_6", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 30}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 -root.layer_with_weights-6"_tf_keras_layer*{"name": "memory_reg", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 31}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -froot.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 32}2 -groot.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 24}2 \ No newline at end of file +Jroot"_tf_keras_network*J{"name": "memory_regressor", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "memory_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "memory_reg", "inbound_nodes": [[["dense_6", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["memory_reg", 0, 0]]}, "shared_object_id": 22, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "full_save_spec": {"class_name": "__tuple__", "items": [[{"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}], {}]}, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.6.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "memory_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "memory_reg", "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["memory_reg", 0, 0]]}}, "training_config": {"loss": "mean_squared_error", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 24}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 + root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 +root.layer_with_weights-0"_tf_keras_layer*{"name": "dense_1", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 25}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +root.layer_with_weights-1"_tf_keras_layer*{"name": "dense_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 26}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 +root.layer_with_weights-2"_tf_keras_layer*{"name": "dense_3", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 27}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 +root.layer_with_weights-3"_tf_keras_layer*{"name": "dense_4", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 28}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 +root.layer_with_weights-4"_tf_keras_layer*{"name": "dense_5", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 29}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 +root.layer_with_weights-5"_tf_keras_layer*{"name": "dense_6", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 30}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 +root.layer_with_weights-6"_tf_keras_layer*{"name": "memory_reg", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "memory_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 31}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +froot.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 32}2 +groot.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 24}2 \ No newline at end of file diff --git a/lambda/JobPredict/models/mem_reg/saved_model.pb b/lambda/JobPredict/models/mem_reg/saved_model.pb index e70ab9e2..efa31a31 100644 Binary files a/lambda/JobPredict/models/mem_reg/saved_model.pb and b/lambda/JobPredict/models/mem_reg/saved_model.pb differ diff --git a/lambda/JobPredict/models/mem_reg/variables/variables.data-00000-of-00001 b/lambda/JobPredict/models/mem_reg/variables/variables.data-00000-of-00001 index 55093a8f..1b560e12 100644 Binary files a/lambda/JobPredict/models/mem_reg/variables/variables.data-00000-of-00001 and b/lambda/JobPredict/models/mem_reg/variables/variables.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/mem_reg/variables/variables.index b/lambda/JobPredict/models/mem_reg/variables/variables.index index e6c59f02..51a78460 100644 Binary files a/lambda/JobPredict/models/mem_reg/variables/variables.index and b/lambda/JobPredict/models/mem_reg/variables/variables.index differ diff --git a/lambda/JobPredict/models/mem_reg/weights/ckpt.data-00000-of-00001 b/lambda/JobPredict/models/mem_reg/weights/ckpt.data-00000-of-00001 index f6e8462b..d2d66cac 100644 Binary files a/lambda/JobPredict/models/mem_reg/weights/ckpt.data-00000-of-00001 and b/lambda/JobPredict/models/mem_reg/weights/ckpt.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/mem_reg/weights/ckpt.index b/lambda/JobPredict/models/mem_reg/weights/ckpt.index index b9f5dbd7..8aacf187 100644 Binary files a/lambda/JobPredict/models/mem_reg/weights/ckpt.index and b/lambda/JobPredict/models/mem_reg/weights/ckpt.index differ diff --git a/lambda/JobPredict/models/pt_transform b/lambda/JobPredict/models/pt_transform new file mode 100644 index 00000000..ae5cab50 --- /dev/null +++ b/lambda/JobPredict/models/pt_transform @@ -0,0 +1 @@ +{"f_lambda": -1.53012642308238, "s_lambda": -0.08805165507126637, "f_mean": 0.5690156475654576, "f_sigma": 0.04177326202270394, "s_mean": 2.0786578109854394, "s_sigma": 1.2068026984185416} \ No newline at end of file diff --git a/lambda/JobPredict/models/wall_reg/keras_metadata.pb b/lambda/JobPredict/models/wall_reg/keras_metadata.pb index ffbb3f84..4f522965 100644 --- a/lambda/JobPredict/models/wall_reg/keras_metadata.pb +++ b/lambda/JobPredict/models/wall_reg/keras_metadata.pb @@ -1,17 +1,17 @@ -iroot"_tf_keras_network*i{"name": "wallclock_regressor", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "wallclock_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_7", "inbound_nodes": [[["dense_6", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_8", "inbound_nodes": [[["dense_7", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_9", "inbound_nodes": [[["dense_8", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_10", "inbound_nodes": [[["dense_9", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "wallclock_reg", "inbound_nodes": [[["dense_10", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["wallclock_reg", 0, 0]]}, "shared_object_id": 34, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.5.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "wallclock_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_7", "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21}, {"class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 22}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 23}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_8", "inbound_nodes": [[["dense_7", 0, 0, {}]]], "shared_object_id": 24}, {"class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 25}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 26}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_9", "inbound_nodes": [[["dense_8", 0, 0, {}]]], "shared_object_id": 27}, {"class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 28}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 29}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_10", "inbound_nodes": [[["dense_9", 0, 0, {}]]], "shared_object_id": 30}, {"class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 31}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 32}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "wallclock_reg", "inbound_nodes": [[["dense_10", 0, 0, {}]]], "shared_object_id": 33}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["wallclock_reg", 0, 0]]}}, "training_config": {"loss": "mean_squared_error", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 36}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 - root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 -root.layer_with_weights-0"_tf_keras_layer*{"name": "dense_1", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 37}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -root.layer_with_weights-1"_tf_keras_layer*{"name": "dense_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 38}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 -root.layer_with_weights-2"_tf_keras_layer*{"name": "dense_3", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 39}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 -root.layer_with_weights-3"_tf_keras_layer*{"name": "dense_4", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 40}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 -root.layer_with_weights-4"_tf_keras_layer*{"name": "dense_5", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 128}}, "shared_object_id": 41}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 128]}}2 -root.layer_with_weights-5"_tf_keras_layer*{"name": "dense_6", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 256}}, "shared_object_id": 42}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 256]}}2 -root.layer_with_weights-6"_tf_keras_layer*{"name": "dense_7", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 128}}, "shared_object_id": 43}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 128]}}2 - root.layer_with_weights-7"_tf_keras_layer*{"name": "dense_8", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 22}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 23}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_7", 0, 0, {}]]], "shared_object_id": 24, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 44}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 +kroot"_tf_keras_network*k{"name": "wallclock_regressor", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Functional", "config": {"name": "wallclock_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": []}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_7", "inbound_nodes": [[["dense_6", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_8", "inbound_nodes": [[["dense_7", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_9", "inbound_nodes": [[["dense_8", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_10", "inbound_nodes": [[["dense_9", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "wallclock_reg", "inbound_nodes": [[["dense_10", 0, 0, {}]]]}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["wallclock_reg", 0, 0]]}, "shared_object_id": 34, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 9]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}, "is_graph_network": true, "full_save_spec": {"class_name": "__tuple__", "items": [[{"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}], {}]}, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 9]}, "float32", "hst_jobs"]}, "keras_version": "2.6.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "wallclock_regressor", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}, "name": "hst_jobs", "inbound_nodes": [], "shared_object_id": 0}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_1", "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_4", "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_5", "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15}, {"class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_6", "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18}, {"class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_7", "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21}, {"class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 22}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 23}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_8", "inbound_nodes": [[["dense_7", 0, 0, {}]]], "shared_object_id": 24}, {"class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 25}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 26}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_9", "inbound_nodes": [[["dense_8", 0, 0, {}]]], "shared_object_id": 27}, {"class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 28}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 29}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_10", "inbound_nodes": [[["dense_9", 0, 0, {}]]], "shared_object_id": 30}, {"class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 31}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 32}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "wallclock_reg", "inbound_nodes": [[["dense_10", 0, 0, {}]]], "shared_object_id": 33}], "input_layers": [["hst_jobs", 0, 0]], "output_layers": [["wallclock_reg", 0, 0]]}}, "training_config": {"loss": "mean_squared_error", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 36}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}2 + root.layer-0"_tf_keras_input_layer*{"class_name": "InputLayer", "name": "hst_jobs", "dtype": "float32", "sparse": false, "ragged": false, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 9]}, "dtype": "float32", "sparse": false, "ragged": false, "name": "hst_jobs"}}2 +root.layer_with_weights-0"_tf_keras_layer*{"name": "dense_1", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 1}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 2}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["hst_jobs", 0, 0, {}]]], "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 37}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +root.layer_with_weights-1"_tf_keras_layer*{"name": "dense_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_1", 0, 0, {}]]], "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 38}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 +root.layer_with_weights-2"_tf_keras_layer*{"name": "dense_3", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 7}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 8}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_2", 0, 0, {}]]], "shared_object_id": 9, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 39}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 +root.layer_with_weights-3"_tf_keras_layer*{"name": "dense_4", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 10}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 11}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_3", 0, 0, {}]]], "shared_object_id": 12, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 40}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2 +root.layer_with_weights-4"_tf_keras_layer*{"name": "dense_5", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 13}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 14}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_4", 0, 0, {}]]], "shared_object_id": 15, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 128}}, "shared_object_id": 41}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 128]}}2 +root.layer_with_weights-5"_tf_keras_layer*{"name": "dense_6", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_6", "trainable": true, "dtype": "float32", "units": 128, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 16}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 17}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_5", 0, 0, {}]]], "shared_object_id": 18, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 256}}, "shared_object_id": 42}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 256]}}2 +root.layer_with_weights-6"_tf_keras_layer*{"name": "dense_7", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_7", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 19}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 20}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_6", 0, 0, {}]]], "shared_object_id": 21, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 128}}, "shared_object_id": 43}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 128]}}2 + root.layer_with_weights-7"_tf_keras_layer*{"name": "dense_8", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_8", "trainable": true, "dtype": "float32", "units": 32, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 22}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 23}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_7", 0, 0, {}]]], "shared_object_id": 24, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 64}}, "shared_object_id": 44}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 64]}}2  -root.layer_with_weights-8"_tf_keras_layer*{"name": "dense_9", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 25}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 26}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_8", 0, 0, {}]]], "shared_object_id": 27, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 45}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 - root.layer_with_weights-9"_tf_keras_layer*{"name": "dense_10", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 28}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 29}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_9", 0, 0, {}]]], "shared_object_id": 30, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 46}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 - root.layer_with_weights-10"_tf_keras_layer*{"name": "wallclock_reg", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 31}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 32}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_10", 0, 0, {}]]], "shared_object_id": 33, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 47}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 -root.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 48}2 -root.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 36}2 \ No newline at end of file +root.layer_with_weights-8"_tf_keras_layer*{"name": "dense_9", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_9", "trainable": true, "dtype": "float32", "units": 18, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 25}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 26}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_8", 0, 0, {}]]], "shared_object_id": 27, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 32}}, "shared_object_id": 45}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 32]}}2 + root.layer_with_weights-9"_tf_keras_layer*{"name": "dense_10", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_10", "trainable": true, "dtype": "float32", "units": 9, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 28}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 29}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_9", 0, 0, {}]]], "shared_object_id": 30, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 18}}, "shared_object_id": 46}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 18]}}2 + root.layer_with_weights-10"_tf_keras_layer*{"name": "wallclock_reg", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "wallclock_reg", "trainable": true, "dtype": "float32", "units": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 31}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 32}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "inbound_nodes": [[["dense_10", 0, 0, {}]]], "shared_object_id": 33, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 9}}, "shared_object_id": 47}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 9]}}2 +root.keras_api.metrics.0"_tf_keras_metric*{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 48}2 +root.keras_api.metrics.1"_tf_keras_metric*{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "binary_accuracy"}, "shared_object_id": 36}2 \ No newline at end of file diff --git a/lambda/JobPredict/models/wall_reg/saved_model.pb b/lambda/JobPredict/models/wall_reg/saved_model.pb index 9c5ba1b4..a0a1e794 100644 Binary files a/lambda/JobPredict/models/wall_reg/saved_model.pb and b/lambda/JobPredict/models/wall_reg/saved_model.pb differ diff --git a/lambda/JobPredict/models/wall_reg/variables/variables.data-00000-of-00001 b/lambda/JobPredict/models/wall_reg/variables/variables.data-00000-of-00001 index 5d38f466..28f8edf8 100644 Binary files a/lambda/JobPredict/models/wall_reg/variables/variables.data-00000-of-00001 and b/lambda/JobPredict/models/wall_reg/variables/variables.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/wall_reg/variables/variables.index b/lambda/JobPredict/models/wall_reg/variables/variables.index index 45852dcb..1f300114 100644 Binary files a/lambda/JobPredict/models/wall_reg/variables/variables.index and b/lambda/JobPredict/models/wall_reg/variables/variables.index differ diff --git a/lambda/JobPredict/models/wall_reg/weights/ckpt.data-00000-of-00001 b/lambda/JobPredict/models/wall_reg/weights/ckpt.data-00000-of-00001 index 5276412d..e393a368 100644 Binary files a/lambda/JobPredict/models/wall_reg/weights/ckpt.data-00000-of-00001 and b/lambda/JobPredict/models/wall_reg/weights/ckpt.data-00000-of-00001 differ diff --git a/lambda/JobPredict/models/wall_reg/weights/ckpt.index b/lambda/JobPredict/models/wall_reg/weights/ckpt.index index 10d672df..50e768b2 100644 Binary files a/lambda/JobPredict/models/wall_reg/weights/ckpt.index and b/lambda/JobPredict/models/wall_reg/weights/ckpt.index differ diff --git a/lambda/JobPredict/predict_handler.py b/lambda/JobPredict/predict_handler.py index d4a1e830..8d55dec6 100644 --- a/lambda/JobPredict/predict_handler.py +++ b/lambda/JobPredict/predict_handler.py @@ -9,6 +9,7 @@ from sklearn.preprocessing import PowerTransformer import tensorflow as tf from botocore.config import Config +import json # mitigation of potential API rate restrictions (esp for Batch API) retry_config = Config(retries={"max_attempts": 5, "mode": "standard"}) @@ -16,6 +17,12 @@ client = boto3.client("s3", config=retry_config) +def load_pt_data(pt_file): + with open(pt_file, "r") as j: + pt_data = json.load(j) + return pt_data + + def get_model(model_path): """Loads pretrained Keras functional model""" model = tf.keras.models.load_model(model_path) @@ -115,7 +122,7 @@ def scrub_keys(self): inputs = np.array([n_files, total_mb, drizcorr, pctecorr, crsplit, subarray, detector, dtype, instr]) return inputs - def transformer(self): + def transformer(self, pt_data): """applies yeo-johnson power transform to first two indices of array (n_files, total_mb) using lambdas, mean and standard deviation calculated for each variable prior to model training. Returns: X inputs as 2D-array for generating predictions @@ -126,11 +133,14 @@ def transformer(self): # apply power transformer normalization to continuous vars x = np.array([[n_files], [total_mb]]).reshape(1, -1) pt = PowerTransformer(standardize=False) - pt.lambdas_ = np.array([-1.05989146, 0.1691683]) + pt.lambdas_ = np.array([pt_data["f_lambda"], pt_data["s_lambda"]]) + # pt.lambdas_ = np.array([-1.05989146, 0.1691683]) xt = pt.transform(x) # normalization (zero mean, unit variance) - f_mean, f_sigma = 0.7313458816815209, 0.09209684806404451 - s_mean, s_sigma = 4.18491577280472, 2.4467903663338366 + f_mean, f_sigma = pt_data["f_mean"], pt_data["f_sigma"] + s_mean, s_sigma = pt_data["s_mean"], pt_data["s_sigma"] + # f_mean, f_sigma = 0.7313458816815209, 0.09209684806404451 + # s_mean, s_sigma = 4.18491577280472, 2.4467903663338366 x_files = np.round(((xt[0, 0] - f_mean) / f_sigma), 5) x_size = np.round(((xt[0, 1] - s_mean) / s_sigma), 5) X = np.array([x_files, x_size, X[2], X[3], X[4], X[5], X[6], X[7], X[8]]).reshape(1, -1) @@ -159,10 +169,12 @@ def lambda_handler(event, context): wall_reg = get_model("./models/wall_reg/") key = event["Key"] ipppssoot = event["Ipppssoot"] + pt_data = load_pt_data("./models/pt_transform") + print(f"pt_data: {pt_data}") prep = Preprocess(ipppssoot, bucket_name, key) prep.input_data = prep.import_data() prep.inputs = prep.scrub_keys() - X = prep.transformer() + X = prep.transformer(pt_data) # Predict Memory Allocation (bin and value preds) membin, pred_proba = classifier(clf, X) memval = np.round(float(regressor(mem_reg, X)), 2) diff --git a/lambda/JobRescue/rescue_handler.py b/lambda/JobRescue/rescue_handler.py index c8fe3693..06d03147 100644 --- a/lambda/JobRescue/rescue_handler.py +++ b/lambda/JobRescue/rescue_handler.py @@ -22,6 +22,8 @@ def lambda_handler(event, context): comm = io.get_io_bundle(bucket_name) + overrides = comm.messages.get(f"rescue-{ipst}") + if ipst == "all": print("Rescuing all") @@ -29,8 +31,8 @@ def lambda_handler(event, context): rescues = comm.messages.ids(RESCUE_TYPES) - comm.messages.broadcast("rescue", rescues) + comm.messages.broadcast("rescue", rescues, overrides) else: print("Rescuing", ipst) # comm.outputs.delete(ipst) - lambda_submit.main(comm, ipst, bucket_name) + lambda_submit.main(comm, ipst, bucket_name, overrides) diff --git a/lambda/ModelIngest/requirements.txt b/lambda/ModelIngest/requirements.txt index 8d249009..83344a3c 100644 --- a/lambda/ModelIngest/requirements.txt +++ b/lambda/ModelIngest/requirements.txt @@ -1 +1,2 @@ -sklearn==0.0 \ No newline at end of file +numpy +boto3 \ No newline at end of file diff --git a/lambda/batch_events/batch_event_handler.py b/lambda/batch_events/batch_event_handler.py index 34f748c9..ef239203 100644 --- a/lambda/batch_events/batch_event_handler.py +++ b/lambda/batch_events/batch_event_handler.py @@ -93,4 +93,4 @@ def lambda_handler(event, context): print(metadata) comm.xdata.put(ipppssoot, metadata) comm.messages.delete("all-" + ipppssoot) - comm.messages.put({continuation_msg: "batch failure event handler " + bucket}) + comm.messages.put(continuation_msg) diff --git a/lambda/broadcast/broadcast_handler.py b/lambda/broadcast/broadcast_handler.py index fe070fa3..3b2b16d2 100644 --- a/lambda/broadcast/broadcast_handler.py +++ b/lambda/broadcast/broadcast_handler.py @@ -24,18 +24,18 @@ def lambda_handler(event, context): if check_for_kill(comm, "Detected broadcast-kill on entry."): return - broadcasted = comm.messages.pop(f"broadcast-{serial}") + bmsg = comm.messages.pop(f"broadcast-{serial}") - if len(broadcasted) > 100: - serial1, serial2 = comm.messages.get_id(), comm.messages.get_id() - comm.messages.put(f"broadcast-{serial1}", broadcasted[: len(broadcasted) // 2]) - comm.messages.put(f"broadcast-{serial2}", broadcasted[len(broadcasted) // 2 :]) - else: + broadcasted, payload = bmsg["messages"], bmsg["payload"] + + if len(broadcasted) > 100: # split broadcast into two new broadcasts + comm.messages.bifurcate_broadcast(broadcasted, payload) + else: # iteratively send payload to each message in broadcasted for i, msg in enumerate(broadcasted): if not i % 10: if check_for_kill(comm, "Detected broadcast-kill in put loop"): return - comm.messages.put(msg) + comm.messages.put(msg, payload) def check_for_kill(comm, message): diff --git a/lambda/s3_trigger/s3_trigger_handler.py b/lambda/s3_trigger/s3_trigger_handler.py index d98becfa..81109a42 100644 --- a/lambda/s3_trigger/s3_trigger_handler.py +++ b/lambda/s3_trigger/s3_trigger_handler.py @@ -9,8 +9,10 @@ def lambda_handler(event, context): comm = io.get_io_bundle(bucket_name) + overrides = comm.messages.get(f"placed-{ipst}") + comm.xdata.delete(ipst) # biggest difference between "placed" and "rescue" # comm.messages.delete(f"placed-{ipst}") - lambda_submit.main(comm, ipst, bucket_name) + lambda_submit.main(comm, ipst, bucket_name, overrides) diff --git a/modeling/io.py b/modeling/io.py index 57209ff7..9d111aad 100644 --- a/modeling/io.py +++ b/modeling/io.py @@ -8,6 +8,7 @@ import zipfile from boto3.dynamodb.conditions import Attr import pickle +from decimal import Decimal # mitigation of potential API rate restrictions (esp for Batch API) retry_config = Config(retries={"max_attempts": 5}) @@ -173,6 +174,12 @@ def save_dict(data_dict, df_key=None): return keys +def save_json(data, name): + with open(name, "w") as fp: + json.dump(data, fp) + print(f"\nJSON file saved:\n {os.path.abspath(name)}") + + def save_dataframe(df, df_key): df["ipst"] = df.index df.to_csv(df_key, index=False) @@ -239,3 +246,50 @@ def zip_models(path_to_models, zipname="models.zip"): for file in file_paths: zip_ref.write(file) print(file) + + +def format_row_item(row): + row["timestamp"] = int(row["timestamp"]) + row["x_files"] = float(row["x_files"]) + row["x_size"] = float(row["x_size"]) + row["bin_pred"] = float(row["bin_pred"]) + row["mem_pred"] = float(row["mem_pred"]) + row["wall_pred"] = float(row["wall_pred"]) + row["wc_mean"] = float(row["wc_mean"]) + row["wc_std"] = float(row["wc_std"]) + row["wc_err"] = float(row["wc_err"]) + return json.loads(json.dumps(row, allow_nan=True), parse_int=Decimal, parse_float=Decimal) + + +def write_to_dynamo(rows, table_name): + try: + table = dynamodb.Table(table_name) + except Exception as e: + print("Error loading DynamoDB table. Check if table was created correctly and environment variable.") + print(e) + try: + with table.batch_writer() as batch: + for i in range(len(rows)): + batch.put_item(Item=rows[i]) + except Exception as e: + print("Error executing batch_writer") + print(e) + + +def batch_ddb_writer(key, table_name): + input_file = csv.DictReader(open(key)) + + batch_size = 100 + batch = [] + + for row in input_file: + item = format_row_item(row) + + if len(batch) >= batch_size: + write_to_dynamo(batch, table_name) + batch.clear() + + batch.append(item) + if batch: + write_to_dynamo(batch, table_name) + return {"statusCode": 200, "body": json.dumps("Uploaded to DynamoDB Table")} diff --git a/modeling/main.py b/modeling/main.py index 70ca45bb..feace580 100644 --- a/modeling/main.py +++ b/modeling/main.py @@ -1,5 +1,6 @@ import sys import os +import shutil from . import io from . import prep from . import train @@ -60,21 +61,25 @@ def get_training_config(args): else: attr = None # load training data - data_path = io.get_paths(timestamp) - home = os.path.join(os.getcwd(), data_path) - prefix = f"{data_path}/data" - os.makedirs(prefix, exist_ok=True) - os.chdir(prefix) + prefix = io.get_paths(timestamp) + home = os.path.join(os.getcwd(), prefix) + os.makedirs(f"{prefix}/data", exist_ok=True) + os.chdir(f"{prefix}/data") df = prep.preprocess(bucket_mod, prefix, src, table_name, attr) os.chdir(home) if cross_val == "only": # run_kfold, skip training - validate.run_kfold(df, bucket_mod, data_path, models, verbose, n_jobs) + validate.run_kfold(df, bucket_mod, prefix, models, verbose, n_jobs) else: - train.train_models(df, bucket_mod, data_path, opt, models, verbose) + df_new = train.train_models(df, bucket_mod, prefix, opt, models, verbose) + io.save_dataframe(df_new, "latest.csv") + io.s3_upload(["latest.csv"], bucket_mod, f"{prefix}/data") + shutil.copy("data/pt_transform", "./models/pt_transform") io.zip_models("./models", zipname="models.zip") - io.s3_upload(["models.zip"], bucket_mod, f"{data_path}/models") + io.s3_upload(["models.zip"], bucket_mod, f"{prefix}/models") + io.batch_ddb_writer("latest.csv", table_name) + if cross_val == "skip": print("Skipping KFOLD") else: - validate.run_kfold(df, bucket_mod, data_path, models, verbose, n_jobs) + validate.run_kfold(df, bucket_mod, prefix, models, verbose, n_jobs) diff --git a/modeling/prep.py b/modeling/prep.py index 405d5a1d..4a952233 100644 --- a/modeling/prep.py +++ b/modeling/prep.py @@ -116,7 +116,15 @@ def update_power_transform(df): df_norm = pd.DataFrame(normalized, index=idx, columns=["x_files", "x_size"]) df["x_files"] = df_norm["x_files"] df["x_size"] = df_norm["x_size"] - pt_transform = {"lambdas": pt.lambdas_, "f_mean": f_mean, "f_sigma": f_sigma, "s_mean": s_mean, "s_sigma": s_sigma} + lambdas = pt.lambdas_ + pt_transform = { + "f_lambda": lambdas[0], + "s_lambda": lambdas[1], + "f_mean": f_mean, + "f_sigma": f_sigma, + "s_mean": s_mean, + "s_sigma": s_sigma, + } print(pt_transform) return df, pt_transform @@ -130,9 +138,8 @@ def preprocess(bucket_mod, prefix, src, table_name, attr): # update power transform df, pt_transform = update_power_transform(df) io.save_dataframe(df, "latest.csv") - data_dict = {"pt_transform": pt_transform} - keys = io.save_to_pickle(data_dict, target_col=None, df_key="latest.csv") - io.s3_upload(keys, bucket_mod, prefix) + io.save_json(pt_transform, "pt_transform") + io.s3_upload(["pt_transform", "latest.csv"], bucket_mod, f"{prefix}/data") return df @@ -160,24 +167,15 @@ def make_tensors(X_train, y_train, X_test, y_test): return X_train, y_train, X_test, y_test -def split_Xy(df, target_col): +def split_Xy(df, target_col, keep_index=False): targets = df[target_col] - cols = [ - "n_files", - "total_mb", - "wallclock", - "memory", - "mem_bin", - "mem_pred", - "bin_pred", - "wall_pred", - "ipst", - "timestamp", - ] - drop_cols = [col for col in cols if col in df.columns] - features = df.drop(columns=drop_cols, axis=1, inplace=False) - X = features.values - y = targets.values + input_cols = ["x_files", "x_size", "drizcorr", "pctecorr", "crsplit", "subarray", "detector", "dtype", "instr"] + features = df[input_cols] + if keep_index is False: + X = features.values + y = targets.values + else: + X, y = features, targets return X, y diff --git a/modeling/requirements.txt b/modeling/requirements.txt index ffa514f7..1fb22bb6 100644 --- a/modeling/requirements.txt +++ b/modeling/requirements.txt @@ -1,4 +1,4 @@ -tensorflow==2.5.0 +tensorflow==2.6.2 sklearn==0.0 boto3==1.17.79 -pandas==1.2.4 +pandas==1.2.4 \ No newline at end of file diff --git a/modeling/train.py b/modeling/train.py index f251c9db..bcef345b 100644 --- a/modeling/train.py +++ b/modeling/train.py @@ -187,7 +187,6 @@ def predict_reg(model, X_train, y_train, X_test, y_test): # RMSE Computation rmse_test = np.sqrt(MSE(y_test, y_pred)) print("RMSE Test : % f" % (rmse_test)) - # train_preds = np.concatenate((y_pred.reshape(len(y_pred), 1), y_test.reshape(len(y_test), 1)), 1) np.set_printoptions(precision=2) preds = np.concatenate((y_pred.reshape(len(y_pred), 1), y_test.reshape(len(y_test), 1)), 1) return preds @@ -283,6 +282,11 @@ def train_memory_classifier(df, clf, bucket_mod, data_path, verbose): # zip and upload trained model to s3 io.zip_models("./models/mem_clf", zipname="mem_clf.zip") io.s3_upload(["mem_clf.zip"], bucket_mod, f"{data_path}/models") + X, _ = prep.split_Xy(df, target_col, keep_index=True) + y_proba = clf.predict(X) + y_pred = np.argmax(y_proba, axis=-1) + bin_preds = pd.DataFrame(y_pred, index=X.index, columns=["bin_pred"]) + return bin_preds def train_memory_regressor(df, mem_reg, bucket_mod, data_path, verbose): @@ -296,6 +300,10 @@ def train_memory_regressor(df, mem_reg, bucket_mod, data_path, verbose): # zip and upload trained model to s3 io.zip_models("./models/mem_reg", zipname="mem_reg.zip") io.s3_upload(["mem_reg.zip"], bucket_mod, f"{data_path}/models") + X, _ = prep.split_Xy(df, target_col, keep_index=True) + y_pred = mem_reg.predict(X) + mem_preds = pd.DataFrame(y_pred, index=X.index, columns=["mem_pred"]) + return mem_preds def train_wallclock_regressor(df, wall_reg, bucket_mod, data_path, verbose): @@ -309,9 +317,36 @@ def train_wallclock_regressor(df, wall_reg, bucket_mod, data_path, verbose): # zip and upload trained model to s3 io.zip_models("./models/wall_reg", zipname="wall_reg.zip") io.s3_upload(["wall_reg.zip"], bucket_mod, f"{data_path}/models") + X, _ = prep.split_Xy(df, target_col, keep_index=True) + y_pred = wall_reg.predict(X) + wall_preds = pd.DataFrame(y_pred, index=X.index, columns=["wall_pred"]) + return wall_preds + + +def wallclock_stats(df): + wc_dict = {} + wc_stats = {} + wc_preds = list(df["wall_pred"].unique()) + for p in wc_preds: + wc_dict[p] = {} + wall = df.loc[df.wall_pred == p]["wallclock"] + std = np.std(wall) + wc_dict[p]["wc_mean"] = np.mean(wall) + wc_dict[p]["wc_std"] = std + wc_dict[p]["wc_err"] = std / np.sqrt(len(wall)) + for idx, row in df.iterrows(): + wc_stats[idx] = {} + wp = row["wall_pred"] + if wp in wc_dict: + wc_stats[idx]["wc_mean"] = wc_dict[wp]["wc_mean"] + wc_stats[idx]["wc_std"] = wc_dict[wp]["wc_std"] + wc_stats[idx]["wc_err"] = wc_dict[wp]["wc_err"] + df_stats = pd.DataFrame.from_dict(wc_stats, orient="index") + return df_stats def train_models(df, bucket_mod, data_path, opt, models, verbose): + preds = {} if opt == "update": clf, mem_reg, wall_reg = get_latest_models(bucket_mod) else: @@ -323,4 +358,12 @@ def train_models(df, bucket_mod, data_path, opt, models, verbose): } for target in models: M = pipeline[target]["model"] - pipeline[target]["function"].__call__(df, M, bucket_mod, data_path, verbose) + preds[target] = pipeline[target]["function"].__call__(df, M, bucket_mod, data_path, verbose) + + cols = ["bin_pred", "mem_pred", "wall_pred", "wc_mean", "wc_std", "wc_err"] + drop_cols = [col for col in cols if col in df.columns] + df = df.drop(drop_cols, axis=1) + df_preds = pd.concat([df, preds["mem_bin"], preds["memory"], preds["wallclock"]], axis=1) + df_stats = wallclock_stats(df_preds) + df_new = df_preds.join(df_stats, how="left") + return df_new diff --git a/scripts/check_batch_jobs.py b/scripts/check_batch_jobs.py index 63b04fc3..3fb78e64 100755 --- a/scripts/check_batch_jobs.py +++ b/scripts/check_batch_jobs.py @@ -1,6 +1,6 @@ #! /usr/bin/python3 -# the deploy_ami_rotate.sh script calls this script, +# the deploy_ami_rotate.sh script calls this script, # and stops ami rotation before calling terraform # if this script exits non-zero @@ -8,25 +8,25 @@ import json import sys -statuses = ['RUNNING','SUBMITTED','PENDING','RUNNABLE','STARTING'] +statuses = ["RUNNING", "SUBMITTED", "PENDING", "RUNNABLE", "STARTING"] # clean up before running -cmd = 'rm ./*.json' +cmd = "rm ./*.json" os.system(cmd) # dump the jobQueues to json cmd = "awsudo $ADMIN_ARN aws batch describe-job-queues > queues.json" os.system(cmd) -with open('./queues.json', 'r') as f: +with open("./queues.json", "r") as f: queues = json.load(f) -for queue in queues['jobQueues']: - name = queue['jobQueueName'] +for queue in queues["jobQueues"]: + name = queue["jobQueueName"] for status in statuses: cmd = f"awsudo $ADMIN_ARN aws batch list-jobs --job-queue {name} --job-status {status} > {name}_{status}.json" os.system(cmd) - with open(f"{name}_{status}.json", 'r') as f: + with open(f"{name}_{status}.json", "r") as f: jobs = json.load(f) - if len(jobs['jobSummaryList']) > 0: - sys.exit(1) \ No newline at end of file + if len(jobs["jobSummaryList"]) > 0: + sys.exit(1) diff --git a/scripts/dynamo_import.py b/scripts/dynamo_import.py new file mode 100644 index 00000000..06e808f3 --- /dev/null +++ b/scripts/dynamo_import.py @@ -0,0 +1,89 @@ +import json +import boto3 +import argparse +import csv +from decimal import Decimal +import sys + +s3 = boto3.resource("s3") +dynamodb = boto3.resource("dynamodb", region_name="us-east-1") + + +def format_row_item(row): + row["timestamp"] = int(row["timestamp"]) + row["x_files"] = float(row["x_files"]) + row["x_size"] = float(row["x_size"]) + row["drizcorr"] = int(row["drizcorr"]) + row["pctecorr"] = int(row["pctecorr"]) + row["crsplit"] = int(row["crsplit"]) + row["subarray"] = int(row["subarray"]) + row["detector"] = int(row["detector"]) + row["dtype"] = int(row["dtype"]) + row["instr"] = int(row["instr"]) + row["wallclock"] = float(row["wallclock"]) + row["memory"] = float(row["memory"]) + row["mem_bin"] = float(row["mem_bin"]) + row["n_files"] = float(row["n_files"]) + row["total_mb"] = float(row["total_mb"]) + row["bin_pred"] = float(row["bin_pred"]) + row["mem_pred"] = float(row["mem_pred"]) + row["wall_pred"] = float(row["wall_pred"]) + row["wc_mean"] = float(row["wc_mean"]) + row["wc_std"] = float(row["wc_std"]) + row["wc_err"] = float(row["wc_err"]) + return json.loads(json.dumps(row, allow_nan=True), parse_int=Decimal, parse_float=Decimal) + + +def write_to_dynamo(rows, table_name): + try: + table = dynamodb.Table(table_name) + except Exception as e: + print("Error loading DynamoDB table. Check if table was created correctly and environment variable.") + print(e) + try: + with table.batch_writer() as batch: + for i in range(len(rows)): + batch.put_item(Item=rows[i]) + except: + import traceback + + traceback.print_exc() + sys.exit() + + +def main(key, table_name): + input_file = csv.DictReader(open(key)) + batch_size = 100 + batch = [] + + for row in input_file: + try: + item = format_row_item(row) + except Exception as e: + import traceback + + traceback.print_exc() + print(e) + print(row) + import sys + + sys.exit() + if len(batch) >= batch_size: + write_to_dynamo(batch, table_name) + batch.clear() + print("Batch uploaded.") + + batch.append(item) + if batch: + write_to_dynamo(batch, table_name) + return {"statusCode": 200, "body": json.dumps("Uploaded to DynamoDB Table")} + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--table", type=str, default="calcloud-model-sb", help="ddb table") + parser.add_argument("-k", "--key", type=str, default="latest.csv", help="local csv filepath") + args = parser.parse_args() + table_name = args.table + key = args.key + main(key, table_name) diff --git a/scripts/dynamo_scrape.py b/scripts/dynamo_scrape.py new file mode 100644 index 00000000..43983d4b --- /dev/null +++ b/scripts/dynamo_scrape.py @@ -0,0 +1,66 @@ +import argparse +import boto3 +from botocore.config import Config +import csv + +# mitigation of potential API rate restrictions (esp for Batch API) +retry_config = Config(retries={"max_attempts": 5}) +client = boto3.client("s3", config=retry_config) +dynamodb = boto3.resource("dynamodb", config=retry_config, region_name="us-east-1") + + +def get_keys(items): + keys = set([]) + for item in items: + keys = keys.union(set(item.keys())) + return keys + + +def ddb_download(table_name): + """retrieves data from dynamodb + Args: + table_name: dynamodb table name + p_key: (default is 'ipst') primary key in dynamodb table + attr: (optional) retrieve a subset using an attribute dictionary + If attr is none, returns all items in database. + """ + table = dynamodb.Table(table_name) + key_set = ["ipst"] # primary key + raw_data = table.scan() + if raw_data is None: + return None + items = raw_data["Items"] + fieldnames = set([]).union(get_keys(items)) + + while raw_data.get("LastEvaluatedKey"): + raw_data = table.scan(ExclusiveStartKey=raw_data["LastEvaluatedKey"]) + items.extend(raw_data["Items"]) + fieldnames - fieldnames.union(get_keys(items)) + + print("\nTotal downloaded records: {}".format(len(items))) + for f in fieldnames: + if f not in key_set: + key_set.append(f) + ddb_data = {"items": items, "keys": key_set} + return ddb_data + + +def write_to_csv(ddb_data, filename=None): + if filename is None: + filename = "batch.csv" + with open(filename, "w") as csvfile: + writer = csv.DictWriter(csvfile, delimiter=",", fieldnames=ddb_data["keys"], quotechar='"') + writer.writeheader() + writer.writerows(ddb_data["items"]) + print(f"DDB data saved to: {filename}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--table", default="calcloud-model-ops", help="ddb table", type=str) + parser.add_argument("-k", "--key", default="latest.csv", help="output csv filename", type=str) + args = parser.parse_args() + table_name = args.table + key = args.key + ddb_data = ddb_download(table_name) + write_to_csv(ddb_data, key) diff --git a/setup.cfg b/setup.cfg index b176f5e2..73c84fcf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,20 +13,20 @@ github_project = spacetelescope/calcloud [options] packages = find: -python_requires = >=3.8 +python_requires = ~=3.7.0 setup_requires = setuptools >=41.0.1 install_requires = - boxsdk[jwt] >=2.5.0, <3 boto3 + pyyaml [options.extras_require] dev = - black ==20.8b1 + black flake8 - pytest >=5.0.1, <6 - pytest-cov >= 2.7.1, <3 - tox >=3.13.2, <4 + pytest + pytest-cov + tox bandit [flake8] diff --git a/terraform/ami-rotation.tf b/terraform/ami-rotation.tf new file mode 100644 index 00000000..4bcc1927 --- /dev/null +++ b/terraform/ami-rotation.tf @@ -0,0 +1,128 @@ +data "template_file" "ami_rotation_userdata" { + template = file("${path.module}/../ami_rotation/ami_rotation_userdata.sh") + vars = { + environment = var.environment, + admin_arn = nonsensitive(data.aws_ssm_parameter.admin_arn.value), + calcloud_ver = var.awsysver, + log_group = aws_cloudwatch_log_group.ami-rotation.name + } +} + +resource "aws_launch_template" "ami_rotation" { + name = "calcloud-ami-rotation${local.environment}" + description = "launch template for running ami rotation via terraform" + ebs_optimized = "false" + image_id = nonsensitive(aws_ssm_parameter.ci_ami.value) + update_default_version = true + tags = { + "Name" = "calcloud-ami-rotation${local.environment}" + } + user_data = base64encode(data.template_file.ami_rotation_userdata.rendered) + + vpc_security_group_ids = local.batch_sgs + instance_type = "t3.large" + instance_initiated_shutdown_behavior = "terminate" + + block_device_mappings { + device_name = "/dev/xvda" + + + ebs { + # see the aws batch launch template for some comments about valid ebs construction + delete_on_termination = "true" + encrypted = "true" + # must be >= 30 gb due to size of the base AMI created by IT + volume_size = 30 + volume_type = "gp2" + } + } + iam_instance_profile { + arn = nonsensitive(data.aws_ssm_parameter.ci_instance_role.value) + } + monitoring { + enabled = true + } + + tag_specifications { + resource_type = "instance" + tags = { + "Name" = "calcloud-ami-rotation${local.environment}" + } + } + + tag_specifications { + resource_type = "volume" + tags = { + "Name" = "calcloud-ami-rotation${local.environment}" + } + } +} + +module "calcloud_env_amiRotation" { + source = "terraform-aws-modules/lambda/aws" + version = "~> 1.43.0" + + function_name = "calcloud-env-AmiRotation${local.environment}" + description = "spawns an ec2 bi-weekly which rotates the ami for batch" + # the path is relative to the path inside the lambda env, not in the local filesystem. + handler = "ami_rotation.lambda_handler" + runtime = "python3.7" + publish = false + timeout = 60 + cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days + + source_path = [ + { + # this is the lambda itself. The code in path will be placed directly into the lambda execution path + path = "${path.module}/../lambda/AmiRotation" + pip_requirements = false + } + ] + + store_on_s3 = true + s3_bucket = aws_s3_bucket.calcloud_lambda_envs.id + + # ensures that terraform doesn't try to mess with IAM + create_role = false + attach_cloudwatch_logs_policy = false + attach_dead_letter_policy = false + attach_network_policy = false + attach_tracing_policy = false + attach_async_event_policy = false + + lambda_role = nonsensitive(data.aws_ssm_parameter.lambda_amiRotate_role.value) + + environment_variables = merge(local.common_env_vars, { + LAUNCH_TEMPLATE_NAME=aws_launch_template.ami_rotation.name, + SUBNET = local.batch_subnet_ids[0] + }) + + tags = { + Name = "calcloud-env-AmiRotation${local.environment}" + } +} + +resource "aws_cloudwatch_log_group" "ami-rotation" { + name = "/tf/ec2/ami-rotation${local.environment}" + retention_in_days = local.lambda_log_retention_in_days +} + +resource "aws_cloudwatch_event_rule" "ami-rotate-scheduler" { + name = "ami-rotate-scheduler${local.environment}" + description = "scheduler for ami rotation" + schedule_expression = "cron(0 8 ? * TUE,FRI *)" +} + +resource "aws_cloudwatch_event_target" "ami-rotate-scheduler" { + rule = aws_cloudwatch_event_rule.ami-rotate-scheduler.name + target_id = "lambda" + arn = module.calcloud_env_amiRotation.this_lambda_function_arn +} + +resource "aws_lambda_permission" "allow_lambda_exec_ami_rotate" { + statement_id = "AllowExecutionFromCloudWatch" + action = "lambda:InvokeFunction" + function_name = module.calcloud_env_amiRotation.this_lambda_function_name + principal = "events.amazonaws.com" + source_arn = aws_cloudwatch_event_rule.ami-rotate-scheduler.arn +} diff --git a/terraform/batch.tf b/terraform/batch.tf index c071bee6..e87c83a1 100644 --- a/terraform/batch.tf +++ b/terraform/batch.tf @@ -52,7 +52,7 @@ resource "aws_launch_template" "hstdp" { name = "calcloud-hst-worker${local.environment}" description = "Template for cluster worker nodes updated to limit stopped container lifespan" ebs_optimized = "false" - image_id = nonsensitive(data.aws_ssm_parameter.batch_ami_id.value) + image_id = nonsensitive(aws_ssm_parameter.ecs_ami.value) update_default_version = true tags = { "Name" = "calcloud-hst-worker${local.environment}" diff --git a/terraform/deploy.sh b/terraform/deploy.sh index a902e0e2..726f9e03 100755 --- a/terraform/deploy.sh +++ b/terraform/deploy.sh @@ -3,9 +3,9 @@ # ADMIN_ARN is set in the ci node env and should not be included in this deploy script # variables that will likely be changed frequently -CALCLOUD_VER="0.4.29" -CALDP_VER="0.2.14" -CAL_BASE_IMAGE="stsci/hst-pipeline:CALDP_20210827_CAL_final" +CALCLOUD_VER="v0.4.30" +CALDP_VER="v0.2.15" +CAL_BASE_IMAGE="stsci/hst-pipeline:CALDP_20211119_CAL_final" # this is the tag that the image will have in AWS ECR CALDP_IMAGE_TAG="latest" @@ -37,11 +37,21 @@ then cd $TMP_INSTALL_DIR git clone https://github.com/spacetelescope/calcloud.git cd calcloud && git fetch --all --tags && git checkout tags/v${CALCLOUD_VER} && cd .. + git_exit_status=$? + if [[ $git_exit_status -ne 0 ]]; then + # try without the v + cd calcloud && git fetch --all --tags && git checkout tags/${CALCLOUD_VER} && cd .. + git_exit_status=$? + fi + if [[ $git_exit_status -ne 0 ]]; then + echo "could not checkout ${CALCLOUD_VER}; exiting" + exit 1 + fi fi # setting up the caldp source dir if it needs downloaded # equivalent to "if len($var) == 0" -if [ -z "${CALDP_BUILD_DIR}"] +if [ -z "${CALDP_BUILD_DIR}" ] then mkdir -p $TMP_INSTALL_DIR CALDP_BUILD_DIR="${TMP_INSTALL_DIR}/caldp" @@ -50,6 +60,16 @@ then # github's tarballs don't work with pip install, so we have to clone and checkout the tag git clone https://github.com/spacetelescope/caldp.git cd caldp && git fetch --all --tags && git checkout tags/v${CALDP_VER} && cd .. + git_exit_status=$? + if [[ $git_exit_status -ne 0 ]]; then + # try without the v + cd caldp && git fetch --all --tags && git checkout tags/${CALDP_VER} && cd .. + git_exit_status=$? + fi + if [[ $git_exit_status -ne 0 ]]; then + echo "could not checkout ${CALDP_VER}; exiting" + exit 1 + fi fi # get a couple of things from AWS ssm @@ -67,13 +87,33 @@ aws_tfstate=${aws_tfstate_response##*:} aws_tfstate=`echo $aws_tfstate | tr -d '",'` echo $aws_tfstate +# get AMI id +cd $CALCLOUD_BUILD_DIR/ami_rotation +ami_json=$(echo $(awsudo $ADMIN_ARN aws ec2 describe-images --region us-east-1 --executable-users self)) +ci_ami=`python3 parse_image_json.py "${ami_json}" STSCI-AWS-Linux-2` +ecs_ami=`python3 parse_image_json.py "${ami_json}" STSCI-HST-REPRO-ECS` + +if [[ "$ci_ami" =~ ^ami-[a-z0-9]+$ ]]; then + echo $ci_ami +else + echo "failed to retrieve valid ami id for ci_ami" + exit 1 +fi + +if [[ "$ecs_ami" =~ ^ami-[a-z0-9]+$ ]]; then + echo $ecs_ami +else + echo "failed to retrieve valid ami id for ecs_ami" + exit 1 +fi + # initial terraform setup cd ${CALCLOUD_BUILD_DIR}/terraform # terraform init and s3 state backend config awsudo $ADMIN_ARN terraform init -backend-config="bucket=${aws_tfstate}" -backend-config="key=calcloud/${aws_env}.tfstate" -backend-config="region=us-east-1" # deploy ecr -awsudo $ADMIN_ARN terraform plan -var "environment=${aws_env}" -out base.out -target aws_ecr_repository.caldp_ecr +awsudo $ADMIN_ARN terraform plan -var "environment=${aws_env}" -var "ci_ami=${ci_ami}" -var "ecs_ami=${ecs_ami}" -out base.out -target aws_ecr_repository.caldp_ecr awsudo $ADMIN_ARN terraform apply -auto-approve "base.out" # get repository url from tf state for use in caldp docker install repo_url_response=`awsudo $ADMIN_ARN terraform state show aws_ecr_repository.caldp_ecr | grep "repository_url"` @@ -129,9 +169,10 @@ awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.compute_env[1] awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.compute_env[2] awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.compute_env[3] awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.model_compute_env[0] +awsudo $ADMIN_ARN terraform taint module.lambda_function_container_image.aws_lambda_function.this[0] # manual confirmation required -awsudo $ADMIN_ARN terraform apply -var "awsysver=${CALCLOUD_VER}" -var "awsdpver=${CALDP_VER}" -var "csys_ver=${CSYS_VER}" -var "environment=${aws_env}" +awsudo $ADMIN_ARN terraform apply -var "awsysver=${CALCLOUD_VER}" -var "awsdpver=${CALDP_VER}" -var "csys_ver=${CSYS_VER}" -var "environment=${aws_env}" -var "ci_ami=${ci_ami}" -var "ecs_ami=${ecs_ami}" # make sure needed prefixes exist in primary s3 bucket # pulls the bucket name in from a tag called Name @@ -152,7 +193,9 @@ awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key inputs/ awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key outputs/ awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key control/ awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key blackboard/ +awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key crds_env_vars/ awsudo $ADMIN_ARN aws s3api put-object --bucket $bucket_url --key crds_env_vars/${crds_context} + cd $HOME rm -rf $TMP_INSTALL_DIR diff --git a/terraform/deploy_ami_rotate.sh b/terraform/deploy_ami_rotate.sh index e8bffe85..3320ef1f 100755 --- a/terraform/deploy_ami_rotate.sh +++ b/terraform/deploy_ami_rotate.sh @@ -1,17 +1,18 @@ #! /bin/bash -xu # ADMIN_ARN is set in the ci node env and should not be included in this deploy script +aws_env=${aws_env:-""} # get the versions from ssm params -calcloud_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/awsysver" | grep "Value"` +calcloud_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/awsysver-${aws_env}" | grep "Value"` CALCLOUD_VER=${calcloud_ver_response##*:} CALCLOUD_VER=`echo $CALCLOUD_VER | tr -d '",'` -caldp_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/awsdpver" | grep "Value"` +caldp_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/awsdpver-${aws_env}" | grep "Value"` CALDP_VER=${caldp_ver_response##*:} CALDP_VER=`echo $CALDP_VER | tr -d '",'` -csys_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/csys_ver" | grep "Value"` +csys_ver_response=`awsudo $ADMIN_ARN aws ssm get-parameter --name "/tf/env/csys_ver-${aws_env}" | grep "Value"` CSYS_VER=${csys_ver_response##*:} CSYS_VER=`echo $CSYS_VER | tr -d '",'` @@ -21,7 +22,6 @@ CSYS_VER=`echo $CSYS_VER | tr -d '",'` # (and avoid accidentally committing a custom path to the repo...) CALCLOUD_BUILD_DIR=${CALCLOUD_BUILD_DIR:-""} CALDP_BUILD_DIR=${CALDP_BUILD_DIR:-""} -aws_env=${aws_env:-""} # variables that will be changed less-frequently TMP_INSTALL_DIR="/tmp/calcloud_install" @@ -73,6 +73,26 @@ aws_tfstate=${aws_tfstate_response##*:} aws_tfstate=`echo $aws_tfstate | tr -d '",'` echo $aws_tfstate +# get AMI id +cd $CALCLOUD_BUILD_DIR/ami_rotation +ami_json=$(echo $(awsudo $ADMIN_ARN aws ec2 describe-images --region us-east-1 --executable-users self)) +ci_ami=`python3 parse_image_json.py "${ami_json}" STSCI-AWS-Linux-2` +ecs_ami=`python3 parse_image_json.py "${ami_json}" STSCI-HST-REPRO-ECS` + +if [[ "$ci_ami" =~ ^ami-[a-z0-9]+$ ]]; then + echo $ci_ami +else + echo "failed to retrieve valid ami id for ci_ami" + exit 1 +fi + +if [[ "$ecs_ami" =~ ^ami-[a-z0-9]+$ ]]; then + echo $ecs_ami +else + echo "failed to retrieve valid ami id for ecs_ami" + exit 1 +fi + # initial terraform setup cd ${CALCLOUD_BUILD_DIR}/terraform @@ -86,15 +106,16 @@ awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.compute_env[2] awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.compute_env[3] awsudo $ADMIN_ARN terraform taint aws_batch_compute_environment.model_compute_env[0] -awsudo $ADMIN_ARN terraform plan -var "environment=${aws_env}" -out ami_rotate.out \ +awsudo $ADMIN_ARN terraform plan -no-color -var "environment=${aws_env}" -out ami_rotate.out \ -target aws_batch_compute_environment.model_compute_env \ -target aws_batch_compute_environment.compute_env \ -target aws_batch_job_queue.batch_queue \ -target aws_batch_job_queue.model_queue \ -target aws_launch_template.hstdp \ - -var "awsysver=${CALCLOUD_VER}" -var "awsdpver=${CALDP_VER}" -var "csys_ver=${CSYS_VER}" -var "environment=${aws_env}" + -target aws_launch_template.ami_rotation \ + -var "awsysver=${CALCLOUD_VER}" -var "awsdpver=${CALDP_VER}" -var "csys_ver=${CSYS_VER}" -var "environment=${aws_env}" -var "ci_ami=${ci_ami}" -var "ecs_ami=${ecs_ami}" -awsudo $ADMIN_ARN terraform apply "ami_rotate.out" +awsudo $ADMIN_ARN terraform apply -no-color "ami_rotate.out" cd $HOME rm -rf $TMP_INSTALL_DIR diff --git a/terraform/lambda_batch_events.tf b/terraform/lambda_batch_events.tf index 3d725e99..cdbc3b84 100644 --- a/terraform/lambda_batch_events.tf +++ b/terraform/lambda_batch_events.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_batchEvents" { description = "listens for Batch failure events from cloudWatch event rule" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "batch_event_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_batchEvents" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_blackboard.tf b/terraform/lambda_blackboard.tf index 65ec8065..ab290c1b 100644 --- a/terraform/lambda_blackboard.tf +++ b/terraform/lambda_blackboard.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_blackboard" { description = "scrapes the Batch console for job metadata and posts to S3 bucket for on-premise poller" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "scrape_batch.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 300 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_blackboard" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_broadcast.tf b/terraform/lambda_broadcast.tf index 2be22565..4d598d93 100644 --- a/terraform/lambda_broadcast.tf +++ b/terraform/lambda_broadcast.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_broadcast" { description = "Broadcasts the specified message type across a list of job_ids or ippppssoots." # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "broadcast_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 300 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_broadcast" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_job_clean.tf b/terraform/lambda_job_clean.tf index 2562721c..2084b369 100644 --- a/terraform/lambda_job_clean.tf +++ b/terraform/lambda_job_clean.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_cleanJob" { description = "accepts messages from s3 event and cleans either individual jobs by ipppssoot, or all active jobs" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "clean_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_cleanJob" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_job_delete.tf b/terraform/lambda_job_delete.tf index 31050f80..1f82446c 100644 --- a/terraform/lambda_job_delete.tf +++ b/terraform/lambda_job_delete.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_deleteJob" { description = "accepts messages from s3 event and deletes either individual jobs by ipppssoot, or all active jobs" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "delete_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_deleteJob" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_job_rescue.tf b/terraform/lambda_job_rescue.tf index cffeddbf..5b68ad90 100644 --- a/terraform/lambda_job_rescue.tf +++ b/terraform/lambda_job_rescue.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_rescueJob" { description = "Rescues the specified ipppssoot (must be in error state) by deleting all outputs and messages and re-placing." # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "rescue_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_rescueJob" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true @@ -42,6 +47,7 @@ module "calcloud_lambda_rescueJob" { environment_variables = merge(local.common_env_vars, { JOBPREDICTLAMBDA = module.lambda_function_container_image.this_lambda_function_arn, SUBMIT_TIMEOUT = 14*60, # leave some room for polling jitter, 14 min vs 15 min above + DDBTABLE = "${aws_dynamodb_table.calcloud_model_db.name}" }) tags = { diff --git a/terraform/lambda_job_submit.tf b/terraform/lambda_job_submit.tf index f357096c..a1311846 100644 --- a/terraform/lambda_job_submit.tf +++ b/terraform/lambda_job_submit.tf @@ -7,7 +7,7 @@ module "calcloud_lambda_submit" { description = "looks for placed-ipppssoot messages and submits jobs to Batch" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "s3_trigger_handler.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 15*60 # see also SUBMIT_TIMEOUT below; this is the AWS timeout, calcloud error handling may not occur cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -24,7 +24,12 @@ module "calcloud_lambda_submit" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true @@ -42,8 +47,9 @@ module "calcloud_lambda_submit" { environment_variables = merge(local.common_env_vars, { JOBPREDICTLAMBDA = module.lambda_function_container_image.this_lambda_function_arn, - SUBMIT_TIMEOUT = 14*60, # leave some room for polling jitter, 14 min vs 15 min above - }) # this is our timeout so error handling / cleanup should occur + SUBMIT_TIMEOUT = 14*60, # leave some room for polling jitter, 14 min vs 15 min above. This is our timeout so error handling / cleanup should occur + DDBTABLE = "${aws_dynamodb_table.calcloud_model_db.name}" + }) tags = { Name = "calcloud-job-submit${local.environment}" diff --git a/terraform/lambda_model_ingest.tf b/terraform/lambda_model_ingest.tf index 1cfb13c7..70e9057c 100644 --- a/terraform/lambda_model_ingest.tf +++ b/terraform/lambda_model_ingest.tf @@ -1,6 +1,6 @@ resource "aws_dynamodb_table" "calcloud_model_db" { name = "calcloud-model${local.environment}" - billing_mode = "PAY_PER_REQUEST" #"PROVISIONED" + billing_mode = "PAY_PER_REQUEST" hash_key = "ipst" attribute { @@ -22,9 +22,10 @@ module "lambda_model_ingest" { lambda_role = nonsensitive(data.aws_ssm_parameter.model_ingest_role.value) description = "looks for processed-ipppssoot.trigger messages, scrapes and uploads completed job data to DynamoDB" handler = "lambda_scrape.lambda_handler" - runtime = "python3.8" + runtime = "python3.7" publish = false timeout = 180 + memory_size = 256 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days source_path = [ diff --git a/terraform/lambda_refresh_cache.tf b/terraform/lambda_refresh_cache.tf index b622b060..dc6a1140 100644 --- a/terraform/lambda_refresh_cache.tf +++ b/terraform/lambda_refresh_cache.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_refresh_cache_submit" { description = "submits refresh cache operations" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "refresh_cache_submit.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_refresh_cache_submit" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/lambda_refresh_cache_logging.tf b/terraform/lambda_refresh_cache_logging.tf index 18478fa5..409bda3c 100644 --- a/terraform/lambda_refresh_cache_logging.tf +++ b/terraform/lambda_refresh_cache_logging.tf @@ -6,7 +6,7 @@ module "calcloud_lambda_refresh_cache_logs" { description = "listens for refresh cache operations and logs them" # the path is relative to the path inside the lambda env, not in the local filesystem. handler = "refresh_cache_logs.lambda_handler" - runtime = "python3.6" + runtime = "python3.7" publish = false timeout = 900 cloudwatch_logs_retention_in_days = local.lambda_log_retention_in_days @@ -23,7 +23,12 @@ module "calcloud_lambda_refresh_cache_logs" { path = "${path.module}/../calcloud" prefix_in_zip = "calcloud" pip_requirements = false - } + }, + { + # pip dependencies defined for calcloud package in requirements.txt + path = "${path.module}/../calcloud" + pip_requirements = true + }, ] store_on_s3 = true diff --git a/terraform/outputs.tf b/terraform/outputs.tf index be151b3e..a00181d7 100644 --- a/terraform/outputs.tf +++ b/terraform/outputs.tf @@ -1,5 +1,5 @@ -output batch_ami_id { - value = nonsensitive(data.aws_ssm_parameter.batch_ami_id.value) +output ecs_ami_id { + value = nonsensitive(aws_ssm_parameter.ecs_ami.value) description = "AMI ID ssm parameter, for ITSD's latest Batch worker AMI" } diff --git a/terraform/parameters.tf b/terraform/parameters.tf index d678a55f..a0055ffd 100644 --- a/terraform/parameters.tf +++ b/terraform/parameters.tf @@ -1,7 +1,3 @@ -data aws_ssm_parameter batch_ami_id { - name = "/AMI/STSCI-HST-REPRO-ECS" -} - data aws_ssm_parameter batch_subnet_ids { name = "/subnets/private" } @@ -30,6 +26,10 @@ data aws_ssm_parameter vpc { name = "vpc" } +data aws_ssm_parameter admin_arn { + name = "/iam/roles/calcloud_admin" +} + data aws_ssm_parameter lambda_submit_role { name = "/iam/roles/calcloud_lambda_submit" } @@ -62,6 +62,10 @@ data aws_ssm_parameter lambda_refreshCacheSubmit_role { name = "/iam/roles/calcloud_lambda_refreshCacheSubmit" } +data aws_ssm_parameter lambda_amiRotate_role { + name = "/iam/roles/calcloud_lambda_amiRotate" +} + data aws_ssm_parameter model_ingest_role { name = "/iam/roles/calcloud_model_ingest" } @@ -110,20 +114,41 @@ data aws_ssm_parameter batch_exec { name = "/iam/roles/batch_exec" } +data aws_ssm_parameter ci_instance_role { + name = "/iam/roles/ci_instance_role" +} + resource "aws_ssm_parameter" "awsysver" { - name = "/tf/env/awsysver" + name = "/tf/env/awsysver${local.environment}" type = "String" value = "${var.awsysver}" + overwrite = true } resource "aws_ssm_parameter" "awsdpver" { - name = "/tf/env/awsdpver" + name = "/tf/env/awsdpver${local.environment}" type = "String" value = "${var.awsdpver}" + overwrite = true } resource "aws_ssm_parameter" "csys_ver" { - name = "/tf/env/csys_ver" + name = "/tf/env/csys_ver${local.environment}" type = "String" value = "${var.csys_ver}" -} \ No newline at end of file + overwrite = true +} + +resource "aws_ssm_parameter" "ecs_ami" { + name = "/tf/ami/stsci-hst-repro-ecs${local.environment}" + type = "String" + value = "${var.ecs_ami}" + overwrite = true +} + +resource "aws_ssm_parameter" "ci_ami" { + name = "/tf/ami/stsci-hst-amazon-linux-2${local.environment}" + type = "String" + value = "${var.ci_ami}" + overwrite = true +} diff --git a/terraform/variables.tf b/terraform/variables.tf index e0ed3bee..901d6217 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -99,8 +99,8 @@ variable crds_context { default = { "-sb" = "hst_0866.pmap" "-dev" = "hst_0866.pmap" - "-test" = "hst_0943.pmap" - "-ops" = "hst_0943.pmap" + "-test" = "hst_0968.pmap" + "-ops" = "hst_0968.pmap" } } @@ -113,3 +113,11 @@ variable crds_bucket { "-ops" = "ops" } } + +variable ci_ami { + type = string +} + +variable ecs_ami { + type = string +} diff --git a/tox.ini b/tox.ini index 9db915cb..e332ca38 100644 --- a/tox.ini +++ b/tox.ini @@ -2,25 +2,25 @@ envlist = black, flake8, bandit #, coverage, pytest [testenv:black] -basepython = python3.8 +basepython = python3.7 extras = dev whitelist_externals = black commands= - black --check calcloud tests lambda + black --check calcloud tests lambda ami_rotation scripts [testenv:flake8] -basepython = python3.8 +basepython = python3.7 extras = dev whitelist_externals = flake8 commands = - flake8 --count --ignore E501,W503,E203 --max-line-length 88 calcloud tests lambda + flake8 --count --ignore E501,W503,E203 --max-line-length 88 calcloud tests lambda ami_rotation [testenv:bandit] -basepython = python3.8 +basepython = python3.7 extras = dev whitelist_externals = bandit commands = - bandit -ll -r -f txt calcloud tests lambda + bandit -ll -r -f txt calcloud tests lambda ami_rotation # [testenv:pytest] # extras = dev @@ -29,7 +29,7 @@ commands = # pytest # [testenv:coverage] -# basepython = python3.8 +# basepython = python3.7 # extras = dev # whitelist_externals = pytest # commands =