├── .gitignore ├── LICENSE ├── README.md ├── pull_request_template.md └── tfjs-converter ├── .babelrc ├── .npmignore ├── DEVELOPMENT.md ├── README.md ├── cloudbuild.yml ├── demo ├── control_flow │ ├── README.md │ ├── index.html │ └── loop_model.js ├── mobilenet │ ├── README.md │ ├── cat.jpg │ ├── imagenet_classes.js │ ├── index.html │ ├── index.js │ └── mobilenet.js ├── package.json ├── ssd │ ├── classes.js │ ├── image1.jpg │ ├── image2.jpg │ ├── index.html │ └── index.js └── yarn.lock ├── docs └── supported_ops.md ├── karma.conf.js ├── package.json ├── python ├── .pylintrc ├── BUILD ├── MANIFEST.in ├── README.md ├── WORKSPACE ├── __init__.py ├── build-pip-package.sh ├── requirements-dev.txt ├── requirements.txt ├── run-python-tests.sh ├── setup.cfg ├── setup.py ├── tensorflowjs │ ├── BUILD │ ├── __init__.py │ ├── converters │ │ ├── BUILD │ │ ├── __init__.py │ │ ├── common.py │ │ ├── converter.py │ │ ├── converter_binary_test.sh │ │ ├── converter_test.py │ │ ├── generate_test_model.py │ │ ├── keras_h5_conversion.py │ │ ├── keras_h5_conversion_test.py │ │ ├── keras_tfjs_loader.py │ │ ├── keras_tfjs_loader_test.py │ │ ├── tf_saved_model_conversion_v2.py │ │ └── tf_saved_model_conversion_v2_test.py │ ├── op_list │ │ ├── arithmetic.json │ │ ├── basic_math.json │ │ ├── control.json │ │ ├── convolution.json │ │ ├── creation.json │ │ ├── dynamic.json │ │ ├── evaluation.json │ │ ├── graph.json │ │ ├── image.json │ │ ├── logical.json │ │ ├── matrices.json │ │ ├── normalization.json │ │ ├── reduction.json │ │ ├── slice_join.json │ │ ├── spectral.json │ │ └── transformation.json │ ├── quantization.py │ ├── quantization_test.py │ ├── read_weights.py │ ├── read_weights_test.py │ ├── version.py │ ├── write_weights.py │ └── write_weights_test.py └── test_pip_package.py ├── rollup.config.js ├── scripts ├── build-npm.sh ├── gen_doc.ts ├── gen_json.ts ├── make-version ├── publish-npm.sh ├── tag-version └── test_snippets.ts ├── src ├── data │ ├── api.proto │ ├── compiled_api.ts │ └── types.ts ├── executor │ ├── execution_context.ts │ ├── execution_context_test.ts │ ├── graph_executor.ts │ ├── graph_executor_test.ts │ ├── graph_model.ts │ ├── graph_model_test.ts │ ├── model_analysis.ts │ ├── model_analysis_test.ts │ ├── model_rewrite.ts │ ├── model_rewrite_test.ts │ ├── tensor_array.ts │ └── tensor_array_test.ts ├── index.ts ├── operations │ ├── custom_op │ │ ├── node_value_impl.ts │ │ ├── node_value_impl_test.ts │ │ ├── register.ts │ │ └── register_test.ts │ ├── executors │ │ ├── arithmetic_executor.ts │ │ ├── arithmetic_executor_test.ts │ │ ├── basic_math_executor.ts │ │ ├── basic_math_executor_test.ts │ │ ├── control_executor.ts │ │ ├── control_executor_test.ts │ │ ├── convolution_executor.ts │ │ ├── convolution_executor_test.ts │ │ ├── creation_executor.ts │ │ ├── creation_executor_test.ts │ │ ├── dynamic_executor.ts │ │ ├── dynamic_executor_test.ts │ │ ├── evaluation_executor.ts │ │ ├── evaluation_executor_test.ts │ │ ├── graph_executor.ts │ │ ├── graph_executor_test.ts │ │ ├── image_executor.ts │ │ ├── image_executor_test.ts │ │ ├── logical_executor.ts │ │ ├── logical_executor_test.ts │ │ ├── matrices_executor.ts │ │ ├── matrices_executor_test.ts │ │ ├── normalization_executor.ts │ │ ├── normalization_executor_test.ts │ │ ├── reduction_executor.ts │ │ ├── reduction_executor_test.ts │ │ ├── slice_join_executor.ts │ │ ├── slice_join_executor_test.ts │ │ ├── spectral_executor.ts │ │ ├── spectral_executor_test.ts │ │ ├── test_helper.ts │ │ ├── transformation_executor.ts │ │ ├── transformation_executor_test.ts │ │ └── utils.ts │ ├── op_list │ │ ├── arithmetic.ts │ │ ├── basic_math.ts │ │ ├── control.ts │ │ ├── convolution.ts │ │ ├── creation.ts │ │ ├── dynamic.ts │ │ ├── evaluation.ts │ │ ├── graph.ts │ │ ├── image.ts │ │ ├── logical.ts │ │ ├── matrices.ts │ │ ├── normalization.ts │ │ ├── op_list_test.ts │ │ ├── reduction.ts │ │ ├── slice_join.ts │ │ ├── spectral.ts │ │ └── transformation.ts │ ├── op_mapper_schema.ts │ ├── operation_executor.ts │ ├── operation_executor_test.ts │ ├── operation_mapper.ts │ ├── operation_mapper_test.ts │ └── types.ts ├── version.ts └── version_test.ts ├── tools ├── compiled_api.d.ts ├── compiled_api.js └── pb2json_converter.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | package-lock.json 4 | npm-debug.log 5 | yarn-error.log 6 | .DS_Store 7 | dist/ 8 | .idea/ 9 | *.tgz 10 | .cache 11 | package/ 12 | 13 | bazel-* 14 | 15 | *.pyc 16 | .rpt2_cache/ 17 | /compiled_api.js 18 | 19 | # Contains auto-generated json files produced by `yarn gen-json` 20 | **.yalc 21 | **yalc.lock 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This repository has been archived in favor of tensorflow/tfjs. 2 | 3 | This repo will remain around for some time to keep history but all future PRs should be sent to [tensorflow/tfjs](https://github.com/tensorflow/tfjs) inside the tfjs-core folder. 4 | 5 | All history and contributions have been preserved in the monorepo. -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## This repository has been archived in favor of the monorepo at https://github.com/tensorflow/tfjs. Please send pull requests there. -------------------------------------------------------------------------------- /tfjs-converter/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ], 10 | "plugins": [ 11 | "external-helpers" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tfjs-converter/.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | .DS_Store 3 | .idea/ 4 | .pylintrc 5 | .rpt2_cache 6 | .travis.yml 7 | .vscode 8 | *.tgz 9 | *.txt 10 | **.yalc 11 | **yalc.lock 12 | cloudbuild.yml 13 | coverage/ 14 | demo/ 15 | DEVELOPMENT.md 16 | dist/**/*_test.d.ts 17 | dist/**/*_test.js 18 | docs/ 19 | ISSUE_TEMPLATE.md 20 | karma.conf.js 21 | node_modules/ 22 | npm-debug.log 23 | package-lock.json 24 | package/ 25 | python/ 26 | rollup.config.google.js 27 | rollup.config.js 28 | scripts/ 29 | src/**/*_test.ts 30 | test_results 31 | tsconfig.json 32 | tslint.json 33 | yarn-error.log 34 | yarn.lock 35 | .git 36 | -------------------------------------------------------------------------------- /tfjs-converter/DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Notes for TensorFlow.js-Converter Developers 2 | 3 | ## Python Development 4 | 5 | There are some Python libraries, binary and tests in the `python/` directory. 6 | 7 | It is recommended to do your Python development and testing in a 8 | [virtualenv](https://virtualenv.pypa.io/en/stable/) or 9 | [pipenv](https://docs.pipenv.org/). 10 | 11 | As a prerequisite, install the following dependencies for python testing 12 | ```sh 13 | cd python 14 | pip install -r requirements.txt 15 | ``` 16 | 17 | For Python linter, install `pylint`, e.g., 18 | * `apt-get install -y pylint` 19 | 20 | To run the Python linter: 21 | ```sh 22 | cd python 23 | pylint tensorflowjs 24 | ``` 25 | 26 | To run the python unit tests, there are two options. You can choose the one that 27 | you prefer. 28 | 29 | 1. Run the tests using the `run-python-tests.sh` script: 30 | 31 | ```sh 32 | cd python 33 | ./run-python-tests.sh 34 | ``` 35 | 36 | 2. Run the tests using Bazel. See bazel installation guide 37 | [here](https://docs.bazel.build/versions/master/install.html). Once bazel 38 | is installed, do: 39 | 40 | ```sh 41 | cd python 42 | bazel test tensorflowjs/... 43 | ``` 44 | 45 | Be sure to run the tests under **both** Python 2 and Python 3. 46 | 47 | ### Building and testing the tensorflowjs pip package 48 | 49 | ```sh 50 | cd python 51 | 52 | # You need to specify a folder where the pip wheel file will be stored, e.g., 53 | ./build-pip-package.sh /tmp/my_tensorflowjs_pip 54 | 55 | # If the script succeeds, you can use `pip install` to install the pip package: 56 | 57 | pip install --force-reinstall \ 58 | /tmp/my_tensorflowjs_pip/tensorflowjs-0.0.1-py2-none-any.whl 59 | ``` 60 | 61 | `build-pip-package.sh` provides a flag (`--test`) with which you can run a 62 | test-on-install after building the pip package. Make sure you are using a 63 | `virutalenv` or `pipenv` to avoid changing your base environmnet. 64 | 65 | ```sh 66 | ./build-pip-package.sh --test /tmp/my_tensorflowjs_pip 67 | ``` 68 | -------------------------------------------------------------------------------- /tfjs-converter/cloudbuild.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: 'node:10' 3 | entrypoint: 'yarn' 4 | id: 'yarn' 5 | args: ['install'] 6 | - name: 'node:10' 7 | entrypoint: 'yarn' 8 | id: 'test-browser' 9 | args: ['test-ci'] 10 | waitFor: ['yarn'] 11 | env: ['BROWSERSTACK_USERNAME=deeplearnjs1', 'NIGHTLY=$_NIGHTLY'] 12 | secretEnv: ['BROWSERSTACK_KEY'] 13 | - name: 'gcr.io/google-appengine/python' 14 | dir: 'python' 15 | entrypoint: 'bash' 16 | args: ['./build-pip-package.sh', '--test', '/tmp/tfjs-pips'] 17 | waitFor: ['yarn'] 18 | - name: 'python:2' 19 | dir: 'python' 20 | entrypoint: 'bash' 21 | args: ['./run-python-tests.sh'] 22 | waitFor: ['yarn'] 23 | - name: 'python:3.6' 24 | dir: 'python' 25 | entrypoint: 'bash' 26 | args: ['./run-python-tests.sh'] 27 | waitFor: ['yarn'] 28 | - name: 'node:10' 29 | entrypoint: 'yarn' 30 | id: 'test-snippets' 31 | args: ['test-snippets'] 32 | waitFor: ['yarn'] 33 | secrets: 34 | - kmsKeyName: projects/learnjs-174218/locations/global/keyRings/tfjs/cryptoKeys/enc 35 | secretEnv: 36 | BROWSERSTACK_KEY: CiQAkwyoIW0LcnxymzotLwaH4udVTQFBEN4AEA5CA+a3+yflL2ASPQAD8BdZnGARf78MhH5T9rQqyz9HNODwVjVIj64CTkFlUCGrP1B2HX9LXHWHLmtKutEGTeFFX9XhuBzNExA= 37 | timeout: 1800s 38 | logsBucket: 'gs://tfjs-build-logs' 39 | substitutions: 40 | _NIGHTLY: '' 41 | options: 42 | logStreamingOption: 'STREAM_ON' 43 | substitution_option: 'ALLOW_LOOSE' 44 | -------------------------------------------------------------------------------- /tfjs-converter/demo/control_flow/README.md: -------------------------------------------------------------------------------- 1 | # TensorFlow SavedModel Import Demo 2 | 3 | This demo imports a TensorFlow model that is generated by tf.while_loop 4 | for inference in the browser. The model was pre-converted to TensorFlow.js 5 | format and hosted on Google Cloud, using the steps in 6 | the repo's [README.md](../../README.md). 7 | 8 | The following commands will start a web server on `localhost:1234` and open 9 | a browser page with the demo. 10 | 11 | The demo allows you to change the conditions of the loop interactively and observe the execution result right in the browser. 12 | 13 | ```bash 14 | cd demo # If not already in the demo directory. 15 | yarn # Installs dependencies. 16 | yarn control_flow # Starts a web server and opens a page. Also watches for changes. 17 | ``` 18 | -------------------------------------------------------------------------------- /tfjs-converter/demo/control_flow/index.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 32 |

TensorFlow.js Converter: ControlFlow

33 |

This example uses a Tensorflow model that is generated by tf.while_loop method.

34 | 35 |

36 | You can change the conditions of the loop and press the run button to 37 | observe the execution result. 38 |

39 | 40 |
41 |         
42 |         var output = 0; 
43 | ; ; i++) {
44 | ; j++) {
45 | ;
46 | }
47 | console.log(output+1);
48 |
49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tfjs-converter/demo/control_flow/loop_model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tf from '@tensorflow/tfjs'; 19 | const GOOGLE_CLOUD_STORAGE_DIR = 20 | 'https://storage.googleapis.com/tfjs-models/savedmodel/'; 21 | const MODEL_FILE_URL = 'nested_loop/model.json'; 22 | const OUTPUT_NODE_NAME = 'Add'; 23 | 24 | export class LoopModel { 25 | constructor() {} 26 | 27 | async load() { 28 | this.model = await tf.loadGraphModel( 29 | GOOGLE_CLOUD_STORAGE_DIR + MODEL_FILE_URL); 30 | } 31 | 32 | dispose() { 33 | if (this.model) { 34 | this.model.dispose(); 35 | } 36 | } 37 | 38 | async predict(init, loop, loop2, inc) { 39 | const dict = { 40 | 'init': tf.scalar(init, 'int32'), 41 | 'times': tf.scalar(loop, 'int32'), 42 | 'times2': tf.scalar(loop2, 'int32'), 43 | 'inc': tf.scalar(inc, 'int32') 44 | }; 45 | return this.model.executeAsync(dict, OUTPUT_NODE_NAME); 46 | } 47 | } 48 | 49 | window.onload = async () => { 50 | const resultElement = document.getElementById('result'); 51 | 52 | resultElement.innerText = 'Loading Control Flow model...'; 53 | 54 | const loopModel = new LoopModel(); 55 | console.time('Loading of model'); 56 | await loopModel.load(); 57 | console.timeEnd('Loading of model'); 58 | resultElement.innerText = 'Model loaded.'; 59 | 60 | const runBtn = document.getElementById('run'); 61 | runBtn.onclick = async () => { 62 | const init = document.getElementById('init').value; 63 | const loop = document.getElementById('loop').value; 64 | const loop2 = document.getElementById('loop2').value; 65 | const inc = document.getElementById('inc').value; 66 | console.time('prediction'); 67 | const result = await loopModel.predict(init, loop, loop2, inc); 68 | console.timeEnd('prediction'); 69 | 70 | resultElement.innerText = "output = " + result.dataSync()[0]; 71 | }; 72 | }; 73 | -------------------------------------------------------------------------------- /tfjs-converter/demo/mobilenet/README.md: -------------------------------------------------------------------------------- 1 | # TensorFlow SavedModel Import Demo 2 | 3 | This demo imports the 4 | [MobileNet v2.0](https://www.tensorflow.org/hub/modules/google/imagenet/mobilenet_v2_100_224/classification/1) 5 | model for inference in the browser. The model was pre-converted to TensorFlow.js 6 | format and hosted on Google Cloud, using the steps in 7 | the repo's [README.md](../../README.md). 8 | 9 | The following commands will start a web server on `localhost:1234` and open 10 | a browser page with the demo. 11 | 12 | ```bash 13 | cd demo # If not already in the demo directory. 14 | yarn # Installs dependencies. 15 | yarn mobilenet # Starts a web server and opens a page. Also watches for changes. 16 | ``` 17 | -------------------------------------------------------------------------------- /tfjs-converter/demo/mobilenet/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tensorflow/tfjs-converter/06b9238b6262d2b359e441998d7a7277a5196886/tfjs-converter/demo/mobilenet/cat.jpg -------------------------------------------------------------------------------- /tfjs-converter/demo/mobilenet/index.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 | 26 | 27 | 28 |

TensorFlow.js Converter: MobileNet

29 | 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tfjs-converter/demo/mobilenet/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import 'babel-polyfill'; 18 | import * as tf from '@tensorflow/tfjs'; 19 | import {MobileNet} from './mobilenet'; 20 | import imageURL from './cat.jpg'; 21 | 22 | const cat = document.getElementById('cat'); 23 | cat.onload = async () => { 24 | const resultElement = document.getElementById('result'); 25 | 26 | resultElement.innerText = 'Loading MobileNet...'; 27 | 28 | const mobileNet = new MobileNet(); 29 | console.time('Loading of model'); 30 | await mobileNet.load(); 31 | console.timeEnd('Loading of model'); 32 | 33 | const pixels = tf.browser.fromPixels(cat); 34 | 35 | console.time('First prediction'); 36 | let result = mobileNet.predict(pixels); 37 | const topK = mobileNet.getTopKClasses(result, 5); 38 | console.timeEnd('First prediction'); 39 | 40 | resultElement.innerText = ''; 41 | topK.forEach(x => { 42 | resultElement.innerText += `${x.value.toFixed(3)}: ${x.label}\n`; 43 | }); 44 | 45 | console.time('Subsequent predictions'); 46 | result = mobileNet.predict(pixels); 47 | mobileNet.getTopKClasses(result, 5); 48 | console.timeEnd('Subsequent predictions'); 49 | 50 | mobileNet.dispose(); 51 | }; 52 | cat.src = imageURL; 53 | -------------------------------------------------------------------------------- /tfjs-converter/demo/mobilenet/mobilenet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tf from '@tensorflow/tfjs'; 19 | 20 | import {IMAGENET_CLASSES} from './imagenet_classes'; 21 | 22 | const GOOGLE_CLOUD_STORAGE_DIR = 23 | 'https://storage.googleapis.com/tfjs-models/savedmodel/'; 24 | const MODEL_FILE_URL = 'mobilenet_v2_1.0_224/model.json'; 25 | const INPUT_NODE_NAME = 'images'; 26 | const OUTPUT_NODE_NAME = 'module_apply_default/MobilenetV2/Logits/output'; 27 | const PREPROCESS_DIVISOR = tf.scalar(255 / 2); 28 | 29 | export class MobileNet { 30 | constructor() {} 31 | 32 | async load() { 33 | this.model = await tf.loadGraphModel( 34 | GOOGLE_CLOUD_STORAGE_DIR + MODEL_FILE_URL); 35 | } 36 | 37 | dispose() { 38 | if (this.model) { 39 | this.model.dispose(); 40 | } 41 | } 42 | /** 43 | * Infer through MobileNet. This does standard ImageNet pre-processing before 44 | * inferring through the model. This method returns named activations as well 45 | * as softmax logits. 46 | * 47 | * @param input un-preprocessed input Array. 48 | * @return The softmax logits. 49 | */ 50 | predict(input) { 51 | const preprocessedInput = tf.div( 52 | tf.sub(input.asType('float32'), PREPROCESS_DIVISOR), 53 | PREPROCESS_DIVISOR); 54 | const reshapedInput = 55 | preprocessedInput.reshape([1, ...preprocessedInput.shape]); 56 | return this.model.execute( 57 | {[INPUT_NODE_NAME]: reshapedInput}, OUTPUT_NODE_NAME); 58 | } 59 | 60 | getTopKClasses(logits, topK) { 61 | const predictions = tf.tidy(() => { 62 | return tf.softmax(logits); 63 | }); 64 | 65 | const values = predictions.dataSync(); 66 | predictions.dispose(); 67 | 68 | let predictionList = []; 69 | for (let i = 0; i < values.length; i++) { 70 | predictionList.push({value: values[i], index: i}); 71 | } 72 | predictionList = predictionList 73 | .sort((a, b) => { 74 | return b.value - a.value; 75 | }) 76 | .slice(0, topK); 77 | 78 | return predictionList.map(x => { 79 | return {label: IMAGENET_CLASSES[x.index], value: x.value}; 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tfjs-converter/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tfjs-converter-demo", 3 | "version": "0.0.1", 4 | "description": "Imports mobilenet model using the tfc.js converter", 5 | "main": "index.js", 6 | "license": "Apache-2.0", 7 | "private": true, 8 | "dependencies": { 9 | "@tensorflow/tfjs": "0.15.3", 10 | "babel-polyfill": "^6.26.0" 11 | }, 12 | "scripts": { 13 | "mobilenet": "NODE_ENV=development parcel mobilenet/index.html --no-hmr --open", 14 | "ssd": "NODE_ENV=development parcel ssd/index.html --no-hmr --open", 15 | "control_flow": "NODE_ENV=development parcel control_flow/index.html --no-hmr --open" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.0.0-0", 19 | "@babel/plugin-transform-runtime": "^7.3.4", 20 | "@babel/polyfill": "~7.2.5", 21 | "@babel/preset-env": "~7.3.4", 22 | "@babel/runtime": "~7.3.4", 23 | "clang-format": "~1.2.2", 24 | "parcel-bundler": "~1.11.0" 25 | }, 26 | "babel": { 27 | "presets": [ 28 | [ 29 | "env", 30 | { 31 | "modules": false, 32 | "targets": { 33 | "browsers": [ 34 | "> 1%", 35 | "last 3 versions", 36 | "ie >= 9", 37 | "ios >= 8", 38 | "android >= 4.2" 39 | ] 40 | }, 41 | "useBuiltIns": false 42 | } 43 | ] 44 | ], 45 | "plugins": [ 46 | [ 47 | "@babel/plugin-transform-runtime" 48 | ] 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tfjs-converter/demo/ssd/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tensorflow/tfjs-converter/06b9238b6262d2b359e441998d7a7277a5196886/tfjs-converter/demo/ssd/image1.jpg -------------------------------------------------------------------------------- /tfjs-converter/demo/ssd/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tensorflow/tfjs-converter/06b9238b6262d2b359e441998d7a7277a5196886/tfjs-converter/demo/ssd/image2.jpg -------------------------------------------------------------------------------- /tfjs-converter/demo/ssd/index.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 | 18 | 19 |

TensorFlow.js converter: ssd_mobilenet_v1_coco_2018_01_28

20 | 21 | 22 |
23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tfjs-converter/demo/ssd/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import 'babel-polyfill'; 18 | import * as tf from '@tensorflow/tfjs'; 19 | import {CLASSES} from './classes'; 20 | import imageURL from './image1.jpg'; 21 | import image2URL from './image2.jpg'; 22 | 23 | const GOOGLE_CLOUD_STORAGE_DIR = 24 | 'https://storage.googleapis.com/tfjs-models/savedmodel/'; 25 | const MODEL_URL = 26 | GOOGLE_CLOUD_STORAGE_DIR + 'coco-ssd-mobilenet_v1/model.json'; 27 | 28 | let modelPromise; 29 | 30 | window.onload = () => modelPromise = tf.loadGraphModel(MODEL_URL); 31 | 32 | const button = document.getElementById('toggle'); 33 | button.onclick = () => { 34 | image.src = image.src.endsWith(imageURL) ? image2URL : imageURL; 35 | }; 36 | 37 | const image = document.getElementById('image'); 38 | image.src = imageURL; 39 | 40 | const runButton = document.getElementById('run'); 41 | runButton.onclick = async () => { 42 | const model = await modelPromise; 43 | const pixels = tf.browser.fromPixels(image); 44 | console.log('model loaded'); 45 | console.time('predict1'); 46 | const res1 = await model.executeAsync(pixels.reshape([1, ...pixels.shape])); 47 | res1.map(t => t.dataSync()); 48 | console.timeEnd('predict1'); 49 | console.time('predict2'); 50 | const res2 = await model.executeAsync(pixels.reshape([1, ...pixels.shape])); 51 | const count = res2[3].dataSync()[0]; 52 | const boxes = res2[0].dataSync(); 53 | const scores = res2[1].dataSync(); 54 | const classes = res2[2].dataSync(); 55 | console.timeEnd('predict2'); 56 | 57 | 58 | const c = document.getElementById('canvas'); 59 | const context = c.getContext('2d'); 60 | context.drawImage(image, 0, 0); 61 | context.font = '10px Arial'; 62 | 63 | console.log('number of detections: ', count); 64 | for (let i = 0; i < count; i++) { 65 | const min_y = boxes[i * 4] * 399; 66 | const min_x = boxes[i * 4 + 1] * 600; 67 | const max_y = boxes[i * 4 + 2] * 399; 68 | const max_x = boxes[i * 4 + 3] * 600; 69 | 70 | context.beginPath(); 71 | context.rect(min_x, min_y, max_x - min_x, max_y - min_y); 72 | context.lineWidth = 1; 73 | context.strokeStyle = 'black'; 74 | context.stroke(); 75 | context.fillText( 76 | scores[i].toFixed(3) + ' ' + CLASSES.find(label => label.id === classes[i]).display_name, 77 | min_x, min_y - 5); 78 | } 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /tfjs-converter/karma.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | module.exports = function(config) { 19 | config.set({ 20 | frameworks: ['jasmine', 'karma-typescript'], 21 | files: [{pattern: 'src/**/*.ts'}], 22 | exclude: [ 23 | 'src/docs/**/*.ts' 24 | ], 25 | preprocessors: { 26 | 'src/**/*.ts': ['karma-typescript'], // *.tsx for React Jsx 27 | 'src/**/*.js': ['karma-typescript'], // *.tsx for React Jsx 28 | }, 29 | karmaTypescriptConfig: { 30 | tsconfig: 'tsconfig.json', 31 | compilerOptions: { 32 | allowJs: true, 33 | declaration: false, 34 | module: 'commonjs' 35 | }, 36 | coverageOptions: {instrumentation: false}, 37 | reports: {} // Do not produce coverage html. 38 | }, 39 | reporters: ['progress', 'karma-typescript'], 40 | browsers: ['Chrome'], 41 | browserStack: { 42 | username: process.env.BROWSERSTACK_USERNAME, 43 | accessKey: process.env.BROWSERSTACK_KEY 44 | }, 45 | reportSlowerThan: 500, 46 | browserNoActivityTimeout: 30000, 47 | customLaunchers: { 48 | bs_chrome_mac: { 49 | base: 'BrowserStack', 50 | browser: 'chrome', 51 | browser_version: 'latest', 52 | os: 'OS X', 53 | os_version: 'Sierra' 54 | }, 55 | bs_firefox_mac: { 56 | base: 'BrowserStack', 57 | browser: 'firefox', 58 | // TODO(cais): Change it back to 'latest' once the ongoing instability 59 | // with regard to OS X and FireFox is resolved on BrowserStack: 60 | // https://github.com/tensorflow/tfjs/issues/1620 61 | browser_version: '66.0', 62 | os: 'OS X', 63 | os_version: 'Sierra' 64 | } 65 | }, 66 | client: { 67 | args: ['--grep', config.grep || ''] 68 | } 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /tfjs-converter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tensorflow/tfjs-converter", 3 | "version": "1.2.7", 4 | "description": "Tensorflow model converter for javascript", 5 | "main": "dist/src/index.js", 6 | "jsnext:main": "dist/tf-converter.esm.js", 7 | "module": "dist/tf-converter.esm.js", 8 | "types": "dist/src/index.d.ts", 9 | "unpkg": "dist/tf-converter.min.js", 10 | "jsdelivr": "dist/tf-converter.min.js", 11 | "miniprogram": "dist/miniprogram", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/tensorflow/tfjs-converter.git" 15 | }, 16 | "license": "Apache-2.0", 17 | "peerDependencies": { 18 | "@tensorflow/tfjs-core": "1.2.8" 19 | }, 20 | "devDependencies": { 21 | "@tensorflow/tfjs-core": "1.2.8", 22 | "@types/deep-equal": "^1.0.1", 23 | "@types/jasmine": "~2.8.6", 24 | "@types/long": "~3.0.32", 25 | "@types/node-fetch": "1.6.9", 26 | "ajv": "~6.3.0", 27 | "babel-core": "~6.26.3", 28 | "babel-plugin-external-helpers": "~6.22.0", 29 | "babel-preset-env": "~1.7.0", 30 | "clang-format": "~1.2.2", 31 | "copyfiles": "~1.2.0", 32 | "deep-equal": "^1.0.1", 33 | "jasmine-core": "~3.1.0", 34 | "karma": "~4.0.1", 35 | "karma-browserstack-launcher": "~1.4.0", 36 | "karma-chrome-launcher": "~2.2.0", 37 | "karma-firefox-launcher": "~1.1.0", 38 | "karma-jasmine": "~2.0.1", 39 | "karma-typescript": "~4.0.0", 40 | "node-fetch": "~2.1.2", 41 | "opn": "~5.1.0", 42 | "protobufjs": "~6.8.6", 43 | "rimraf": "~2.6.2", 44 | "rollup": "~0.58.2", 45 | "rollup-plugin-cleanup": "~3.0.0", 46 | "rollup-plugin-commonjs": "~9.1.3", 47 | "rollup-plugin-node-resolve": "~3.3.0", 48 | "rollup-plugin-typescript2": "~0.13.0", 49 | "rollup-plugin-uglify": "~3.0.0", 50 | "ts-node": "~4.1.0", 51 | "tslint": "~5.8.0", 52 | "tslint-no-circular-imports": "~0.5.0", 53 | "typescript": "3.3.3333", 54 | "yalc": "~1.0.0-pre.21" 55 | }, 56 | "scripts": { 57 | "build": "yarn gen-json --test && tsc && copyfiles -f src/data/compiled_api.* dist/src/data/", 58 | "build-npm": "./scripts/build-npm.sh", 59 | "link-local": "yalc link", 60 | "publish-local": "yarn build-npm && yalc push", 61 | "test": "yarn gen-json --test && karma start", 62 | "test-ci": "yarn gen-json --test && yarn build && yarn lint && yarn run-browserstack", 63 | "test-snippets": "ts-node ./scripts/test_snippets.ts", 64 | "run-browserstack": "karma start --singleRun --browsers='bs_firefox_mac,bs_chrome_mac' --reporters='dots,karma-typescript,BrowserStack'", 65 | "lint": "tslint -p . -t verbose", 66 | "make-version": "sh -c ./scripts/make-version", 67 | "gen-doc": "ts-node ./scripts/gen_doc.ts", 68 | "gen-json": "ts-node ./scripts/gen_json.ts", 69 | "pb2json": "ts-node ./tools/pb2json_converter.ts", 70 | "build-pip-package": "yarn gen-json --test && cd python && ./build-pip-package.sh --test /tmp/tfjs-pips", 71 | "run-python-tests": "yarn gen-json --test && cd python && ./run-python-tests.sh" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tfjs-converter/python/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tensorflow/tfjs-converter/06b9238b6262d2b359e441998d7a7277a5196886/tfjs-converter/python/BUILD -------------------------------------------------------------------------------- /tfjs-converter/python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | -------------------------------------------------------------------------------- /tfjs-converter/python/README.md: -------------------------------------------------------------------------------- 1 | # tensorflowjs: The Python Package for TensorFlow.js 2 | 3 | The **tensorflowjs** pip package contains libraries and tools for 4 | [TensorFlow.js](https://js.tensorflow.org). 5 | -------------------------------------------------------------------------------- /tfjs-converter/python/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "org_tensorflow_js") 2 | -------------------------------------------------------------------------------- /tfjs-converter/python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tensorflow/tfjs-converter/06b9238b6262d2b359e441998d7a7277a5196886/tfjs-converter/python/__init__.py -------------------------------------------------------------------------------- /tfjs-converter/python/requirements-dev.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | pylint==1.8.3 3 | -------------------------------------------------------------------------------- /tfjs-converter/python/requirements.txt: -------------------------------------------------------------------------------- 1 | h5py==2.8.0 2 | keras==2.2.4 3 | numpy==1.16.4 4 | six==1.11.0 5 | tensorflow==1.14.0 6 | tensorflow-hub==0.5.0 7 | -------------------------------------------------------------------------------- /tfjs-converter/python/run-python-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2018 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ============================================================================== 16 | 17 | # A script that runs all Python unit tests in tfjs-layers. 18 | 19 | set -e 20 | 21 | SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 22 | 23 | TEST_FILES="$(find "${SCRIPTS_DIR}" -name '*_test.py')" 24 | 25 | pip install virtualenv 26 | 27 | TMP_VENV_DIR="$(mktemp -d --suffix=_venv)" 28 | virtualenv -p "python" "${TMP_VENV_DIR}" 29 | source "${TMP_VENV_DIR}/bin/activate" 30 | 31 | pip install -r "${SCRIPTS_DIR}/requirements-dev.txt" 32 | 33 | cd "${SCRIPTS_DIR}" 34 | pylint --rcfile=.pylintrc tensorflowjs 35 | 36 | export PYTHONPATH=".:${PYTHONPATH}" 37 | for TEST_FILE in ${TEST_FILES}; do 38 | echo 39 | echo "====== Running test: ${TEST_FILE} ======" 40 | echo 41 | python "${TEST_FILE}" 42 | done 43 | 44 | echo 45 | echo "All tests passed." 46 | echo 47 | 48 | deactivate 49 | rm -rf "${TMP_VENV_DIR}" 50 | -------------------------------------------------------------------------------- /tfjs-converter/python/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /tfjs-converter/python/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """Build pip wheel for model_converter.""" 16 | 17 | import os 18 | import setuptools 19 | from tensorflowjs import version 20 | 21 | DIR_NAME = os.path.dirname(__file__) 22 | 23 | def _get_requirements(file): 24 | "Reads the requirements file and returns the packages" 25 | with open(os.path.join(DIR_NAME, file), 'r') as requirements: 26 | return requirements.readlines() 27 | 28 | CONSOLE_SCRIPTS = [ 29 | 'tensorflowjs_converter = tensorflowjs.converters.converter:pip_main', 30 | ] 31 | 32 | setuptools.setup( 33 | name='tensorflowjs', 34 | version=version.version, 35 | description='Python Libraries and Tools for TensorFlow.js', 36 | url='https://js.tensorflow.org/', 37 | author='Google LLC', 38 | author_email='opensource@google.com', 39 | classifiers=[ 40 | 'Development Status :: 3 - Alpha', 41 | 'Intended Audience :: Developers', 42 | 'Intended Audience :: Education', 43 | 'Intended Audience :: Science/Research', 44 | 'License :: OSI Approved :: Apache Software License', 45 | 'Programming Language :: JavaScript', 46 | 'Programming Language :: Python :: 2', 47 | 'Programming Language :: Python :: 3', 48 | 'Topic :: Scientific/Engineering', 49 | 'Topic :: Scientific/Engineering :: Mathematics', 50 | 'Topic :: Scientific/Engineering :: Artificial Intelligence', 51 | 'Topic :: Software Development', 52 | 'Topic :: Software Development :: Libraries', 53 | 'Topic :: Software Development :: Libraries :: Python Modules', 54 | ], 55 | py_modules=[ 56 | 'tensorflowjs', 57 | 'tensorflowjs.version', 58 | 'tensorflowjs.quantization', 59 | 'tensorflowjs.read_weights', 60 | 'tensorflowjs.write_weights', 61 | 'tensorflowjs.converters', 62 | 'tensorflowjs.converters.common', 63 | 'tensorflowjs.converters.converter', 64 | 'tensorflowjs.converters.keras_h5_conversion', 65 | 'tensorflowjs.converters.keras_tfjs_loader', 66 | 'tensorflowjs.converters.tf_saved_model_conversion_v2', 67 | ], 68 | include_package_data=True, 69 | packages=['tensorflowjs/op_list'], 70 | package_data={ 71 | 'tensorflowjs/op_list': ['*.json'] 72 | }, 73 | install_requires=_get_requirements('requirements.txt'), 74 | entry_points={ 75 | 'console_scripts': CONSOLE_SCRIPTS, 76 | }, 77 | license='Apache 2.0', 78 | keywords='tensorflow javascript machine deep learning converter', 79 | ) 80 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/BUILD: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = [ 3 | "//tensorflowjs:__subpackages__", 4 | ], 5 | ) 6 | 7 | licenses(["notice"]) # Apache 2.0 8 | 9 | exports_files(["LICENSE"]) 10 | 11 | py_library( 12 | name = "tensorflowjs", 13 | srcs = ["__init__.py"], 14 | srcs_version = "PY2AND3", 15 | deps = [ 16 | ":quantization", 17 | ":version", 18 | "//tensorflowjs/converters:converter" 19 | ], 20 | visibility = ["//visibility:public"], 21 | ) 22 | 23 | py_library( 24 | name = "expect_h5py_installed", 25 | # This is a dummy rule used as a h5py dependency in open-source. 26 | # We expect h5py to already be installed on the system, e.g. via 27 | # `pip install h5py`. 28 | ) 29 | 30 | py_library( 31 | name = "expect_numpy_installed", 32 | # This is a dummy rule used as a numpy dependency in open-source. 33 | # We expect numpy to already be installed on the system, e.g. via 34 | # `pip install numpy`. 35 | ) 36 | 37 | py_library( 38 | name = "expect_tensorflow_installed", 39 | # This is a dummy rule used as a tensorflow dependency in open-source. 40 | # We expect tensorflow to already be installed on the system, e.g. via 41 | # `pip install tensorflow` or `pip install tensorflow-gpu`. 42 | ) 43 | 44 | py_library( 45 | name = "expect_tensorflow_hub_installed", 46 | # This is a dummy rule used as a tensorflow_hub dependency in open-source. 47 | # We expect tensorflow to already be installed on the system, e.g. via 48 | # `pip install tensorflow` or `pip install tensorflow-gpu`. 49 | ) 50 | 51 | py_library( 52 | name = "quantization", 53 | srcs = ["quantization.py"], 54 | srcs_version = "PY2AND3", 55 | deps = [ 56 | "//tensorflowjs:expect_numpy_installed", 57 | ], 58 | ) 59 | 60 | py_library( 61 | name = "write_weights", 62 | srcs = ["write_weights.py"], 63 | srcs_version = "PY2AND3", 64 | deps = [ 65 | ":quantization", 66 | ":read_weights", 67 | "//tensorflowjs:expect_numpy_installed", 68 | ], 69 | ) 70 | 71 | py_library( 72 | name = "read_weights", 73 | srcs = ["read_weights.py"], 74 | srcs_version = "PY2AND3", 75 | deps = [ 76 | ":quantization", 77 | "//tensorflowjs:expect_numpy_installed", 78 | ], 79 | ) 80 | 81 | py_library( 82 | name = "version", 83 | srcs = ["version.py"], 84 | srcs_version = "PY2AND3", 85 | deps = [], 86 | ) 87 | 88 | py_test( 89 | name = "quantization_test", 90 | srcs = ["quantization_test.py"], 91 | srcs_version = "PY2AND3", 92 | deps = [ 93 | ":quantization", 94 | "//tensorflowjs:expect_numpy_installed", 95 | ], 96 | ) 97 | 98 | py_test( 99 | name = "write_weights_test", 100 | srcs = ["write_weights_test.py"], 101 | srcs_version = "PY2AND3", 102 | deps = [ 103 | ":write_weights", 104 | "//tensorflowjs:expect_numpy_installed", 105 | ], 106 | ) 107 | 108 | py_test( 109 | name = "read_weights_test", 110 | srcs = ["read_weights_test.py"], 111 | srcs_version = "PY2AND3", 112 | deps = [ 113 | ":read_weights", 114 | ":write_weights", 115 | "//tensorflowjs:expect_numpy_installed", 116 | ], 117 | ) 118 | 119 | # A filegroup BUILD target that includes all the op list json files in the 120 | # the op_list/ folder. The op_list folder itself is a symbolic link to the 121 | # actual op_list folder under src/. 122 | filegroup( 123 | name = "op_list_jsons", 124 | srcs = glob(["op_list/*.json"]), 125 | ) 126 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | # pylint: disable=unused-imports 21 | from tensorflowjs import converters 22 | from tensorflowjs import quantization 23 | from tensorflowjs import version 24 | 25 | __version__ = version.version 26 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/converters/BUILD: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = [ 3 | "//tensorflowjs:__subpackages__", 4 | ], 5 | licenses = ["notice"], # Apache 2.0 6 | ) 7 | 8 | py_library( 9 | name = "common", 10 | srcs = ["common.py"], 11 | srcs_version = "PY2AND3", 12 | deps = ["//tensorflowjs:version"], 13 | ) 14 | 15 | py_library( 16 | name = "keras_h5_conversion", 17 | srcs = ["keras_h5_conversion.py"], 18 | srcs_version = "PY2AND3", 19 | deps = [ 20 | ":common", 21 | "//tensorflowjs:expect_h5py_installed", 22 | "//tensorflowjs:expect_numpy_installed", 23 | "//tensorflowjs:write_weights", 24 | ], 25 | ) 26 | 27 | py_test( 28 | name = "keras_h5_conversion_test", 29 | srcs = ["keras_h5_conversion_test.py"], 30 | srcs_version = "PY2AND3", 31 | deps = [ 32 | ":keras_h5_conversion", 33 | "//tensorflowjs:expect_h5py_installed", 34 | "//tensorflowjs:expect_numpy_installed", 35 | "//tensorflowjs:expect_tensorflow_installed", 36 | "//tensorflowjs:version", 37 | ], 38 | ) 39 | 40 | py_library( 41 | name = "keras_tfjs_loader", 42 | srcs = ["keras_tfjs_loader.py"], 43 | srcs_version = "PY2AND3", 44 | deps = [ 45 | ":keras_h5_conversion", 46 | "//tensorflowjs:expect_numpy_installed", 47 | "//tensorflowjs:read_weights", 48 | ], 49 | ) 50 | 51 | py_test( 52 | name = "keras_tfjs_loader_test", 53 | srcs = ["keras_tfjs_loader_test.py"], 54 | srcs_version = "PY2AND3", 55 | deps = [ 56 | ":keras_h5_conversion", 57 | ":keras_tfjs_loader", 58 | "//tensorflowjs:expect_numpy_installed", 59 | "//tensorflowjs:expect_tensorflow_installed", 60 | ], 61 | ) 62 | 63 | py_test( 64 | name = "tf_saved_model_conversion_v2_test", 65 | srcs = ["tf_saved_model_conversion_v2_test.py"], 66 | srcs_version = "PY2AND3", 67 | deps = [ 68 | ":tf_saved_model_conversion_v2", 69 | "//tensorflowjs:expect_tensorflow_installed", 70 | "//tensorflowjs:expect_tensorflow_hub_installed", 71 | ], 72 | ) 73 | 74 | py_library( 75 | name = "tf_saved_model_conversion_v2", 76 | srcs = ["tf_saved_model_conversion_v2.py"], 77 | data = ["//tensorflowjs:op_list_jsons"], 78 | srcs_version = "PY2AND3", 79 | deps = [ 80 | "//tensorflowjs:expect_numpy_installed", 81 | "//tensorflowjs:expect_tensorflow_installed", 82 | "//tensorflowjs:expect_tensorflow_hub_installed", 83 | "//tensorflowjs:version", 84 | "//tensorflowjs:write_weights", 85 | "//tensorflowjs/converters:common", 86 | ], 87 | ) 88 | 89 | py_binary( 90 | name = "converter", 91 | srcs = ["converter.py"], 92 | srcs_version = "PY2AND3", 93 | deps = [ 94 | ":keras_h5_conversion", 95 | ":keras_tfjs_loader", 96 | ":tf_saved_model_conversion_v2", 97 | "//tensorflowjs:expect_h5py_installed", 98 | "//tensorflowjs:expect_tensorflow_installed", 99 | "//tensorflowjs:version", 100 | ], 101 | visibility = ["//visibility:public"], 102 | ) 103 | 104 | py_binary( 105 | name = "generate_test_model", 106 | srcs = ["generate_test_model.py"], 107 | testonly = True, 108 | srcs_version = "PY2AND3", 109 | deps = [ 110 | "//tensorflowjs:expect_tensorflow_installed", 111 | ] 112 | ) 113 | 114 | py_test( 115 | name = "converter_test", 116 | srcs = ["converter_test.py"], 117 | srcs_version = "PY2AND3", 118 | deps = [ 119 | ":converter", 120 | ":keras_tfjs_loader", 121 | "//tensorflowjs:expect_numpy_installed", 122 | "//tensorflowjs:expect_tensorflow_installed", 123 | "//tensorflowjs:version", 124 | ], 125 | ) 126 | 127 | sh_test( 128 | name = "converter_binary_test", 129 | srcs = ["converter_binary_test.sh"], 130 | data = [ 131 | ":converter", 132 | ":generate_test_model", 133 | ], 134 | ) 135 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/converters/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | from __future__ import absolute_import 17 | from __future__ import division 18 | from __future__ import print_function 19 | 20 | # pylint: disable=unused-imports,line-too-long 21 | from tensorflowjs.converters.keras_h5_conversion import save_keras_model 22 | from tensorflowjs.converters.keras_tfjs_loader import deserialize_keras_model 23 | from tensorflowjs.converters.keras_tfjs_loader import load_keras_model 24 | from tensorflowjs.converters.tf_saved_model_conversion_v2 import convert_tf_saved_model 25 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/converters/common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | from tensorflowjs import version 17 | 18 | 19 | # File name for the indexing JSON file in an artifact directory. 20 | ARTIFACT_MODEL_JSON_FILE_NAME = 'model.json' 21 | 22 | # JSON string keys for fields of the indexing JSON. 23 | ARTIFACT_MODEL_TOPOLOGY_KEY = 'modelTopology' 24 | ARTIFACT_WEIGHTS_MANIFEST_KEY = 'weightsManifest' 25 | 26 | FORMAT_KEY = 'format' 27 | TFJS_GRAPH_MODEL_FORMAT = 'graph-model' 28 | TFJS_LAYERS_MODEL_FORMAT = 'layers-model' 29 | 30 | GENERATED_BY_KEY = 'generatedBy' 31 | CONVERTED_BY_KEY = 'convertedBy' 32 | 33 | 34 | def get_converted_by(): 35 | """Get the convertedBy string for storage in model artifacts.""" 36 | return 'TensorFlow.js Converter v%s' % version.version 37 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/converters/converter_binary_test.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | set -e 17 | 18 | GENERATE_BIN="${TEST_SRCDIR}/org_tensorflow_js/tensorflowjs/converters/generate_test_model" 19 | CONVERTER_BIN="${TEST_SRCDIR}/org_tensorflow_js/tensorflowjs/converters/converter" 20 | 21 | # 1. Test tf_saved_model --> tfjs_graph_model conversion. 22 | SAVED_MODEL_DIR="$(mktemp -d)" 23 | echo "Genearting TF SavedModel for testing..." 24 | "${GENERATE_BIN}" "${SAVED_MODEL_DIR}" --model_type tf_saved_model 25 | echo "Done genearting TF SavedModel for testing at ${SAVED_MODEL_DIR}" 26 | 27 | OUTPUT_DIR="${SAVED_MODEL_DIR}_converted" 28 | "${CONVERTER_BIN}" \ 29 | --input_format tf_saved_model \ 30 | --output_format tfjs_graph_model \ 31 | "${SAVED_MODEL_DIR}" \ 32 | "${OUTPUT_DIR}" 33 | 34 | if [[ ! -d "${OUTPUT_DIR}" ]]; then 35 | echo "ERROR: Failed to find conversion output directory: ${OUTPUT_DIR}" 1>&2 36 | exit 1 37 | fi 38 | 39 | # Clean up files. 40 | rm -rf "${SAVED_MODEL_DIR}" "${OUTPUT_DIR}" 41 | 42 | # 2. Test keras HDF5 --> tfjs_layers_model conversion. 43 | KERAS_H5_PATH="$(mktemp).h5" 44 | echo "Genearting Keras HDF5 model for testing..." 45 | "${GENERATE_BIN}" "${KERAS_H5_PATH}" --model_type tf_keras_h5 46 | echo "Done genearting Keras HDF5 model for testing at ${KERAS_H5_PATH}" 47 | 48 | OUTPUT_H5_PATH="${KERAS_H5_PATH}_converted.h5" 49 | "${CONVERTER_BIN}" \ 50 | --input_format keras \ 51 | --output_format tfjs_layers_model \ 52 | "${KERAS_H5_PATH}" \ 53 | "${OUTPUT_H5_PATH}" 54 | 55 | if [[ ! -d "${OUTPUT_H5_PATH}" ]]; then 56 | echo "ERROR: Failed to find conversion output directory: ${OUTPUT_H5_PATH}" 1>&2 57 | exit 1 58 | fi 59 | 60 | # Clean up files. 61 | rm -rf "${KERAS_H5_PATH}" "${OUTPUT_H5_PATH}" 62 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/converters/generate_test_model.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | """A binary that generates saved model artifacts for testing.""" 16 | 17 | from __future__ import absolute_import 18 | from __future__ import division 19 | from __future__ import print_function 20 | 21 | import argparse 22 | import os 23 | import sys 24 | 25 | import tensorflow as tf 26 | 27 | tf.enable_eager_execution() 28 | 29 | 30 | def parse_args(): 31 | parser = argparse.ArgumentParser( 32 | 'Generates saved model artifacts for testing.') 33 | parser.add_argument( 34 | 'output_path', 35 | type=str, 36 | help='Model output path.') 37 | parser.add_argument( 38 | '--model_type', 39 | type=str, 40 | required=True, 41 | choices=set(['tf_keras_h5', 'tf_saved_model']), 42 | help='Model format to generate.') 43 | return parser.parse_known_args() 44 | 45 | 46 | def main(_): 47 | 48 | if args.model_type == 'tf_keras_h5': 49 | model = tf.keras.Sequential() 50 | model.add(tf.keras.layers.Dense(5, activation='relu', input_shape=(8,))) 51 | model.add(tf.keras.layers.Dense(1, activation='sigmoid')) 52 | model.save(os.path.join(args.output_path)) 53 | elif args.model_type == 'tf_saved_model': 54 | class TimesThreePlusOne(tf.train.Checkpoint): 55 | 56 | @tf.function(input_signature=[ 57 | tf.TensorSpec(shape=None, dtype=tf.float32)]) 58 | def compute(self, x): 59 | return x * 3.0 + 1.0 60 | 61 | tf.saved_model.save(TimesThreePlusOne(), args.output_path) 62 | else: 63 | raise ValueError('Unrecognized model type: %s' % args.model_type) 64 | 65 | 66 | if __name__ == '__main__': 67 | args, unparsed = parse_args() 68 | tf.app.run(main=main, argv=[sys.argv[0]] + unparsed) 69 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/dynamic.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "NonMaxSuppressionV2", 4 | "category": "dynamic", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "boxes", 9 | "type": "tensor" 10 | }, 11 | { 12 | "start": 1, 13 | "name": "scores", 14 | "type": "tensor" 15 | }, 16 | { 17 | "start": 2, 18 | "name": "maxOutputSize", 19 | "type": "number" 20 | }, 21 | { 22 | "start": 3, 23 | "name": "iouThreshold", 24 | "type": "number" 25 | } 26 | ] 27 | }, 28 | { 29 | "tfOpName": "NonMaxSuppressionV3", 30 | "category": "dynamic", 31 | "inputs": [ 32 | { 33 | "start": 0, 34 | "name": "boxes", 35 | "type": "tensor" 36 | }, 37 | { 38 | "start": 1, 39 | "name": "scores", 40 | "type": "tensor" 41 | }, 42 | { 43 | "start": 2, 44 | "name": "maxOutputSize", 45 | "type": "number" 46 | }, 47 | { 48 | "start": 3, 49 | "name": "iouThreshold", 50 | "type": "number" 51 | }, 52 | { 53 | "start": 4, 54 | "name": "scoreThreshold", 55 | "type": "number" 56 | } 57 | ] 58 | }, 59 | { 60 | "tfOpName": "Where", 61 | "category": "dynamic", 62 | "inputs": [ 63 | { 64 | "start": 0, 65 | "name": "condition", 66 | "type": "tensor" 67 | } 68 | ], 69 | "attrs": [ 70 | { 71 | "tfName": "T", 72 | "name": "dtype", 73 | "type": "dtype", 74 | "notSupported": true 75 | } 76 | ] 77 | }, 78 | { 79 | "tfOpName": "ListDiff", 80 | "category": "dynamic", 81 | "inputs": [ 82 | { 83 | "start": 0, 84 | "name": "x", 85 | "type": "tensor" 86 | }, 87 | { 88 | "start": 1, 89 | "name": "y", 90 | "type": "tensor" 91 | } 92 | ], 93 | "attrs": [ 94 | { 95 | "tfName": "T", 96 | "name": "dtype", 97 | "type": "dtype", 98 | "notSupported": true 99 | } 100 | ] 101 | } 102 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/evaluation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "TopKV2", 4 | "category": "evaluation", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "x", 9 | "type": "tensor" 10 | }, 11 | { 12 | "start": 1, 13 | "name": "k", 14 | "type": "number" 15 | } 16 | ], 17 | "attrs": [ 18 | { 19 | "tfName": "sorted", 20 | "name": "sorted", 21 | "type": "bool" 22 | } 23 | ] 24 | } 25 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/graph.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "PlaceholderWithDefault", 4 | "category": "graph", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "default", 9 | "type": "tensor" 10 | } 11 | ], 12 | "attrs": [ 13 | { 14 | "tfName": "shape", 15 | "name": "shape", 16 | "type": "shape" 17 | }, 18 | { 19 | "tfName": "dtype", 20 | "name": "dtype", 21 | "type": "dtype" 22 | } 23 | ] 24 | }, 25 | { 26 | "tfOpName": "Placeholder", 27 | "category": "graph", 28 | "attrs": [ 29 | { 30 | "tfName": "shape", 31 | "name": "shape", 32 | "type": "shape" 33 | }, 34 | { 35 | "tfName": "dtype", 36 | "name": "dtype", 37 | "type": "dtype" 38 | } 39 | ] 40 | }, 41 | { 42 | "tfOpName": "Const", 43 | "category": "graph" 44 | }, 45 | { 46 | "tfOpName": "Identity", 47 | "category": "graph", 48 | "inputs": [ 49 | { 50 | "start": 0, 51 | "name": "x", 52 | "type": "tensor" 53 | } 54 | ] 55 | }, 56 | { 57 | "tfOpName": "IdentityN", 58 | "category": "graph", 59 | "inputs": [ 60 | { 61 | "start": 0, 62 | "end": 0, 63 | "name": "x", 64 | "type": "tensors" 65 | } 66 | ] 67 | }, 68 | { 69 | "tfOpName": "Snapshot", 70 | "category": "graph", 71 | "inputs": [ 72 | { 73 | "start": 0, 74 | "name": "x", 75 | "type": "tensor" 76 | } 77 | ] 78 | }, 79 | { 80 | "tfOpName": "Rank", 81 | "category": "graph", 82 | "inputs": [ 83 | { 84 | "start": 0, 85 | "name": "x", 86 | "type": "tensor" 87 | } 88 | ] 89 | }, 90 | { 91 | "tfOpName": "Size", 92 | "category": "graph", 93 | "inputs": [ 94 | { 95 | "start": 0, 96 | "name": "x", 97 | "type": "tensor" 98 | } 99 | ] 100 | }, 101 | { 102 | "tfOpName": "Shape", 103 | "category": "graph", 104 | "inputs": [ 105 | { 106 | "start": 0, 107 | "name": "x", 108 | "type": "tensor" 109 | } 110 | ] 111 | }, 112 | { 113 | "tfOpName": "ShapeN", 114 | "category": "graph", 115 | "inputs": [ 116 | { 117 | "start": 0, 118 | "end": 0, 119 | "name": "x", 120 | "type": "tensors" 121 | } 122 | ] 123 | }, 124 | { 125 | "tfOpName": "Print", 126 | "category": "graph", 127 | "inputs": [ 128 | { 129 | "start": 0, 130 | "name": "x", 131 | "type": "tensor" 132 | }, 133 | { 134 | "start": 1, 135 | "name": "data", 136 | "type": "tensors" 137 | } 138 | ], 139 | "attrs": [ 140 | { 141 | "tfName": "message", 142 | "name": "message", 143 | "type": "string" 144 | }, 145 | { 146 | "tfName": "first_n", 147 | "name": "firstN", 148 | "type": "number", 149 | "notSupported": true 150 | }, 151 | { 152 | "tfName": "summarize", 153 | "name": "summarize", 154 | "type": "number", 155 | "defaultValue": 3 156 | } 157 | ] 158 | }, 159 | { 160 | "tfOpName": "NoOp", 161 | "category": "graph", 162 | "inputs": [] 163 | }, 164 | { 165 | "tfOpName": "StopGradient", 166 | "category": "graph", 167 | "inputs": [ 168 | { 169 | "start": 0, 170 | "name": "x", 171 | "type": "tensor" 172 | } 173 | ] 174 | }, 175 | { 176 | "tfOpName": "FakeQuantWithMinMaxVars", 177 | "category": "graph", 178 | "inputs": [ 179 | { 180 | "start": 0, 181 | "name": "x", 182 | "type": "tensor" 183 | } 184 | ], 185 | "attrs": [ 186 | { 187 | "tfName": "min", 188 | "name": "min", 189 | "type": "number" 190 | }, 191 | { 192 | "tfName": "max", 193 | "name": "max", 194 | "type": "number" 195 | } 196 | ] 197 | } 198 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/image.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "ResizeBilinear", 4 | "category": "image", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "images", 9 | "type": "tensor" 10 | }, 11 | { 12 | "start": 1, 13 | "name": "size", 14 | "type": "number[]" 15 | } 16 | ], 17 | "attrs": [ 18 | { 19 | "tfName": "align_corners", 20 | "name": "alignCorners", 21 | "type": "bool" 22 | }, 23 | { 24 | "tfName": "T", 25 | "name": "dtype", 26 | "type": "dtype", 27 | "notSupported": true 28 | } 29 | ] 30 | }, 31 | { 32 | "tfOpName": "ResizeNearestNeighbor", 33 | "category": "image", 34 | "inputs": [ 35 | { 36 | "start": 0, 37 | "name": "images", 38 | "type": "tensor" 39 | }, 40 | { 41 | "start": 1, 42 | "name": "size", 43 | "type": "number[]" 44 | } 45 | ], 46 | "attrs": [ 47 | { 48 | "tfName": "align_corners", 49 | "name": "alignCorners", 50 | "type": "bool" 51 | }, 52 | { 53 | "tfName": "T", 54 | "name": "dtype", 55 | "type": "dtype", 56 | "notSupported": true 57 | } 58 | ] 59 | }, 60 | { 61 | "tfOpName": "CropAndResize", 62 | "category": "image", 63 | "inputs": [ 64 | { 65 | "start": 0, 66 | "name": "image", 67 | "type": "tensor" 68 | }, 69 | { 70 | "start": 1, 71 | "name": "boxes", 72 | "type": "tensor" 73 | }, 74 | { 75 | "start": 2, 76 | "name": "boxInd", 77 | "type": "tensor" 78 | }, 79 | { 80 | "start": 3, 81 | "name": "cropSize", 82 | "type": "number[]" 83 | } 84 | ], 85 | "attrs": [ 86 | { 87 | "tfName": "method", 88 | "name": "method", 89 | "type": "string" 90 | }, 91 | { 92 | "tfName": "extrapolation_value", 93 | "name": "extrapolationValue", 94 | "type": "number" 95 | } 96 | ] 97 | } 98 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/matrices.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "MatMul", 4 | "category": "matrices", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "a", 9 | "type": "tensor" 10 | }, 11 | { 12 | "start": 1, 13 | "name": "b", 14 | "type": "tensor" 15 | } 16 | ], 17 | "attrs": [ 18 | { 19 | "tfName": "transpose_a", 20 | "name": "transposeA", 21 | "type": "bool", 22 | "defaultValue": false 23 | }, 24 | { 25 | "tfName": "transpose_b", 26 | "name": "transposeB", 27 | "type": "bool", 28 | "defaultValue": false 29 | }, 30 | { 31 | "tfName": "T", 32 | "name": "dtype", 33 | "type": "dtype", 34 | "notSupported": true 35 | } 36 | ] 37 | }, 38 | { 39 | "tfOpName": "BatchMatMul", 40 | "category": "matrices", 41 | "inputs": [ 42 | { 43 | "start": 0, 44 | "name": "a", 45 | "type": "tensor" 46 | }, 47 | { 48 | "start": 1, 49 | "name": "b", 50 | "type": "tensor" 51 | } 52 | ], 53 | "attrs": [ 54 | { 55 | "tfName": "adj_x", 56 | "name": "transposeA", 57 | "type": "bool", 58 | "defaultValue": false 59 | }, 60 | { 61 | "tfName": "adj_y", 62 | "name": "transposeB", 63 | "type": "bool", 64 | "defaultValue": false 65 | }, 66 | { 67 | "tfName": "T", 68 | "name": "dtype", 69 | "type": "dtype", 70 | "notSupported": true 71 | } 72 | ] 73 | }, 74 | { 75 | "tfOpName": "BatchMatMulV2", 76 | "category": "matrices", 77 | "inputs": [ 78 | { 79 | "start": 0, 80 | "name": "a", 81 | "type": "tensor" 82 | }, 83 | { 84 | "start": 1, 85 | "name": "b", 86 | "type": "tensor" 87 | } 88 | ], 89 | "attrs": [ 90 | { 91 | "tfName": "adj_x", 92 | "name": "transposeA", 93 | "type": "bool", 94 | "defaultValue": false 95 | }, 96 | { 97 | "tfName": "adj_y", 98 | "name": "transposeB", 99 | "type": "bool", 100 | "defaultValue": false 101 | }, 102 | { 103 | "tfName": "T", 104 | "name": "dtype", 105 | "type": "dtype", 106 | "notSupported": true 107 | } 108 | ] 109 | }, 110 | { 111 | "tfOpName": "Transpose", 112 | "category": "matrices", 113 | "inputs": [ 114 | { 115 | "start": 0, 116 | "name": "x", 117 | "type": "tensor" 118 | }, 119 | { 120 | "start": 1, 121 | "name": "perm", 122 | "type": "number[]" 123 | } 124 | ], 125 | "attrs": [ 126 | { 127 | "tfName": "T", 128 | "name": "dtype", 129 | "type": "dtype", 130 | "notSupported": true 131 | } 132 | ] 133 | } 134 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/reduction.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "Max", 4 | "category": "reduction", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "x", 9 | "type": "tensor" 10 | }, 11 | { 12 | "start": 1, 13 | "name": "axis", 14 | "type": "number[]" 15 | } 16 | ], 17 | "attrs": [ 18 | { 19 | "tfName": "keep_dims", 20 | "name": "keepDims", 21 | "type": "bool" 22 | } 23 | ] 24 | }, 25 | { 26 | "tfOpName": "Mean", 27 | "category": "reduction", 28 | "inputs": [ 29 | { 30 | "start": 0, 31 | "name": "x", 32 | "type": "tensor" 33 | }, 34 | { 35 | "start": 1, 36 | "name": "axis", 37 | "type": "number[]" 38 | } 39 | ], 40 | "attrs": [ 41 | { 42 | "tfName": "keep_dims", 43 | "name": "keepDims", 44 | "type": "bool" 45 | } 46 | ] 47 | }, 48 | { 49 | "tfOpName": "Min", 50 | "category": "reduction", 51 | "inputs": [ 52 | { 53 | "start": 0, 54 | "name": "x", 55 | "type": "tensor" 56 | }, 57 | { 58 | "start": 1, 59 | "name": "axis", 60 | "type": "number[]" 61 | } 62 | ], 63 | "attrs": [ 64 | { 65 | "tfName": "keep_dims", 66 | "name": "keepDims", 67 | "type": "bool" 68 | } 69 | ] 70 | }, 71 | { 72 | "tfOpName": "Sum", 73 | "category": "reduction", 74 | "inputs": [ 75 | { 76 | "start": 0, 77 | "name": "x", 78 | "type": "tensor" 79 | }, 80 | { 81 | "start": 1, 82 | "name": "axis", 83 | "type": "number[]" 84 | } 85 | ], 86 | "attrs": [ 87 | { 88 | "tfName": "keep_dims", 89 | "name": "keepDims", 90 | "type": "bool" 91 | } 92 | ] 93 | }, 94 | { 95 | "tfOpName": "All", 96 | "category": "reduction", 97 | "inputs": [ 98 | { 99 | "start": 0, 100 | "name": "x", 101 | "type": "tensor" 102 | }, 103 | { 104 | "start": 1, 105 | "name": "axis", 106 | "type": "number[]" 107 | } 108 | ], 109 | "attrs": [ 110 | { 111 | "tfName": "keep_dims", 112 | "name": "keepDims", 113 | "type": "bool" 114 | } 115 | ] 116 | }, 117 | { 118 | "tfOpName": "Any", 119 | "category": "reduction", 120 | "inputs": [ 121 | { 122 | "start": 0, 123 | "name": "x", 124 | "type": "tensor" 125 | }, 126 | { 127 | "start": 1, 128 | "name": "axis", 129 | "type": "number[]" 130 | } 131 | ], 132 | "attrs": [ 133 | { 134 | "tfName": "keep_dims", 135 | "name": "keepDims", 136 | "type": "bool" 137 | } 138 | ] 139 | }, 140 | { 141 | "tfOpName": "ArgMax", 142 | "category": "reduction", 143 | "inputs": [ 144 | { 145 | "start": 0, 146 | "name": "x", 147 | "type": "tensor" 148 | }, 149 | { 150 | "start": 1, 151 | "name": "axis", 152 | "type": "number" 153 | } 154 | ] 155 | }, 156 | { 157 | "tfOpName": "ArgMin", 158 | "category": "reduction", 159 | "inputs": [ 160 | { 161 | "start": 0, 162 | "name": "x", 163 | "type": "tensor" 164 | }, 165 | { 166 | "start": 1, 167 | "name": "axis", 168 | "type": "number" 169 | } 170 | ] 171 | }, 172 | { 173 | "tfOpName": "Prod", 174 | "category": "reduction", 175 | "inputs": [ 176 | { 177 | "start": 0, 178 | "name": "x", 179 | "type": "tensor" 180 | }, 181 | { 182 | "start": 1, 183 | "name": "axis", 184 | "type": "number[]" 185 | } 186 | ], 187 | "attrs": [ 188 | { 189 | "tfName": "keep_dims", 190 | "name": "keepDims", 191 | "type": "bool" 192 | } 193 | ] 194 | } 195 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/spectral.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "FFT", 4 | "category": "spectral", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "x", 9 | "type": "tensor" 10 | } 11 | ] 12 | }, 13 | { 14 | "tfOpName": "IFFT", 15 | "category": "spectral", 16 | "inputs": [ 17 | { 18 | "start": 0, 19 | "name": "x", 20 | "type": "tensor" 21 | } 22 | ] 23 | }, 24 | { 25 | "tfOpName": "RFFT", 26 | "category": "spectral", 27 | "inputs": [ 28 | { 29 | "start": 0, 30 | "name": "x", 31 | "type": "tensor" 32 | }, 33 | { 34 | "start": 1, 35 | "name": "fft_length", 36 | "type": "number", 37 | "notSupported": true 38 | } 39 | ] 40 | }, 41 | { 42 | "tfOpName": "IRFFT", 43 | "category": "spectral", 44 | "inputs": [ 45 | { 46 | "start": 0, 47 | "name": "x", 48 | "type": "tensor" 49 | }, 50 | { 51 | "start": 1, 52 | "name": "fft_length", 53 | "type": "number", 54 | "notSupported": true 55 | } 56 | ] 57 | } 58 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/op_list/transformation.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tfOpName": "Cast", 4 | "category": "transformation", 5 | "inputs": [ 6 | { 7 | "start": 0, 8 | "name": "x", 9 | "type": "tensor" 10 | } 11 | ], 12 | "attrs": [ 13 | { 14 | "tfName": "SrcT", 15 | "name": "sdtype", 16 | "type": "dtype", 17 | "notSupported": true 18 | }, 19 | { 20 | "tfName": "DstT", 21 | "name": "dtype", 22 | "type": "dtype" 23 | } 24 | ] 25 | }, 26 | { 27 | "tfOpName": "ExpandDims", 28 | "category": "transformation", 29 | "inputs": [ 30 | { 31 | "start": 0, 32 | "name": "x", 33 | "type": "tensor" 34 | }, 35 | { 36 | "start": 1, 37 | "name": "axis", 38 | "type": "number" 39 | } 40 | ] 41 | }, 42 | { 43 | "tfOpName": "Pad", 44 | "category": "transformation", 45 | "inputs": [ 46 | { 47 | "start": 0, 48 | "name": "x", 49 | "type": "tensor" 50 | }, 51 | { 52 | "start": 1, 53 | "name": "padding", 54 | "type": "number[]" 55 | } 56 | ], 57 | "attrs": [ 58 | { 59 | "tfName": "constant_value", 60 | "name": "constantValue", 61 | "type": "number", 62 | "defaultValue": 0 63 | } 64 | ] 65 | }, 66 | { 67 | "tfOpName": "PadV2", 68 | "category": "transformation", 69 | "inputs": [ 70 | { 71 | "start": 0, 72 | "name": "x", 73 | "type": "tensor" 74 | }, 75 | { 76 | "start": 1, 77 | "name": "padding", 78 | "type": "number[]" 79 | }, 80 | { 81 | "start": 2, 82 | "name": "constantValue", 83 | "type": "number", 84 | "defaultValue": 0 85 | } 86 | ] 87 | }, 88 | { 89 | "tfOpName": "Reshape", 90 | "category": "transformation", 91 | "inputs": [ 92 | { 93 | "start": 0, 94 | "name": "x", 95 | "type": "tensor" 96 | }, 97 | { 98 | "start": 1, 99 | "name": "shape", 100 | "type": "number[]" 101 | } 102 | ] 103 | }, 104 | { 105 | "tfOpName": "Squeeze", 106 | "category": "transformation", 107 | "inputs": [ 108 | { 109 | "start": 0, 110 | "name": "x", 111 | "type": "tensor" 112 | } 113 | ], 114 | "attrs": [ 115 | { 116 | "tfName": "axis", 117 | "tfDeprecatedName": "squeeze_dims", 118 | "name": "axis", 119 | "type": "number[]" 120 | } 121 | ] 122 | }, 123 | { 124 | "tfOpName": "SpaceToBatchND", 125 | "category": "transformation", 126 | "inputs": [ 127 | { 128 | "start": 0, 129 | "name": "x", 130 | "type": "tensor" 131 | }, 132 | { 133 | "start": 1, 134 | "name": "blockShape", 135 | "type": "number[]" 136 | }, 137 | { 138 | "start": 2, 139 | "name": "paddings", 140 | "type": "number[]" 141 | } 142 | ] 143 | }, 144 | { 145 | "tfOpName": "BatchToSpaceND", 146 | "category": "transformation", 147 | "inputs": [ 148 | { 149 | "start": 0, 150 | "name": "x", 151 | "type": "tensor" 152 | }, 153 | { 154 | "start": 1, 155 | "name": "blockShape", 156 | "type": "number[]" 157 | }, 158 | { 159 | "start": 2, 160 | "name": "crops", 161 | "type": "number[]" 162 | } 163 | ] 164 | }, 165 | { 166 | "tfOpName": "DepthToSpace", 167 | "category": "transformation", 168 | "inputs": [ 169 | { 170 | "start": 0, 171 | "name": "x", 172 | "type": "tensor" 173 | } 174 | ], 175 | "attrs": [ 176 | { 177 | "tfName": "block_size", 178 | "name": "blockSize", 179 | "type": "number" 180 | }, 181 | { 182 | "tfName": "data_format", 183 | "name": "dataFormat", 184 | "type": "string" 185 | } 186 | ] 187 | } 188 | ] -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/quantization_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | from __future__ import absolute_import 16 | from __future__ import division 17 | from __future__ import print_function 18 | 19 | import unittest 20 | 21 | import numpy as np 22 | 23 | from tensorflowjs import quantization 24 | 25 | class TestQuantizationUtil(unittest.TestCase): 26 | 27 | def _runQuantizeTest( 28 | self, range_min, range_max, data_dtype, quantization_dtype, 29 | expected_scale): 30 | d = np.arange(range_min, range_max + 1, dtype=data_dtype) 31 | q, s, m = quantization.quantize_weights(d, quantization_dtype) 32 | self.assertAlmostEqual(s, expected_scale) 33 | self.assertEqual(q.dtype, quantization_dtype) 34 | 35 | de_q = quantization.dequantize_weights(q, s, m, data_dtype) 36 | np.testing.assert_allclose(de_q, d) 37 | 38 | if range_min <= 0 <= range_max: 39 | d_0 = np.zeros(1, data_dtype) 40 | q_0 = np.round((d_0 - m) / s).astype(quantization_dtype) 41 | self.assertEqual( 42 | quantization.dequantize_weights(q_0, s, m, data_dtype), d_0) 43 | 44 | def testAllEqual(self): 45 | d = np.ones(5, dtype=np.float32) 46 | q, s, m = quantization.quantize_weights(d, np.uint8) 47 | self.assertEqual(s, 1.0) 48 | self.assertEqual(q.dtype, np.uint8) 49 | 50 | de_q = quantization.dequantize_weights(q, s, m, np.float32) 51 | np.testing.assert_array_equal(de_q, d) 52 | 53 | def testQuantizeNegativeFloats(self): 54 | self._runQuantizeTest(-3, -1, np.float32, np.uint8, expected_scale=2/255) 55 | self._runQuantizeTest(-3, -1, np.float32, np.uint16, expected_scale=2/65536) 56 | 57 | def testQuantizeNegativeAndZeroFloats(self): 58 | self._runQuantizeTest(-3, 0, np.float32, np.uint8, expected_scale=3/255) 59 | self._runQuantizeTest(-3, 0, np.float32, np.uint16, expected_scale=3/65536) 60 | 61 | def testQuantizeNegativeAndPositiveFloats(self): 62 | self._runQuantizeTest(-3, 3, np.float32, np.uint8, expected_scale=6/255) 63 | self._runQuantizeTest(-3, 3, np.float32, np.uint16, expected_scale=6/65536) 64 | 65 | def testQuantizeZeroAndPositiveFloats(self): 66 | self._runQuantizeTest(0, 3, np.float32, np.uint8, expected_scale=3/255) 67 | self._runQuantizeTest(0, 3, np.float32, np.uint16, expected_scale=3/65536) 68 | 69 | def testQuantizePositiveFloats(self): 70 | self._runQuantizeTest(1, 3, np.float32, np.uint8, expected_scale=2/255) 71 | self._runQuantizeTest(1, 3, np.float32, np.uint16, expected_scale=2/65536) 72 | 73 | def testQuantizeNegativeInts(self): 74 | self._runQuantizeTest(-3, -1, np.int32, np.uint8, expected_scale=2/255) 75 | self._runQuantizeTest(-3, -1, np.int32, np.uint16, expected_scale=2/65536) 76 | 77 | def testQuantizeNegativeAndZeroInts(self): 78 | self._runQuantizeTest(-3, 0, np.int32, np.uint8, expected_scale=3/255) 79 | self._runQuantizeTest(-3, 0, np.int32, np.uint16, expected_scale=3/65536) 80 | 81 | def testQuantizeNegativeAndPositiveInts(self): 82 | self._runQuantizeTest(-3, 3, np.int32, np.uint8, expected_scale=6/255) 83 | self._runQuantizeTest(-3, 3, np.int32, np.uint16, expected_scale=6/65536) 84 | 85 | def testQuantizeZeroAndPositiveInts(self): 86 | self._runQuantizeTest(0, 3, np.int32, np.uint8, expected_scale=3/255) 87 | self._runQuantizeTest(0, 3, np.int32, np.uint16, expected_scale=3/65536) 88 | 89 | def testQuantizePositiveInts(self): 90 | self._runQuantizeTest(1, 3, np.int32, np.uint8, expected_scale=2/255) 91 | self._runQuantizeTest(1, 3, np.int32, np.uint16, expected_scale=2/65536) 92 | 93 | 94 | if __name__ == '__main__': 95 | unittest.main() 96 | -------------------------------------------------------------------------------- /tfjs-converter/python/tensorflowjs/version.py: -------------------------------------------------------------------------------- 1 | # @license See the LICENSE file. 2 | 3 | # This code is auto-generated, do not modify this file! 4 | version = '1.2.7' 5 | -------------------------------------------------------------------------------- /tfjs-converter/rollup.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import node from 'rollup-plugin-node-resolve'; 19 | import typescript from 'rollup-plugin-typescript2'; 20 | import commonjs from 'rollup-plugin-commonjs'; 21 | import uglify from 'rollup-plugin-uglify'; 22 | 23 | const PREAMBLE = `/** 24 | * @license 25 | * Copyright ${(new Date).getFullYear()} Google LLC. All Rights Reserved. 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | * ============================================================================= 38 | */`; 39 | 40 | function minify() { 41 | return uglify({ 42 | output: {preamble: PREAMBLE} 43 | }); 44 | } 45 | 46 | function config({plugins = [], output = {}}) { 47 | return { 48 | input: 'src/index.ts', 49 | plugins: [ 50 | typescript({ 51 | tsconfigOverride: {compilerOptions: {module: 'ES2015'}} 52 | }), 53 | node(), 54 | // Polyfill require() from dependencies. 55 | commonjs({ 56 | namedExports: { 57 | './src/data/compiled_api.js': ['tensorflow'], 58 | './node_modules/protobufjs/minimal.js': ['roots', 'Reader', 'util'] 59 | } 60 | }), 61 | ...plugins 62 | ], 63 | output: { 64 | banner: PREAMBLE, 65 | sourcemap: true, 66 | globals: {'@tensorflow/tfjs-core': 'tf'}, 67 | ...output 68 | }, 69 | external: ['@tensorflow/tfjs-core'], 70 | onwarn: warning => { 71 | let {code} = warning; 72 | if (code === 'CIRCULAR_DEPENDENCY' || 73 | code === 'CIRCULAR' || code === 'EVAL') { 74 | return; 75 | } 76 | console.warn('WARNING: ', warning.toString()); 77 | } 78 | }; 79 | } 80 | 81 | export default [ 82 | config({ 83 | output: { 84 | format: 'umd', 85 | name: 'tf', 86 | extend: true, 87 | file: 'dist/tf-converter.js' 88 | } 89 | }), 90 | config({ 91 | plugins: [minify()], 92 | output: { 93 | format: 'umd', 94 | name: 'tf', 95 | extend: true, 96 | file: 'dist/tf-converter.min.js' 97 | } 98 | }), 99 | config({ 100 | plugins: [minify()], 101 | output: { 102 | format: 'es', 103 | file: 'dist/tf-converter.esm.js' 104 | } 105 | }) 106 | ]; 107 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/build-npm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2018 Google LLC. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ============================================================================= 16 | 17 | # Exit immediately if a command exits with a non-zero status. 18 | set -e 19 | 20 | rimraf dist/ 21 | yarn 22 | yarn build 23 | rollup -c 24 | 25 | # Use minified files for miniprogram 26 | mkdir dist/miniprogram 27 | cp dist/tf-converter.min.js dist/miniprogram/index.js 28 | cp dist/tf-converter.min.js.map dist/miniprogram/index.js.map 29 | 30 | echo "Stored standalone library at dist/tf-converter(.min).js" 31 | npm pack 32 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/gen_json.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as fs from 'fs'; 19 | import * as path from 'path'; 20 | 21 | // tslint:disable-next-line:no-require-imports 22 | const deepEqual = require('deep-equal'); 23 | 24 | /** 25 | * Converts the ts files in src/operations/op_list/* to json files and stores 26 | * them in python/tensorflowjs/op_list/. These are then used by the python 27 | * converter. 28 | * 29 | * If this script is called with the `--test` flag, will perform consistency 30 | * test between the two directories instead of actual file sync'ing. 31 | */ 32 | 33 | // Make the directory python/tensorflowjs/op_list/ if it doesn't exist. 34 | const destDir = './python/tensorflowjs/op_list/'; 35 | if (!fs.existsSync(destDir)) { 36 | fs.mkdirSync(destDir); 37 | } 38 | 39 | // Go over all .ts files in src/operations/op_list and convert them to json. 40 | const srcDir = './src/operations/op_list'; 41 | const fileNames = fs.readdirSync(srcDir); 42 | 43 | const testing = process.argv.indexOf('--test') !== -1; 44 | 45 | const tsFilesNamesWithJSONs: string[] = []; 46 | fileNames.forEach(fileName => { 47 | const srcPath = path.join(srcDir, fileName); 48 | if (srcPath.endsWith('_test.ts')) { 49 | return; 50 | } 51 | const m = require('../' + srcPath); 52 | if (m.json == null) { 53 | console.log(`Ignored ${srcPath} due to absent "json" field.`); 54 | return; 55 | } 56 | tsFilesNamesWithJSONs.push(path.basename(srcPath)); 57 | const destPath = path.join(destDir, fileName.replace('.ts', '.json')); 58 | if (testing) { 59 | if (!fs.existsSync(destPath) || !fs.lstatSync(destPath).isFile()) { 60 | throw new Error( 61 | `Op JSON consistency test failed: Missing file ${destPath}. ` + 62 | `You may want to run: yarn gen-json`); 63 | } 64 | const destJSON = JSON.parse(fs.readFileSync(destPath, {encoding: 'utf8'})); 65 | if (!deepEqual(m.json, destJSON)) { 66 | throw new Error( 67 | `JSON content of ${destPath} does not match TypeScript file ` + 68 | `${srcPath}. Run the following command to make sure they are ` + 69 | `in sync: yarn gen-json`); 70 | } 71 | } else { 72 | fs.writeFileSync(destPath, JSON.stringify(m.json, null, 2)); 73 | console.log('Generated', destPath); 74 | } 75 | }); 76 | 77 | if (testing) { 78 | const dirContent = fs.readdirSync(destDir); 79 | dirContent.forEach(itemPath => { 80 | if (!itemPath.endsWith('.json')) { 81 | throw new Error( 82 | `Found non-json file in directory ${destDir}: ${itemPath}`); 83 | } 84 | if (tsFilesNamesWithJSONs.indexOf(itemPath.replace('.json', '.ts')) === 85 | -1) { 86 | throw new Error(`Found extraneous .json file in ${destDir}: ${itemPath}`); 87 | } 88 | }); 89 | } 90 | 91 | console.log('Done!'); 92 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/make-version: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Copyright 2018 Google LLC. All Rights Reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // ============================================================================= 16 | 17 | var fs = require('fs'); 18 | 19 | var version = JSON.parse(fs.readFileSync('package.json', 'utf8')).version; 20 | 21 | const npmVersionCode = 22 | `/** @license See the LICENSE file. */ 23 | 24 | // This code is auto-generated, do not modify this file! 25 | const version = '${version}'; 26 | export {version}; 27 | ` 28 | 29 | fs.writeFile('src/version.ts', npmVersionCode, err => { 30 | if (err != null) { 31 | throw new Error(`Could not save npm version file ${version}: ${err}`); 32 | } 33 | console.log(`Version file for npm version ${version} saved sucessfully.`); 34 | }); 35 | 36 | const pipVersionCode = 37 | `# @license See the LICENSE file. 38 | 39 | # This code is auto-generated, do not modify this file! 40 | version = '${version}' 41 | ` 42 | fs.writeFile('python/tensorflowjs/version.py', pipVersionCode, err => { 43 | if (err != null) { 44 | throw new Error(`Could not save pip version file ${version}: ${err}`); 45 | } 46 | console.log(`Version file for pip version ${version} saved sucessfully.`); 47 | }); 48 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/publish-npm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2018 Google LLC. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ============================================================================= 16 | 17 | # Before you run this script, do this: 18 | # 1) Update the version in package.json 19 | # 2) Run ./scripts/make-version from the base dir of the project. 20 | # 3) Commit to the master branch. 21 | 22 | # Then: 23 | # 4) Run this script as `./scripts/publish-npm.sh` from the master branch. 24 | 25 | set -e 26 | 27 | BRANCH=`git rev-parse --abbrev-ref HEAD` 28 | 29 | if [ "$BRANCH" != "master" ]; then 30 | echo "Error: Switch to the master branch before tagging." 31 | exit 32 | fi 33 | 34 | yarn build-npm 35 | ./scripts/make-version # This is for safety in case you forgot to do 2). 36 | ./scripts/tag-version 37 | npm publish 38 | echo 'Yay! Published a new package to npm.' 39 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/tag-version: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Copyright 2018 Google LLC. All Rights Reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // ============================================================================= 16 | 17 | 18 | // Run this script from the base directory (not the script directory): 19 | // ./scripts/tag-version 20 | 21 | var fs = require('fs'); 22 | var exec = require('child_process').exec; 23 | 24 | var version = JSON.parse(fs.readFileSync('package.json', 'utf8')).version; 25 | var tag = `v${version}`; 26 | 27 | exec(`git tag ${tag}`, err => { 28 | if (err) { 29 | throw new Error(`Could not git tag with ${tag}: ${err.message}.`); 30 | } 31 | console.log(`Successfully tagged with ${tag}.`); 32 | }); 33 | 34 | exec(`git push --tags`, err => { 35 | if (err) { 36 | throw new Error(`Could not push git tags: ${err.message}.`); 37 | } 38 | console.log(`Successfully pushed tags.`); 39 | }); 40 | -------------------------------------------------------------------------------- /tfjs-converter/scripts/test_snippets.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | import {parseAndEvaluateSnippets} from '@tensorflow/tfjs-core/dist/scripts/test_snippets/util'; 19 | 20 | import * as tfconv from '../src/index'; 21 | 22 | const tf = { 23 | ...tfconv, 24 | ...tfc 25 | }; 26 | parseAndEvaluateSnippets(tf); 27 | -------------------------------------------------------------------------------- /tfjs-converter/src/data/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import {DataType, Tensor} from '@tensorflow/tfjs-core'; 18 | import {TensorArray} from '../executor/tensor_array'; 19 | 20 | export type NamedTensorMap = { 21 | [key: string]: Tensor 22 | }; 23 | 24 | export type NamedTensorsMap = { 25 | [key: string]: Tensor[] 26 | }; 27 | 28 | export type TensorArrayMap = { 29 | [key: number]: TensorArray 30 | }; 31 | 32 | export interface TensorInfo { 33 | name: string; 34 | shape?: number[]; 35 | dtype: DataType; 36 | } 37 | -------------------------------------------------------------------------------- /tfjs-converter/src/executor/execution_context_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import {ExecutionContext} from './execution_context'; 19 | import {TensorArray} from './tensor_array'; 20 | 21 | let context: ExecutionContext; 22 | let tensorArray: TensorArray; 23 | describe('ExecutionContext', () => { 24 | beforeEach(() => { 25 | context = new ExecutionContext({}, {}); 26 | }); 27 | 28 | it('should initialize', () => { 29 | expect(context.currentContext).toEqual([ 30 | {id: 0, frameName: '', iterationId: 0} 31 | ]); 32 | expect(context.currentContextId).toEqual(''); 33 | }); 34 | 35 | describe('tensor array', () => { 36 | beforeEach(() => { 37 | tensorArray = new TensorArray('', 'float32', 10, [1], true, true, true); 38 | }); 39 | 40 | it('should be able to add tensor array', () => { 41 | context.addTensorArray(tensorArray); 42 | expect(context.getTensorArray(tensorArray.id)).toBe(tensorArray); 43 | }); 44 | 45 | it('should be able to read tensor array', () => { 46 | expect(context.getTensorArray(tensorArray.id)).toBeUndefined(); 47 | }); 48 | }); 49 | 50 | describe('enterFrame', () => { 51 | it('should add new Frame', () => { 52 | context.enterFrame('1'); 53 | expect(context.currentContextId).toEqual('/1-0'); 54 | expect(context.currentContext).toEqual([ 55 | {id: 0, frameName: '', iterationId: 0}, 56 | {id: 1, frameName: '1', iterationId: 0} 57 | ]); 58 | }); 59 | }); 60 | 61 | describe('exitFrame', () => { 62 | it('should remove Frame', () => { 63 | context.enterFrame('1'); 64 | context.exitFrame(); 65 | 66 | expect(context.currentContextId).toEqual(''); 67 | expect(context.currentContext).toEqual([ 68 | {id: 0, frameName: '', iterationId: 0} 69 | ]); 70 | }); 71 | 72 | it('should remember previous Frame', () => { 73 | context.enterFrame('1'); 74 | context.nextIteration(); 75 | context.enterFrame('2'); 76 | context.exitFrame(); 77 | 78 | expect(context.currentContextId).toEqual('/1-1'); 79 | expect(context.currentContext).toEqual([ 80 | {id: 0, frameName: '', iterationId: 0}, 81 | {id: 2, frameName: '1', iterationId: 1} 82 | ]); 83 | }); 84 | }); 85 | 86 | describe('nextIteration', () => { 87 | it('should increate iteration', () => { 88 | context.enterFrame('1'); 89 | context.nextIteration(); 90 | 91 | expect(context.currentContextId).toEqual('/1-1'); 92 | expect(context.currentContext).toEqual([ 93 | {id: 0, frameName: '', iterationId: 0}, 94 | {id: 2, frameName: '1', iterationId: 1} 95 | ]); 96 | }); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /tfjs-converter/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | export {GraphModel, loadGraphModel} from './executor/graph_model'; 18 | export {deregisterOp, registerOp} from './operations/custom_op/register'; 19 | export {GraphNode, OpExecutor} from './operations/types'; 20 | export {version as version_converter} from './version'; 21 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/custom_op/node_value_impl.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import {DataType, Tensor} from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {getTensor} from '../executors/utils'; 23 | import {getBoolArrayParam, getBoolParam, getDtypeArrayParam, getDtypeParam, getNumberParam, getNumericArrayParam, getStringArrayParam, getStringParam, getTensorShapeArrayParam, getTensorShapeParam} from '../operation_mapper'; 24 | import {GraphNode, Node, ValueType} from '../types'; 25 | 26 | /** 27 | * Helper class for lookup inputs and params for nodes in the model graph. 28 | */ 29 | export class NodeValueImpl implements GraphNode { 30 | public readonly inputs: Tensor[] = []; 31 | public readonly attrs: {[key: string]: ValueType} = {}; 32 | constructor( 33 | private node: Node, private tensorMap: NamedTensorsMap, 34 | private context: ExecutionContext) { 35 | this.inputs = node.inputNames.map(name => this.getInput(name)); 36 | if (node.rawAttrs != null) { 37 | this.attrs = Object.keys(node.rawAttrs) 38 | .reduce((attrs: {[key: string]: ValueType}, key) => { 39 | attrs[key] = this.getAttr(key); 40 | return attrs; 41 | }, {}); 42 | } 43 | } 44 | 45 | /** 46 | * Return the value of the attribute or input param. 47 | * @param name String: name of attribute or input param. 48 | */ 49 | private getInput(name: string): Tensor { 50 | return getTensor(name, this.tensorMap, this.context); 51 | } 52 | 53 | /** 54 | * Return the value of the attribute or input param. 55 | * @param name String: name of attribute or input param. 56 | */ 57 | private getAttr(name: string, defaultValue?: ValueType): ValueType { 58 | const value = this.node.rawAttrs[name]; 59 | if (value.tensor != null) { 60 | return getTensor(name, this.tensorMap, this.context); 61 | } 62 | if (value.i != null || value.f != null) { 63 | return getNumberParam(this.node.rawAttrs, name, defaultValue as number); 64 | } 65 | if (value.s != null) { 66 | return getStringParam(this.node.rawAttrs, name, defaultValue as string); 67 | } 68 | if (value.b != null) { 69 | return getBoolParam(this.node.rawAttrs, name, defaultValue as boolean); 70 | } 71 | if (value.shape != null) { 72 | return getTensorShapeParam( 73 | this.node.rawAttrs, name, defaultValue as number[]); 74 | } 75 | if (value.type != null) { 76 | return getDtypeParam(this.node.rawAttrs, name, defaultValue as DataType); 77 | } 78 | if (value.list != null) { 79 | if (value.list.i != null || value.list.f != null) { 80 | return getNumericArrayParam( 81 | this.node.rawAttrs, name, defaultValue as number[]); 82 | } 83 | if (value.list.s != null) { 84 | return getStringArrayParam( 85 | this.node.rawAttrs, name, defaultValue as string[]); 86 | } 87 | if (value.list.shape != null) { 88 | return getTensorShapeArrayParam( 89 | this.node.rawAttrs, name, defaultValue as number[][]); 90 | } 91 | if (value.list.b != null) { 92 | return getBoolArrayParam( 93 | this.node.rawAttrs, name, defaultValue as boolean[]); 94 | } 95 | if (value.list.type != null) { 96 | return getDtypeArrayParam( 97 | this.node.rawAttrs, name, defaultValue as DataType[]); 98 | } 99 | } 100 | 101 | return defaultValue; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/custom_op/node_value_impl_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import {scalar, test_util} from '@tensorflow/tfjs-core'; 18 | 19 | import * as tensorflow from '../../data/compiled_api'; 20 | import {ExecutionContext} from '../../executor/execution_context'; 21 | import {Node} from '../types'; 22 | 23 | import {NodeValueImpl} from './node_value_impl'; 24 | 25 | const NODE: Node = { 26 | name: 'test', 27 | op: 'const', 28 | category: 'custom', 29 | inputNames: ['a', 'b'], 30 | inputs: [], 31 | inputParams: {}, 32 | attrParams: {}, 33 | children: [], 34 | rawAttrs: { 35 | c: {tensor: {}}, 36 | d: {i: 3}, 37 | e: {s: 'TkhXQw=='}, 38 | f: {type: tensorflow.DataType.DT_FLOAT}, 39 | g: {b: true}, 40 | h: {f: 4.5}, 41 | i: {list: {i: [3, 6, 0]}}, 42 | j: {list: {f: [4.5, 5.5, 0.0]}}, 43 | k: {list: {s: ['TkhXQw==', 'TkhXQw==', '']}}, 44 | l: { 45 | list: 46 | {type: [tensorflow.DataType.DT_FLOAT, tensorflow.DataType.DT_INT32]} 47 | }, 48 | m: {shape: {dim: [{name: 'a', size: 1}, {name: 'b', size: 2}]}}, 49 | n: { 50 | list: { 51 | shape: [ 52 | {dim: [{name: 'a', size: 1}, {name: 'b', size: 2}]}, 53 | {dim: [{name: 'c', size: 2}, {name: 'd', size: 3}]} 54 | ] 55 | } 56 | }, 57 | o: {list: {b: [true, false]}} 58 | } 59 | }; 60 | const TENSOR_MAP = { 61 | 'a': [scalar(1)], 62 | 'b': [scalar(2)], 63 | 'test': [scalar(3)] 64 | }; 65 | 66 | let nodeValue: NodeValueImpl; 67 | describe('NodeValueImpl', () => { 68 | beforeEach(() => { 69 | nodeValue = 70 | new NodeValueImpl(NODE, TENSOR_MAP, new ExecutionContext({}, {})); 71 | }); 72 | describe('getInput', () => { 73 | it('should find tensor from tensormap', async () => { 74 | const result = nodeValue.inputs[0]; 75 | test_util.expectArraysClose(await result.data(), [1]); 76 | 77 | const result2 = nodeValue.inputs[1]; 78 | test_util.expectArraysClose(await result2.data(), [2]); 79 | }); 80 | }); 81 | describe('getAttr', () => { 82 | it('should parse number', () => { 83 | expect(nodeValue.attrs['d']).toEqual(3); 84 | expect(nodeValue.attrs['h']).toEqual(4.5); 85 | }); 86 | it('should parse number[]', () => { 87 | expect(nodeValue.attrs['i']).toEqual([3, 6, 0]); 88 | expect(nodeValue.attrs['j']).toEqual([4.5, 5.5, 0.0]); 89 | }); 90 | it('should parse string', () => { 91 | expect(nodeValue.attrs['e']).toEqual('nhwc'); 92 | }); 93 | it('should parse string[]', () => { 94 | expect(nodeValue.attrs['k']).toEqual(['nhwc', 'nhwc', '']); 95 | }); 96 | it('should parse boolean', () => { 97 | expect(nodeValue.attrs['g']).toEqual(true); 98 | }); 99 | it('should parse boolean[]', () => { 100 | expect(nodeValue.attrs['o']).toEqual([true, false]); 101 | }); 102 | it('should parse dtype', () => { 103 | expect(nodeValue.attrs['f']).toEqual('float32'); 104 | }); 105 | it('should parse dtype[]', () => { 106 | expect(nodeValue.attrs['l']).toEqual(['float32', 'int32']); 107 | }); 108 | it('should parse tensor shape', () => { 109 | expect(nodeValue.attrs['m']).toEqual([1, 2]); 110 | }); 111 | it('should parse tensor shape[]', () => { 112 | expect(nodeValue.attrs['n']).toEqual([[1, 2], [2, 3]]); 113 | }); 114 | }); 115 | }); 116 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/custom_op/register.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @license 4 | * Copyright 2019 Google LLC. All Rights Reserved. 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * ============================================================================= 17 | */ 18 | 19 | import {OpExecutor, OpMapper} from '../types'; 20 | 21 | const CUSTOM_OPS: {[key: string]: OpMapper} = {}; 22 | 23 | /** 24 | * Register an Op for graph model executor. This allow you to register 25 | * TensorFlow custom op or override existing op. 26 | * 27 | * Here is an example of registering a new MatMul Op. 28 | * ```js 29 | * const customMatmul = (node) => 30 | * tf.matMul( 31 | * node.inputs[0], node.inputs[1], 32 | * node.attrs['transpose_a'], node.attrs['transpose_b']); 33 | * 34 | * tf.registerOp('MatMul', customMatmul); 35 | * ``` 36 | * The inputs and attrs of the node object is based on the TensorFlow op 37 | * registry. 38 | * 39 | * @param name The Tensorflow Op name. 40 | * @param opFunc An op function which is called with the current graph node 41 | * during execution and needs to return a tensor or a list of tensors. The node 42 | * has the following attributes: 43 | * - attr: A map from attribute name to its value 44 | * - inputs: A list of input tensors 45 | */ 46 | /** @doc {heading: 'Models', subheading: 'Op Registry'} */ 47 | export function registerOp(name: string, opFunc: OpExecutor) { 48 | const opMapper: OpMapper = { 49 | tfOpName: name, 50 | category: 'custom', 51 | inputs: [], 52 | attrs: [], 53 | customExecutor: opFunc 54 | }; 55 | 56 | CUSTOM_OPS[name] = opMapper; 57 | } 58 | 59 | /** 60 | * Retrieve the OpMapper object for the registered op. 61 | * 62 | * @param name The Tensorflow Op name. 63 | */ 64 | /** @doc {heading: 'Models', subheading: 'Op Registry'} */ 65 | 66 | export function getRegisteredOp(name: string): OpMapper { 67 | return CUSTOM_OPS[name]; 68 | } 69 | 70 | /** 71 | * Deregister the Op for graph model executor. 72 | * 73 | * @param name The Tensorflow Op name. 74 | */ 75 | /** @doc {heading: 'Models', subheading: 'Op Registry'} */ 76 | export function deregisterOp(name: string) { 77 | delete CUSTOM_OPS[name]; 78 | } 79 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/custom_op/register_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import {scalar} from '@tensorflow/tfjs-core'; 19 | 20 | import {deregisterOp, getRegisteredOp, registerOp} from './register'; 21 | 22 | describe('register custom op', () => { 23 | describe('registerCustomOp', () => { 24 | it('should auto fill missing fields', () => { 25 | const executor = () => scalar(1); 26 | registerOp('newOp', executor); 27 | const opMapper = getRegisteredOp('newOp'); 28 | expect(opMapper.tfOpName).toEqual('newOp'); 29 | expect(opMapper.category).toEqual('custom'); 30 | expect(opMapper.inputs).toEqual([]); 31 | expect(opMapper.attrs).toEqual([]); 32 | expect(opMapper.customExecutor).toEqual(executor); 33 | deregisterOp('newOp'); 34 | }); 35 | }); 36 | describe('deregisterOp', () => { 37 | it('should remove the custom op', () => { 38 | registerOp('newOp', () => scalar(1)); 39 | expect(getRegisteredOp('newOp')).toBeDefined(); 40 | deregisterOp('newOp'); 41 | expect(getRegisteredOp('newOp')).not.toBeDefined(); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/arithmetic_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'BiasAdd': 32 | case 'AddV2': 33 | case 'Add': { 34 | return [tfc.add( 35 | (getParamValue('a', node, tensorMap, context) as tfc.Tensor), 36 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 37 | } 38 | case 'AddN': { 39 | return [tfc.addN(( 40 | getParamValue('tensors', node, tensorMap, context) as tfc.Tensor[]))]; 41 | } 42 | case 'FloorMod': 43 | case 'Mod': 44 | return [tfc.mod( 45 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 46 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 47 | case 'Mul': 48 | return [tfc.mul( 49 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 50 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 51 | case 'RealDiv': 52 | case 'Div': { 53 | return [tfc.div( 54 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 55 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 56 | } 57 | case 'FloorDiv': { 58 | return [tfc.floorDiv( 59 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 60 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 61 | } 62 | case 'Sub': { 63 | return [tfc.sub( 64 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 65 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 66 | } 67 | case 'Minimum': { 68 | return [tfc.minimum( 69 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 70 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 71 | } 72 | case 'Maximum': { 73 | return [tfc.maximum( 74 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 75 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 76 | } 77 | case 'Pow': { 78 | return [tfc.pow( 79 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 80 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 81 | } 82 | case 'SquaredDifference': { 83 | return [tfc.squaredDifference( 84 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 85 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 86 | } 87 | default: 88 | throw TypeError(`Node type ${node.op} is not implemented`); 89 | } 90 | }; 91 | 92 | export const CATEGORY = 'arithmetic'; 93 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/arithmetic_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import {Node} from '../types'; 21 | import {executeOp} from './arithmetic_executor'; 22 | import {createTensorAttr, createTensorsAttr} from './test_helper'; 23 | 24 | describe('arithmetic', () => { 25 | let node: Node; 26 | const input1 = [tfc.scalar(1)]; 27 | const input2 = [tfc.scalar(1)]; 28 | const input3 = [tfc.scalar(4)]; 29 | const context = new ExecutionContext({}, {}); 30 | 31 | beforeEach(() => { 32 | node = { 33 | name: 'test', 34 | op: '', 35 | category: 'arithmetic', 36 | inputNames: ['input1', 'input2'], 37 | inputs: [], 38 | inputParams: {a: createTensorAttr(0), b: createTensorAttr(1)}, 39 | attrParams: {}, 40 | children: [] 41 | }; 42 | }); 43 | 44 | describe('executeOp', () => { 45 | ['Add', 'Mul', 'Div', 'Sub', 'Maximum', 'Minimum', 'Pow', 46 | 'SquaredDifference', 'Mod', 'FloorDiv'] 47 | .forEach((op => { 48 | it('should call tfc.' + op, () => { 49 | const spy = 50 | spyOn(tfc, op.charAt(0).toLowerCase() + op.slice(1) as 'add'); 51 | node.op = op; 52 | executeOp(node, {input1, input2}, context); 53 | 54 | expect(spy).toHaveBeenCalledWith(input1[0], input2[0]); 55 | }); 56 | })); 57 | 58 | it('AddV2', async () => { 59 | const spy = spyOn(tfc, 'add').and.callThrough(); 60 | node.op = 'AddV2'; 61 | const res = executeOp(node, {input1, input2}, context) as tfc.Tensor[]; 62 | expect(spy).toHaveBeenCalledWith(input1[0], input2[0]); 63 | expect(res[0].dtype).toBe('float32'); 64 | expect(res[0].shape).toEqual([]); 65 | tfc.test_util.expectArraysClose(await res[0].data(), 2); 66 | }); 67 | 68 | it('AddN', async () => { 69 | const spy = spyOn(tfc, 'addN').and.callThrough(); 70 | node.op = 'AddN'; 71 | node.inputParams = {tensors: createTensorsAttr(0, 0)}; 72 | node.inputNames = ['input1', 'input2', 'input3']; 73 | const res = 74 | executeOp(node, {input1, input2, input3}, context) as tfc.Tensor[]; 75 | expect(spy).toHaveBeenCalledWith([input1[0], input2[0], input3[0]]); 76 | expect(res[0].dtype).toBe('float32'); 77 | expect(res[0].shape).toEqual([]); 78 | tfc.test_util.expectArraysClose(await res[0].data(), [6]); 79 | }); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/dynamic_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google Inc. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {Node} from '../types'; 23 | import {getParamValue} from './utils'; 24 | 25 | export async function executeOp( 26 | node: Node, tensorMap: NamedTensorsMap, 27 | context: ExecutionContext): Promise { 28 | switch (node.op) { 29 | case 'NonMaxSuppressionV3': 30 | case 'NonMaxSuppressionV2': { 31 | const boxes = 32 | getParamValue('boxes', node, tensorMap, context) as tfc.Tensor; 33 | const scores = 34 | getParamValue('scores', node, tensorMap, context) as tfc.Tensor; 35 | const maxOutputSize = 36 | getParamValue('maxOutputSize', node, tensorMap, context) as number; 37 | const iouThreshold = 38 | getParamValue('iouThreshold', node, tensorMap, context) as number; 39 | const scoreThreshold = 40 | getParamValue('scoreThreshold', node, tensorMap, context) as number; 41 | return [await tfc.image.nonMaxSuppressionAsync( 42 | boxes as tfc.Tensor2D, scores as tfc.Tensor1D, maxOutputSize, 43 | iouThreshold, scoreThreshold)]; 44 | } 45 | case 'Where': { 46 | return [await tfc.whereAsync( 47 | getParamValue('condition', node, tensorMap, context) as tfc.Tensor)]; 48 | } 49 | case 'ListDiff': { 50 | return await tfc.setdiff1dAsync( 51 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 52 | getParamValue('y', node, tensorMap, context) as tfc.Tensor); 53 | } 54 | default: 55 | throw TypeError(`Node type ${node.op} is not implemented`); 56 | } 57 | } 58 | 59 | export const CATEGORY = 'dynamic'; 60 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/evaluation_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google Inc. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = 27 | (node: Node, tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): tfc.Tensor[] => { 29 | switch (node.op) { 30 | case 'TopKV2': { 31 | const x = getParamValue('x', node, tensorMap, context) as tfc.Tensor; 32 | const k = getParamValue('k', node, tensorMap, context) as number; 33 | const sorted = 34 | getParamValue('sorted', node, tensorMap, context) as boolean; 35 | const result = tfc.topk(x, k, sorted); 36 | return [result.values, result.indices]; 37 | } 38 | default: 39 | throw TypeError(`Node type ${node.op} is not implemented`); 40 | } 41 | }; 42 | 43 | export const CATEGORY = 'evaluation'; 44 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/evaluation_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google Inc. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import {Node} from '../types'; 21 | 22 | import {executeOp} from './evaluation_executor'; 23 | // tslint:disable-next-line:max-line-length 24 | import {createBoolAttr, createNumberAttrFromIndex, createTensorAttr} from './test_helper'; 25 | 26 | describe('evaluation', () => { 27 | let node: Node; 28 | const input1 = [tfc.tensor1d([1])]; 29 | const input2 = [tfc.scalar(1)]; 30 | const context = new ExecutionContext({}, {}); 31 | 32 | beforeEach(() => { 33 | node = { 34 | name: 'input1', 35 | op: '', 36 | category: 'evaluation', 37 | inputNames: ['input1', 'input2'], 38 | inputs: [], 39 | inputParams: {}, 40 | attrParams: {}, 41 | children: [] 42 | }; 43 | }); 44 | 45 | describe('executeOp', () => { 46 | describe('TopKV2', () => { 47 | it('should return input', () => { 48 | node.op = 'TopKV2'; 49 | node.inputParams['x'] = createTensorAttr(0); 50 | node.inputParams['k'] = createNumberAttrFromIndex(1); 51 | node.attrParams['sorted'] = createBoolAttr(true); 52 | spyOn(tfc, 'topk').and.callThrough(); 53 | executeOp(node, {input1, input2}, context); 54 | expect(tfc.topk).toHaveBeenCalledWith(input1[0], 1, true); 55 | }); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/graph_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue, getTensor} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'Const': { 32 | return tensorMap[node.name]; 33 | } 34 | case 'PlaceholderWithDefault': 35 | const def = 36 | getParamValue('default', node, tensorMap, context) as tfc.Tensor; 37 | return [getTensor(node.name, tensorMap, context) || def]; 38 | case 'Placeholder': 39 | return [getTensor(node.name, tensorMap, context)]; 40 | case 'Identity': 41 | case 'StopGradient': 42 | case 'FakeQuantWithMinMaxVars': // This op is currently ignored. 43 | return [ 44 | (getParamValue('x', node, tensorMap, context) as tfc.Tensor).clone() 45 | ]; 46 | case 'IdentityN': 47 | return (getParamValue('x', node, tensorMap, context) as tfc.Tensor[]) 48 | .map((t: tfc.Tensor) => t.clone()); 49 | case 'Snapshot': 50 | const snapshot = 51 | (getParamValue('x', node, tensorMap, context) as tfc.Tensor); 52 | return [snapshot.clone()]; 53 | case 'Shape': 54 | return [tfc.tensor1d( 55 | (getParamValue('x', node, tensorMap, context) as tfc.Tensor).shape, 56 | 'int32')]; 57 | case 'ShapeN': 58 | return (getParamValue('x', node, tensorMap, context) as tfc.Tensor[]) 59 | .map((t: tfc.Tensor) => tfc.tensor1d(t.shape)); 60 | case 'Size': 61 | return [tfc.scalar( 62 | (getParamValue('x', node, tensorMap, context) as tfc.Tensor).size, 63 | 'int32')]; 64 | case 'Rank': 65 | return [tfc.scalar( 66 | (getParamValue('x', node, tensorMap, context) as tfc.Tensor).rank, 67 | 'int32')]; 68 | case 'NoOp': 69 | return []; 70 | case 'Print': 71 | const input = getParamValue('x', node, tensorMap, context) as tfc.Tensor; 72 | const data = 73 | getParamValue('data', node, tensorMap, context) as tfc.Tensor[]; 74 | const message = 75 | getParamValue('message', node, tensorMap, context) as string; 76 | const summarize = 77 | getParamValue('summarize', node, tensorMap, context) as number; 78 | console.warn( 79 | 'The graph has a tf.print() operation,' + 80 | 'usually used for debugging, which slows down performance.'); 81 | console.log(message); 82 | for (let i = 0; i < data.length; i++) { 83 | console.log( 84 | Array.prototype.slice.call(data[i].dataSync()).slice(0, summarize)); 85 | } 86 | return [input]; 87 | 88 | default: 89 | throw TypeError(`Node type ${node.op} is not implemented`); 90 | } 91 | }; 92 | 93 | export const CATEGORY = 'graph'; 94 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/image_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google Inc. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'ResizeBilinear': { 32 | const images = 33 | getParamValue('images', node, tensorMap, context) as tfc.Tensor; 34 | const size = getParamValue('size', node, tensorMap, context) as number[]; 35 | const alignCorners = 36 | getParamValue('alignCorners', node, tensorMap, context) as boolean; 37 | return [tfc.image.resizeBilinear( 38 | images as tfc.Tensor3D | tfc.Tensor4D, [size[0], size[1]], 39 | alignCorners)]; 40 | } 41 | case 'ResizeNearestNeighbor': { 42 | const images = 43 | getParamValue('images', node, tensorMap, context) as tfc.Tensor; 44 | const size = getParamValue('size', node, tensorMap, context) as number[]; 45 | const alignCorners = 46 | getParamValue('alignCorners', node, tensorMap, context) as boolean; 47 | return [tfc.image.resizeNearestNeighbor( 48 | images as tfc.Tensor3D | tfc.Tensor4D, [size[0], size[1]], 49 | alignCorners)]; 50 | } 51 | case 'CropAndResize': { 52 | const image = 53 | getParamValue('image', node, tensorMap, context) as tfc.Tensor; 54 | const boxes = 55 | getParamValue('boxes', node, tensorMap, context) as tfc.Tensor; 56 | const boxInd = 57 | getParamValue('boxInd', node, tensorMap, context) as tfc.Tensor; 58 | const cropSize = 59 | getParamValue('cropSize', node, tensorMap, context) as number[]; 60 | const method = 61 | getParamValue('method', node, tensorMap, context) as string; 62 | const extrapolationValue = 63 | getParamValue('extrapolationValue', node, tensorMap, context) as 64 | number; 65 | return [tfc.image.cropAndResize( 66 | image as tfc.Tensor4D, boxes as tfc.Tensor2D, boxInd as tfc.Tensor1D, 67 | cropSize as [number, number], method as 'bilinear' | 'nearest', 68 | extrapolationValue)]; 69 | } 70 | default: 71 | throw TypeError(`Node type ${node.op} is not implemented`); 72 | } 73 | }; 74 | 75 | export const CATEGORY = 'image'; 76 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/logical_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'Equal': { 32 | return [tfc.equal( 33 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 34 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 35 | } 36 | case 'NotEqual': { 37 | return [tfc.notEqual( 38 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 39 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 40 | } 41 | case 'Greater': { 42 | return [tfc.greater( 43 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 44 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 45 | } 46 | case 'GreaterEqual': { 47 | return [tfc.greaterEqual( 48 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 49 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 50 | } 51 | case 'Less': { 52 | return [tfc.less( 53 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 54 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 55 | } 56 | case 'LessEqual': { 57 | return [tfc.lessEqual( 58 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 59 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 60 | } 61 | case 'LogicalAnd': { 62 | return [tfc.logicalAnd( 63 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 64 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 65 | } 66 | case 'LogicalNot': { 67 | return [tfc.logicalNot( 68 | getParamValue('a', node, tensorMap, context) as tfc.Tensor)]; 69 | } 70 | case 'LogicalOr': { 71 | return [tfc.logicalOr( 72 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 73 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 74 | } 75 | case 'Select': { 76 | return [tfc.where( 77 | getParamValue('condition', node, tensorMap, context) as tfc.Tensor, 78 | getParamValue('a', node, tensorMap, context) as tfc.Tensor, 79 | getParamValue('b', node, tensorMap, context) as tfc.Tensor)]; 80 | } 81 | default: 82 | throw TypeError(`Node type ${node.op} is not implemented`); 83 | } 84 | }; 85 | 86 | export const CATEGORY = 'logical'; 87 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/logical_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import {Node} from '../types'; 21 | 22 | import {executeOp} from './logical_executor'; 23 | import {createTensorAttr} from './test_helper'; 24 | 25 | describe('logical', () => { 26 | let node: Node; 27 | const input1 = [tfc.scalar(1)]; 28 | const input2 = [tfc.scalar(2)]; 29 | const context = new ExecutionContext({}, {}); 30 | 31 | beforeEach(() => { 32 | node = { 33 | name: 'test', 34 | op: '', 35 | category: 'logical', 36 | inputNames: ['input1', 'input2'], 37 | inputs: [], 38 | inputParams: {a: createTensorAttr(0), b: createTensorAttr(1)}, 39 | attrParams: {}, 40 | children: [] 41 | }; 42 | }); 43 | 44 | describe('executeOp', () => { 45 | ['Equal', 'NotEqual', 'Greater', 'GreaterEqual', 'Less', 'LessEqual', 46 | 'LogicalAnd', 'LogicalOr'] 47 | .forEach(op => { 48 | it('should call tfc.' + op, () => { 49 | const spy = 50 | spyOn(tfc, op.charAt(0).toLowerCase() + op.slice(1) as 'equal'); 51 | node.op = op; 52 | executeOp(node, {input1, input2}, context); 53 | 54 | expect(spy).toHaveBeenCalledWith(input1[0], input2[0]); 55 | }); 56 | }); 57 | describe('LogicalNot', () => { 58 | it('should call tfc.logicalNot', () => { 59 | spyOn(tfc, 'logicalNot'); 60 | node.op = 'LogicalNot'; 61 | executeOp(node, {input1}, context); 62 | 63 | expect(tfc.logicalNot).toHaveBeenCalledWith(input1[0]); 64 | }); 65 | }); 66 | 67 | describe('Select', () => { 68 | it('should call tfc.where', () => { 69 | spyOn(tfc, 'where'); 70 | node.op = 'Select'; 71 | node.inputNames = ['input1', 'input2', 'input3']; 72 | node.inputParams.condition = createTensorAttr(2); 73 | const input3 = [tfc.scalar(1)]; 74 | executeOp(node, {input1, input2, input3}, context); 75 | 76 | expect(tfc.where).toHaveBeenCalledWith(input3[0], input1[0], input2[0]); 77 | }); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/matrices_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'BatchMatMul': 32 | case 'BatchMatMulV2': 33 | case 'MatMul': 34 | return [tfc.matMul( 35 | getParamValue('a', node, tensorMap, context) as tfc.Tensor2D, 36 | getParamValue('b', node, tensorMap, context) as tfc.Tensor2D, 37 | getParamValue('transposeA', node, tensorMap, context) as boolean, 38 | getParamValue('transposeB', node, tensorMap, context) as boolean)]; 39 | case 'Transpose': 40 | return [tfc.transpose( 41 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 42 | getParamValue('perm', node, tensorMap, context) as number[])]; 43 | 44 | default: 45 | throw TypeError(`Node type ${node.op} is not implemented`); 46 | } 47 | }; 48 | 49 | export const CATEGORY = 'matrices'; 50 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/matrices_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import {Node} from '../types'; 21 | 22 | import {executeOp} from './matrices_executor'; 23 | // tslint:disable-next-line:max-line-length 24 | import {createBoolAttr, createNumericArrayAttr, createTensorAttr} from './test_helper'; 25 | 26 | describe('matrices', () => { 27 | let node: Node; 28 | const input1 = [tfc.scalar(1)]; 29 | const input2 = [tfc.scalar(2)]; 30 | const context = new ExecutionContext({}, {}); 31 | 32 | beforeEach(() => { 33 | node = { 34 | name: 'test', 35 | op: '', 36 | category: 'matrices', 37 | inputNames: ['input1', 'input2'], 38 | inputs: [], 39 | inputParams: {a: createTensorAttr(0), b: createTensorAttr(1)}, 40 | attrParams: {}, 41 | children: [] 42 | }; 43 | }); 44 | 45 | describe('executeOp', () => { 46 | describe('MatMul', () => { 47 | it('should call tfc.matMul', () => { 48 | spyOn(tfc, 'matMul'); 49 | node.op = 'MatMul'; 50 | node.attrParams.transposeA = createBoolAttr(true); 51 | node.attrParams.transposeB = createBoolAttr(false); 52 | executeOp(node, {input1, input2}, context); 53 | 54 | expect(tfc.matMul) 55 | .toHaveBeenCalledWith(input1[0], input2[0], true, false); 56 | }); 57 | }); 58 | describe('BatchMatMul', () => { 59 | it('should call tfc.matMul', () => { 60 | spyOn(tfc, 'matMul'); 61 | node.op = 'BatchMatMul'; 62 | node.attrParams.transposeA = createBoolAttr(true); 63 | node.attrParams.transposeB = createBoolAttr(false); 64 | executeOp(node, {input1, input2}, context); 65 | 66 | expect(tfc.matMul) 67 | .toHaveBeenCalledWith(input1[0], input2[0], true, false); 68 | }); 69 | }); 70 | describe('BatchMatMulV2', () => { 71 | it('should call tfc.matMul', () => { 72 | spyOn(tfc, 'matMul'); 73 | node.op = 'BatchMatMulV2'; 74 | node.attrParams.transposeA = createBoolAttr(true); 75 | node.attrParams.transposeB = createBoolAttr(false); 76 | executeOp(node, {input1, input2}, context); 77 | 78 | expect(tfc.matMul) 79 | .toHaveBeenCalledWith(input1[0], input2[0], true, false); 80 | }); 81 | }); 82 | describe('Transpose', () => { 83 | it('should call tfc.transpose', () => { 84 | spyOn(tfc, 'transpose'); 85 | node.op = 'Transpose'; 86 | node.inputNames = ['input1', 'input2', 'input3']; 87 | node.inputParams.x = createTensorAttr(0); 88 | node.attrParams.perm = createNumericArrayAttr([1, 2]); 89 | executeOp(node, {input1}, context); 90 | 91 | expect(tfc.transpose).toHaveBeenCalledWith(input1[0], [1, 2]); 92 | }); 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/normalization_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'FusedBatchNorm': 32 | case 'FusedBatchNormV2': { 33 | return [tfc.batchNorm( 34 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 35 | getParamValue('mean', node, tensorMap, context) as tfc.Tensor, 36 | getParamValue('variance', node, tensorMap, context) as tfc.Tensor, 37 | getParamValue('offset', node, tensorMap, context) as tfc.Tensor, 38 | getParamValue('scale', node, tensorMap, context) as tfc.Tensor, 39 | getParamValue('epsilon', node, tensorMap, context) as number)]; 40 | } 41 | case 'FusedBatchNormV3': { 42 | return [tfc.batchNorm( 43 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 44 | getParamValue('mean', node, tensorMap, context) as tfc.Tensor, 45 | getParamValue('variance', node, tensorMap, context) as tfc.Tensor, 46 | getParamValue('offset', node, tensorMap, context) as tfc.Tensor, 47 | getParamValue('scale', node, tensorMap, context) as tfc.Tensor, 48 | getParamValue('epsilon', node, tensorMap, context) as number)]; 49 | } 50 | case 'LRN': { 51 | return [tfc.localResponseNormalization( 52 | getParamValue('x', node, tensorMap, context) as tfc.Tensor3D | 53 | tfc.Tensor4D, 54 | getParamValue('radius', node, tensorMap, context) as number, 55 | getParamValue('bias', node, tensorMap, context) as number, 56 | getParamValue('alpha', node, tensorMap, context) as number, 57 | getParamValue('beta', node, tensorMap, context) as number)]; 58 | } 59 | case 'Softmax': { 60 | return [tfc.softmax( 61 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 62 | } 63 | case 'LogSoftmax': { 64 | return [tfc.logSoftmax( 65 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 66 | } 67 | case 'SparseToDense': { 68 | return [tfc.sparseToDense( 69 | getParamValue('sparseIndices', node, tensorMap, context) as 70 | tfc.Tensor, 71 | getParamValue('outputShape', node, tensorMap, context) as tfc.Tensor, 72 | getParamValue('sparseValues', node, tensorMap, context) as number[], 73 | getParamValue('defaultValue', node, tensorMap, context) as 74 | tfc.Scalar)]; 75 | } 76 | default: 77 | throw TypeError(`Node type ${node.op} is not implemented`); 78 | } 79 | }; 80 | 81 | export const CATEGORY = 'normalization'; 82 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/reduction_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'Max': { 32 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 33 | const keepDims = 34 | getParamValue('keepDims', node, tensorMap, context) as boolean; 35 | return [tfc.max( 36 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 37 | keepDims)]; 38 | } 39 | case 'Mean': { 40 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 41 | const keepDims = 42 | getParamValue('keepDims', node, tensorMap, context) as boolean; 43 | return [tfc.mean( 44 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 45 | keepDims)]; 46 | } 47 | case 'Min': { 48 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 49 | const keepDims = 50 | getParamValue('keepDims', node, tensorMap, context) as boolean; 51 | return [tfc.min( 52 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 53 | keepDims)]; 54 | } 55 | case 'Sum': { 56 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 57 | const keepDims = 58 | getParamValue('keepDims', node, tensorMap, context) as boolean; 59 | return [tfc.sum( 60 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 61 | keepDims)]; 62 | } 63 | case 'All': { 64 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 65 | const keepDims = 66 | getParamValue('keepDims', node, tensorMap, context) as boolean; 67 | return [tfc.all( 68 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 69 | keepDims)]; 70 | } 71 | case 'Any': { 72 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 73 | const keepDims = 74 | getParamValue('keepDims', node, tensorMap, context) as boolean; 75 | return [tfc.any( 76 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 77 | keepDims)]; 78 | } 79 | case 'ArgMax': { 80 | const axis = getParamValue('axis', node, tensorMap, context) as number; 81 | return [tfc.argMax( 82 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis)]; 83 | } 84 | case 'ArgMin': { 85 | const axis = getParamValue('axis', node, tensorMap, context) as number; 86 | return [tfc.argMin( 87 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis)]; 88 | } 89 | case 'Prod': { 90 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 91 | const keepDims = 92 | getParamValue('keepDims', node, tensorMap, context) as boolean; 93 | return [tfc.prod( 94 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis, 95 | keepDims)]; 96 | } 97 | default: 98 | throw TypeError(`Node type ${node.op} is not implemented`); 99 | } 100 | }; 101 | 102 | export const CATEGORY = 'reduction'; 103 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/reduction_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import {Node} from '../types'; 21 | 22 | import {executeOp} from './reduction_executor'; 23 | // tslint:disable-next-line:max-line-length 24 | import {createBoolAttr, createNumberAttr, createTensorAttr} from './test_helper'; 25 | 26 | describe('reduction', () => { 27 | let node: Node; 28 | const input1 = [tfc.scalar(1)]; 29 | const context = new ExecutionContext({}, {}); 30 | 31 | beforeEach(() => { 32 | node = { 33 | name: 'test', 34 | op: '', 35 | category: 'logical', 36 | inputNames: ['input1'], 37 | inputs: [], 38 | inputParams: {x: createTensorAttr(0)}, 39 | attrParams: {keepDims: createBoolAttr(true), axis: createNumberAttr(1)}, 40 | children: [] 41 | }; 42 | }); 43 | 44 | describe('executeOp', () => { 45 | ['Max', 'Mean', 'Min', 'Sum', 'All', 'Any', 'Prod'].forEach(op => { 46 | it('should call tfc.' + op, () => { 47 | const spy = 48 | spyOn(tfc, op.charAt(0).toLowerCase() + op.slice(1) as 'max'); 49 | node.op = op; 50 | executeOp(node, {input1}, context); 51 | 52 | expect(spy).toHaveBeenCalledWith(input1[0], 1, true); 53 | }); 54 | }); 55 | describe('ArgMax', () => { 56 | it('should call tfc.argMax', () => { 57 | spyOn(tfc, 'argMax'); 58 | node.op = 'ArgMax'; 59 | executeOp(node, {input1}, context); 60 | 61 | expect(tfc.argMax).toHaveBeenCalledWith(input1[0], 1); 62 | }); 63 | }); 64 | describe('ArgMin', () => { 65 | it('should call tfc.argMin', () => { 66 | spyOn(tfc, 'argMin'); 67 | node.op = 'ArgMin'; 68 | executeOp(node, {input1}, context); 69 | 70 | expect(tfc.argMin).toHaveBeenCalledWith(input1[0], 1); 71 | }); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/spectral_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = 27 | (node: Node, tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): tfc.Tensor[] => { 29 | switch (node.op) { 30 | case 'FFT': { 31 | return [tfc.fft( 32 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 33 | } 34 | case 'IFFT': { 35 | return [tfc.ifft( 36 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 37 | } 38 | case 'RFFT': { 39 | return [tfc.rfft( 40 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 41 | } 42 | case 'IRFFT': { 43 | return [tfc.irfft( 44 | getParamValue('x', node, tensorMap, context) as tfc.Tensor)]; 45 | } 46 | default: 47 | throw TypeError(`Node type ${node.op} is not implemented`); 48 | } 49 | }; 50 | 51 | export const CATEGORY = 'spectral'; 52 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/spectral_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as tfc from '@tensorflow/tfjs-core'; 18 | 19 | import {ExecutionContext} from '../../executor/execution_context'; 20 | import * as spectral from '../op_list/spectral'; 21 | import {Node, OpMapper} from '../types'; 22 | 23 | import {executeOp} from './spectral_executor'; 24 | import {createTensorAttr, validateParam} from './test_helper'; 25 | 26 | describe('spectral', () => { 27 | let node: Node; 28 | const input1 = [tfc.scalar(1)]; 29 | const context = new ExecutionContext({}, {}); 30 | 31 | beforeEach(() => { 32 | node = { 33 | name: 'test', 34 | op: '', 35 | category: 'spectral', 36 | inputNames: ['input1'], 37 | inputs: [], 38 | inputParams: {x: createTensorAttr(0)}, 39 | attrParams: {}, 40 | children: [] 41 | }; 42 | }); 43 | 44 | describe('executeOp', () => { 45 | describe('FFT', () => { 46 | it('should call tfc.fft', () => { 47 | spyOn(tfc, 'fft'); 48 | node.op = 'FFT'; 49 | executeOp(node, {input1}, context); 50 | 51 | expect(tfc.fft).toHaveBeenCalledWith(input1[0]); 52 | }); 53 | it('should match json def', () => { 54 | node.op = 'FFT'; 55 | 56 | expect(validateParam(node, spectral.json as OpMapper[])).toBeTruthy(); 57 | }); 58 | }); 59 | describe('IFFT', () => { 60 | it('should call tfc.ifft', () => { 61 | spyOn(tfc, 'ifft'); 62 | node.op = 'IFFT'; 63 | executeOp(node, {input1}, context); 64 | 65 | expect(tfc.ifft).toHaveBeenCalledWith(input1[0]); 66 | }); 67 | it('should match json def', () => { 68 | node.op = 'IFFT'; 69 | 70 | expect(validateParam(node, spectral.json as OpMapper[])).toBeTruthy(); 71 | }); 72 | }); 73 | describe('RFFT', () => { 74 | it('should call tfc.rfft', () => { 75 | spyOn(tfc, 'rfft'); 76 | node.op = 'RFFT'; 77 | executeOp(node, {input1}, context); 78 | 79 | expect(tfc.rfft).toHaveBeenCalledWith(input1[0]); 80 | }); 81 | it('should match json def', () => { 82 | node.op = 'RFFT'; 83 | 84 | expect(validateParam(node, spectral.json as OpMapper[])).toBeTruthy(); 85 | }); 86 | }); 87 | describe('IRFFT', () => { 88 | it('should call tfc.irfft', () => { 89 | spyOn(tfc, 'irfft'); 90 | node.op = 'IRFFT'; 91 | executeOp(node, {input1}, context); 92 | 93 | expect(tfc.irfft).toHaveBeenCalledWith(input1[0]); 94 | }); 95 | it('should match json def', () => { 96 | node.op = 'IRFFT'; 97 | 98 | expect(validateParam(node, spectral.json as OpMapper[])).toBeTruthy(); 99 | }); 100 | }); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/test_helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import {InputParamValue, OpMapper, ParamValue} from '../types'; 18 | import {Node} from '../types'; 19 | 20 | export function createNumberAttr(value: number): ParamValue { 21 | return {value, type: 'number'}; 22 | } 23 | 24 | export function createNumberAttrFromIndex(inputIndex: number): InputParamValue { 25 | return {inputIndexStart: inputIndex, type: 'number'}; 26 | } 27 | 28 | export function createStrAttr(str: string): ParamValue { 29 | return {value: str, type: 'string'}; 30 | } 31 | 32 | export function createBoolAttr(value: boolean): ParamValue { 33 | return {value, type: 'bool'}; 34 | } 35 | 36 | export function createTensorShapeAttr(value: number[]): ParamValue { 37 | return {value, type: 'shape'}; 38 | } 39 | export function createNumericArrayAttr(value: number[]): ParamValue { 40 | return {value, type: 'number[]'}; 41 | } 42 | 43 | export function createNumericArrayAttrFromIndex(inputIndex: number): 44 | InputParamValue { 45 | return {inputIndexStart: inputIndex, type: 'number[]'}; 46 | } 47 | 48 | export function createTensorAttr(index: number): InputParamValue { 49 | return {inputIndexStart: index, type: 'tensor'}; 50 | } 51 | 52 | export function createTensorsAttr( 53 | index: number, paramLength: number): InputParamValue { 54 | return {inputIndexStart: index, inputIndexEnd: paramLength, type: 'tensors'}; 55 | } 56 | 57 | export function createDtypeAttr(dtype: string): ParamValue { 58 | return {value: dtype, type: 'dtype'}; 59 | } 60 | 61 | export function validateParam( 62 | node: Node, opMappers: OpMapper[], tfOpName?: string) { 63 | const opMapper = tfOpName != null ? 64 | opMappers.find(mapper => mapper.tfOpName === tfOpName) : 65 | opMappers.find(mapper => mapper.tfOpName === node.op); 66 | return Object.keys(node.inputParams).every(key => { 67 | const value = node.inputParams[key]; 68 | const def = opMapper.inputs.find(param => param.name === key); 69 | return def && def.type === value.type && 70 | def.start === value.inputIndexStart && def.end === value.inputIndexEnd; 71 | }) && 72 | Object.keys(node.attrParams).every(key => { 73 | const value = node.attrParams[key]; 74 | const def = opMapper.attrs.find(param => param.name === key); 75 | return def && def.type === value.type; 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/transformation_executor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {InternalOpExecutor, Node} from '../types'; 23 | 24 | import {getParamValue, split} from './utils'; 25 | 26 | export let executeOp: InternalOpExecutor = (node: Node, 27 | tensorMap: NamedTensorsMap, 28 | context: ExecutionContext): 29 | tfc.Tensor[] => { 30 | switch (node.op) { 31 | case 'Cast': { 32 | return [tfc.cast( 33 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 34 | getParamValue('dtype', node, tensorMap, context) as 'int32' | 35 | 'float32' | 'bool')]; 36 | } 37 | case 'ExpandDims': { 38 | const axis = getParamValue('axis', node, tensorMap, context) as number; 39 | return [tfc.expandDims( 40 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis)]; 41 | } 42 | case 'Squeeze': { 43 | const axis = getParamValue('axis', node, tensorMap, context) as number[]; 44 | return [tfc.squeeze( 45 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, axis)]; 46 | } 47 | 48 | case 'Reshape': { 49 | return [tfc.reshape( 50 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 51 | getParamValue('shape', node, tensorMap, context) as number[])]; 52 | } 53 | case 'PadV2': 54 | case 'Pad': { 55 | return [tfc.pad( 56 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 57 | split( 58 | getParamValue('padding', node, tensorMap, context) as number[], 59 | 2) as Array<[number, number]>, 60 | getParamValue('constantValue', node, tensorMap, context) as number)]; 61 | } 62 | case 'SpaceToBatchND': { 63 | const blockShape = 64 | getParamValue('blockShape', node, tensorMap, context) as number[]; 65 | const paddings = split( 66 | getParamValue('paddings', node, tensorMap, context) as number[], 2); 67 | return [tfc.spaceToBatchND( 68 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 69 | blockShape, paddings)]; 70 | } 71 | case 'BatchToSpaceND': { 72 | const blockShape = 73 | getParamValue('blockShape', node, tensorMap, context) as number[]; 74 | const crops = split( 75 | getParamValue('crops', node, tensorMap, context) as number[], 2); 76 | return [tfc.batchToSpaceND( 77 | getParamValue('x', node, tensorMap, context) as tfc.Tensor, 78 | blockShape, crops)]; 79 | } 80 | case 'DepthToSpace': { 81 | const blockSize = 82 | getParamValue('blockSize', node, tensorMap, context) as number; 83 | const dataFormat = 84 | (getParamValue('dataFormat', node, tensorMap, context) as 85 | string).toUpperCase() as 'NHWC' | 86 | 'NCHW'; 87 | return [tfc.depthToSpace( 88 | getParamValue('x', node, tensorMap, context) as tfc.Tensor4D, 89 | blockSize, dataFormat)]; 90 | } 91 | default: 92 | throw TypeError(`Node type ${node.op} is not implemented`); 93 | } 94 | }; 95 | 96 | export const CATEGORY = 'transformation'; 97 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/executors/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as tfc from '@tensorflow/tfjs-core'; 19 | 20 | import {NamedTensorsMap} from '../../data/types'; 21 | import {ExecutionContext} from '../../executor/execution_context'; 22 | import {Node, ValueType} from '../types'; 23 | 24 | export function getParamValue( 25 | paramName: string, node: Node, tensorMap: NamedTensorsMap, 26 | context: ExecutionContext): ValueType { 27 | const inputParam = node.inputParams[paramName]; 28 | if (inputParam && inputParam.inputIndexStart !== undefined) { 29 | const start = inputParam.inputIndexStart; 30 | const end = inputParam.inputIndexEnd === 0 ? 31 | undefined : 32 | (inputParam.inputIndexEnd === undefined ? start + 1 : 33 | inputParam.inputIndexEnd); 34 | if (inputParam.type === 'tensor') { 35 | return getTensor( 36 | node.inputNames[inputParam.inputIndexStart], tensorMap, context); 37 | } 38 | if (inputParam.type === 'tensors') { 39 | const inputs = node.inputNames.slice(start, end); 40 | 41 | return inputs.map(name => getTensor(name, tensorMap, context)); 42 | } 43 | const data = Array.prototype.slice.call( 44 | getTensor(node.inputNames.slice(start)[0], tensorMap, context) 45 | .dataSync()); 46 | return inputParam.type === 'number' ? data[0] : data; 47 | } 48 | const attrParam = node.attrParams[paramName]; 49 | return attrParam && attrParam.value; 50 | } 51 | 52 | /** 53 | * Retrieve the tensor based on input name by extracting the node name and 54 | * output index information. 55 | * @param name Node input name 56 | * @param tensorsMap Tensors map keyed by the node 57 | */ 58 | export function getTensor( 59 | name: string, tensorsMap: NamedTensorsMap, 60 | context: ExecutionContext): tfc.Tensor { 61 | const [nodeName, index] = parseNodeName(name); 62 | const contextId = context.currentContextIds.find(contextId => { 63 | return !!tensorsMap[getNodeNameWithContextId(nodeName, contextId)]; 64 | }); 65 | 66 | return contextId !== undefined ? 67 | tensorsMap[getNodeNameWithContextId(nodeName, contextId)][index] : 68 | undefined; 69 | } 70 | 71 | /** 72 | * Retrieve the tensors based on input name for current context. 73 | * @param name Node input name 74 | * @param tensorsMap Tensors map keyed by the node 75 | */ 76 | export function getTensorsForCurrentContenxt( 77 | name: string, tensorsMap: NamedTensorsMap, 78 | context: ExecutionContext): tfc.Tensor[] { 79 | return tensorsMap[getNodeNameWithContextId(name, context.currentContextId)]; 80 | } 81 | 82 | /** 83 | * Returns the node name and index from the Node input name. 84 | * @param inputName The input name of the node, in format of 85 | * node_name:output_index, i.e. MatMul:0, if the output_index is not set, it is 86 | * default to 0. 87 | */ 88 | export function getNodeNameAndIndex( 89 | inputName: string, context?: ExecutionContext): [string, number] { 90 | const [nodeName, index] = parseNodeName(inputName); 91 | 92 | return [ 93 | getNodeNameWithContextId(nodeName, context && context.currentContextId), 94 | index 95 | ]; 96 | } 97 | 98 | function getNodeNameWithContextId(name: string, contextId?: string): string { 99 | return !!contextId ? `${name}-${contextId}` : name; 100 | } 101 | 102 | export function parseNodeName(name: string): [string, number] { 103 | const index = name.lastIndexOf(':'); 104 | if (index === -1) return [name, 0]; 105 | 106 | const nodeName = name.substring(0, index); 107 | return [nodeName, Number(name.substring(index + 1))]; 108 | } 109 | 110 | export function split(arr: number[], size: number) { 111 | const res = []; 112 | for (let i = 0; i < arr.length; i += size) { 113 | res.push(arr.slice(i, i + size)); 114 | } 115 | return res; 116 | } 117 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/dynamic.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'NonMaxSuppressionV2', 23 | 'category': 'dynamic', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'boxes', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'scores', 'type': 'tensor'}, 27 | {'start': 2, 'name': 'maxOutputSize', 'type': 'number'}, 28 | {'start': 3, 'name': 'iouThreshold', 'type': 'number'} 29 | ] 30 | }, 31 | { 32 | 'tfOpName': 'NonMaxSuppressionV3', 33 | 'category': 'dynamic', 34 | 'inputs': [ 35 | {'start': 0, 'name': 'boxes', 'type': 'tensor'}, 36 | {'start': 1, 'name': 'scores', 'type': 'tensor'}, 37 | {'start': 2, 'name': 'maxOutputSize', 'type': 'number'}, 38 | {'start': 3, 'name': 'iouThreshold', 'type': 'number'}, 39 | {'start': 4, 'name': 'scoreThreshold', 'type': 'number'} 40 | ] 41 | }, 42 | { 43 | 'tfOpName': 'Where', 44 | 'category': 'dynamic', 45 | 'inputs': [ 46 | {'start': 0, 'name': 'condition', 'type': 'tensor'}, 47 | ], 48 | 'attrs': [ 49 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 50 | ] 51 | }, 52 | { 53 | 'tfOpName': 'ListDiff', 54 | 'category': 'dynamic', 55 | 'inputs': [ 56 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 57 | {'start': 1, 'name': 'y', 'type': 'tensor'}, 58 | ], 59 | 'attrs': [{ 60 | 'tfName': 'T', 61 | 'name': 'dtype', 62 | 'type': 'dtype', 63 | 'notSupported': true 64 | }] 65 | } 66 | ]; 67 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/evaluation.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [{ 21 | 'tfOpName': 'TopKV2', 22 | 'category': 'evaluation', 23 | 'inputs': [ 24 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 25 | {'start': 1, 'name': 'k', 'type': 'number'}, 26 | ], 27 | 'attrs': [{'tfName': 'sorted', 'name': 'sorted', 'type': 'bool'}] 28 | }]; 29 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/graph.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'PlaceholderWithDefault', 23 | 'category': 'graph', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'default', 'type': 'tensor'}, 26 | ], 27 | 'attrs': [ 28 | {'tfName': 'shape', 'name': 'shape', 'type': 'shape'}, 29 | {'tfName': 'dtype', 'name': 'dtype', 'type': 'dtype'} 30 | ] 31 | }, 32 | { 33 | 'tfOpName': 'Placeholder', 34 | 'category': 'graph', 35 | 'attrs': [ 36 | {'tfName': 'shape', 'name': 'shape', 'type': 'shape'}, 37 | {'tfName': 'dtype', 'name': 'dtype', 'type': 'dtype'} 38 | ] 39 | }, 40 | {'tfOpName': 'Const', 'category': 'graph'}, { 41 | 'tfOpName': 'Identity', 42 | 'category': 'graph', 43 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 44 | }, 45 | { 46 | 'tfOpName': 'IdentityN', 47 | 'category': 'graph', 48 | 'inputs': [{'start': 0, 'end': 0, 'name': 'x', 'type': 'tensors'}] 49 | }, 50 | { 51 | 'tfOpName': 'Snapshot', 52 | 'category': 'graph', 53 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 54 | }, 55 | { 56 | 'tfOpName': 'Rank', 57 | 'category': 'graph', 58 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 59 | }, 60 | { 61 | 'tfOpName': 'Size', 62 | 'category': 'graph', 63 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 64 | }, 65 | { 66 | 'tfOpName': 'Shape', 67 | 'category': 'graph', 68 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 69 | }, 70 | { 71 | 'tfOpName': 'ShapeN', 72 | 'category': 'graph', 73 | 'inputs': [{'start': 0, 'end': 0, 'name': 'x', 'type': 'tensors'}] 74 | }, 75 | { 76 | 'tfOpName': 'Print', 77 | 'category': 'graph', 78 | 'inputs': [ 79 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 80 | {'start': 1, 'name': 'data', 'type': 'tensors'}, 81 | ], 82 | 'attrs': [ 83 | {'tfName': 'message', 'name': 'message', 'type': 'string'}, { 84 | 'tfName': 'first_n', 85 | 'name': 'firstN', 86 | 'type': 'number', 87 | 'notSupported': true 88 | }, 89 | { 90 | 'tfName': 'summarize', 91 | 'name': 'summarize', 92 | 'type': 'number', 93 | 'defaultValue': 3 94 | } 95 | ] 96 | }, 97 | {'tfOpName': 'NoOp', 'category': 'graph', 'inputs': []}, { 98 | 'tfOpName': 'StopGradient', 99 | 'category': 'graph', 100 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 101 | }, 102 | { 103 | 'tfOpName': 'FakeQuantWithMinMaxVars', 104 | 'category': 'graph', 105 | 'inputs': [ 106 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 107 | ], 108 | 'attrs': [ 109 | {'tfName': 'min', 'name': 'min', 'type': 'number'}, 110 | {'tfName': 'max', 'name': 'max', 'type': 'number'} 111 | ] 112 | } 113 | ]; 114 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/image.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'ResizeBilinear', 23 | 'category': 'image', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'images', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'size', 'type': 'number[]'}, 27 | ], 28 | 'attrs': [ 29 | {'tfName': 'align_corners', 'name': 'alignCorners', 'type': 'bool'}, 30 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 31 | ] 32 | }, 33 | { 34 | 'tfOpName': 'ResizeNearestNeighbor', 35 | 'category': 'image', 36 | 'inputs': [ 37 | {'start': 0, 'name': 'images', 'type': 'tensor'}, 38 | {'start': 1, 'name': 'size', 'type': 'number[]'}, 39 | ], 40 | 'attrs': [ 41 | {'tfName': 'align_corners', 'name': 'alignCorners', 'type': 'bool'}, 42 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 43 | ] 44 | }, 45 | { 46 | 'tfOpName': 'CropAndResize', 47 | 'category': 'image', 48 | 'inputs': [ 49 | {'start': 0, 'name': 'image', 'type': 'tensor'}, 50 | {'start': 1, 'name': 'boxes', 'type': 'tensor'}, 51 | {'start': 2, 'name': 'boxInd', 'type': 'tensor'}, 52 | {'start': 3, 'name': 'cropSize', 'type': 'number[]'}, 53 | ], 54 | 'attrs': [ 55 | {'tfName': 'method', 'name': 'method', 'type': 'string'}, { 56 | 'tfName': 'extrapolation_value', 57 | 'name': 'extrapolationValue', 58 | 'type': 'number' 59 | } 60 | ] 61 | } 62 | ]; 63 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/logical.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'Equal', 23 | 'category': 'logical', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 27 | ], 28 | 'attrs': [ 29 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 30 | ] 31 | }, 32 | { 33 | 'tfOpName': 'NotEqual', 34 | 'category': 'logical', 35 | 'inputs': [ 36 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 37 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 38 | ], 39 | 'attrs': [ 40 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 41 | ] 42 | }, 43 | { 44 | 'tfOpName': 'Greater', 45 | 'category': 'logical', 46 | 'inputs': [ 47 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 48 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 49 | ], 50 | 'attrs': [ 51 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 52 | ] 53 | }, 54 | { 55 | 'tfOpName': 'GreaterEqual', 56 | 'category': 'logical', 57 | 'inputs': [ 58 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 59 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 60 | ], 61 | 'attrs': [ 62 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 63 | ] 64 | }, 65 | { 66 | 'tfOpName': 'Less', 67 | 'category': 'logical', 68 | 'inputs': [ 69 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 70 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 71 | ], 72 | 'attrs': [ 73 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 74 | ] 75 | }, 76 | { 77 | 'tfOpName': 'LessEqual', 78 | 'category': 'logical', 79 | 'inputs': [ 80 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 81 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 82 | ], 83 | 'attrs': [ 84 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 85 | ] 86 | }, 87 | { 88 | 'tfOpName': 'LogicalAnd', 89 | 'category': 'logical', 90 | 'inputs': [ 91 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 92 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 93 | ], 94 | 'attrs': [ 95 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 96 | ] 97 | }, 98 | { 99 | 'tfOpName': 'LogicalNot', 100 | 'category': 'logical', 101 | 'inputs': [ 102 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 103 | ], 104 | 'attrs': [ 105 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 106 | ] 107 | }, 108 | { 109 | 'tfOpName': 'LogicalOr', 110 | 'category': 'logical', 111 | 'inputs': [ 112 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 113 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 114 | ], 115 | 'attrs': [ 116 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 117 | ] 118 | }, 119 | { 120 | 'tfOpName': 'Select', 121 | 'category': 'logical', 122 | 'inputs': [ 123 | {'start': 0, 'name': 'condition', 'type': 'tensor'}, 124 | {'start': 1, 'name': 'a', 'type': 'tensor'}, 125 | {'start': 2, 'name': 'b', 'type': 'tensor'}, 126 | ], 127 | 'attrs': [{ 128 | 'tfName': 'T', 129 | 'name': 'dtype', 130 | 'type': 'dtype', 131 | 'notSupported': true 132 | }] 133 | } 134 | ]; 135 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/matrices.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import {OpMapper} from '../types'; 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'MatMul', 23 | 'category': 'matrices', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 27 | ], 28 | 'attrs': [ 29 | { 30 | 'tfName': 'transpose_a', 31 | 'name': 'transposeA', 32 | 'type': 'bool', 33 | 'defaultValue': false 34 | }, 35 | { 36 | 'tfName': 'transpose_b', 37 | 'name': 'transposeB', 38 | 'type': 'bool', 39 | 'defaultValue': false 40 | }, 41 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 42 | ] 43 | }, 44 | { 45 | 'tfOpName': 'BatchMatMul', 46 | 'category': 'matrices', 47 | 'inputs': [ 48 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 49 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 50 | ], 51 | 'attrs': [ 52 | { 53 | 'tfName': 'adj_x', 54 | 'name': 'transposeA', 55 | 'type': 'bool', 56 | 'defaultValue': false 57 | }, 58 | { 59 | 'tfName': 'adj_y', 60 | 'name': 'transposeB', 61 | 'type': 'bool', 62 | 'defaultValue': false 63 | }, 64 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 65 | ] 66 | }, 67 | { 68 | 'tfOpName': 'BatchMatMulV2', 69 | 'category': 'matrices', 70 | 'inputs': [ 71 | {'start': 0, 'name': 'a', 'type': 'tensor'}, 72 | {'start': 1, 'name': 'b', 'type': 'tensor'}, 73 | ], 74 | 'attrs': [ 75 | { 76 | 'tfName': 'adj_x', 77 | 'name': 'transposeA', 78 | 'type': 'bool', 79 | 'defaultValue': false 80 | }, 81 | { 82 | 'tfName': 'adj_y', 83 | 'name': 'transposeB', 84 | 'type': 'bool', 85 | 'defaultValue': false 86 | }, 87 | {'tfName': 'T', 'name': 'dtype', 'type': 'dtype', 'notSupported': true} 88 | ] 89 | }, 90 | { 91 | 'tfOpName': 'Transpose', 92 | 'category': 'matrices', 93 | 'inputs': [ 94 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 95 | {'start': 1, 'name': 'perm', 'type': 'number[]'}, 96 | ], 97 | 'attrs': [{ 98 | 'tfName': 'T', 99 | 'name': 'dtype', 100 | 'type': 'dtype', 101 | 'notSupported': true 102 | }] 103 | } 104 | ]; 105 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/normalization.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'FusedBatchNorm', 23 | 'category': 'normalization', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'scale', 'type': 'tensor'}, 27 | {'start': 2, 'name': 'offset', 'type': 'tensor'}, 28 | {'start': 3, 'name': 'mean', 'type': 'tensor'}, 29 | {'start': 4, 'name': 'variance', 'type': 'tensor'}, 30 | ], 31 | 'attrs': [ 32 | { 33 | 'tfName': 'epsilon', 34 | 'name': 'epsilon', 35 | 'type': 'number', 36 | 'defaultValue': 0.001 37 | }, 38 | { 39 | 'tfName': 'data_format', 40 | 'name': 'dataFormat', 41 | 'type': 'string', 42 | 'notSupported': true 43 | } 44 | ] 45 | }, 46 | { 47 | 'tfOpName': 'FusedBatchNormV2', 48 | 'category': 'normalization', 49 | 'inputs': [ 50 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 51 | {'start': 1, 'name': 'scale', 'type': 'tensor'}, 52 | {'start': 2, 'name': 'offset', 'type': 'tensor'}, 53 | {'start': 3, 'name': 'mean', 'type': 'tensor'}, 54 | {'start': 4, 'name': 'variance', 'type': 'tensor'}, 55 | ], 56 | 'attrs': [ 57 | { 58 | 'tfName': 'epsilon', 59 | 'name': 'epsilon', 60 | 'type': 'number', 61 | 'defaultValue': 0.001 62 | }, 63 | { 64 | 'tfName': 'data_format', 65 | 'name': 'dataFormat', 66 | 'type': 'string', 67 | 'notSupported': true 68 | } 69 | ] 70 | }, 71 | { 72 | 'tfOpName': 'FusedBatchNormV3', 73 | 'category': 'normalization', 74 | 'inputs': [ 75 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 76 | {'start': 1, 'name': 'scale', 'type': 'tensor'}, 77 | {'start': 2, 'name': 'offset', 'type': 'tensor'}, 78 | {'start': 3, 'name': 'mean', 'type': 'tensor'}, 79 | {'start': 4, 'name': 'variance', 'type': 'tensor'}, 80 | ], 81 | 'attrs': [ 82 | { 83 | 'tfName': 'epsilon', 84 | 'name': 'epsilon', 85 | 'type': 'number', 86 | 'defaultValue': 0.001 87 | }, 88 | { 89 | 'tfName': 'data_format', 90 | 'name': 'dataFormat', 91 | 'type': 'string', 92 | 'notSupported': true 93 | } 94 | ] 95 | }, 96 | { 97 | 'tfOpName': 'LRN', 98 | 'category': 'normalization', 99 | 'inputs': [ 100 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 101 | ], 102 | 'attrs': [ 103 | { 104 | 'tfName': 'depth_radius', 105 | 'name': 'radius', 106 | 'type': 'number', 107 | 'defaultValue': 5 108 | }, 109 | {'tfName': 'bias', 'name': 'bias', 'type': 'number', 'defaultValue': 1.0}, 110 | { 111 | 'tfName': 'alpha', 112 | 'name': 'alpha', 113 | 'type': 'number', 114 | 'defaultValue': 1.0 115 | }, 116 | { 117 | 'tfName': 'beta', 118 | 'name': 'beta', 119 | 'type': 'number', 120 | 'defaultValue': 0.5 121 | } 122 | ] 123 | }, 124 | { 125 | 'tfOpName': 'Softmax', 126 | 'category': 'normalization', 127 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 128 | }, 129 | { 130 | 'tfOpName': 'LogSoftmax', 131 | 'category': 'normalization', 132 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 133 | }, 134 | { 135 | 'tfOpName': 'SparseToDense', 136 | 'category': 'normalization', 137 | 'inputs': [ 138 | {'start': 0, 'name': 'sparseIndices', 'type': 'tensor'}, 139 | {'start': 1, 'name': 'outputShape', 'type': 'number[]'}, 140 | {'start': 2, 'name': 'sparseValues', 'type': 'tensor'}, 141 | {'start': 3, 'name': 'defaultValue', 'type': 'tensor'}, 142 | ], 143 | 'attrs': [{ 144 | 'tfName': 'validate_indices', 145 | 'name': 'validateIndices', 146 | 'type': 'bool', 147 | 'defaultValue': true, 148 | 'notSupported': true 149 | }] 150 | } 151 | ]; 152 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/op_list_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import * as ajv from 'ajv'; 19 | import * as schema from '../op_mapper_schema'; 20 | 21 | import * as arithmetic from './arithmetic'; 22 | import * as basicMath from './basic_math'; 23 | import * as control from './control'; 24 | import * as convolution from './convolution'; 25 | import * as creation from './creation'; 26 | import * as dynamic from './dynamic'; 27 | import * as evaluation from './evaluation'; 28 | import * as graph from './graph'; 29 | import * as image from './image'; 30 | import * as logical from './logical'; 31 | import * as matrices from './matrices'; 32 | import * as normalization from './normalization'; 33 | import * as reduction from './reduction'; 34 | import * as sliceJoin from './slice_join'; 35 | import * as transformation from './transformation'; 36 | 37 | describe('OpListTest', () => { 38 | const jsonValidator = new ajv(); 39 | const validator = jsonValidator.compile(schema.json); 40 | beforeEach(() => {}); 41 | 42 | // tslint:disable-next-line:no-any 43 | const mappersJson: any = { 44 | arithmetic, 45 | basicMath, 46 | control, 47 | convolution, 48 | dynamic, 49 | evaluation, 50 | creation, 51 | logical, 52 | image, 53 | graph, 54 | matrices, 55 | normalization, 56 | reduction, 57 | sliceJoin, 58 | transformation 59 | }; 60 | Object.keys(mappersJson).forEach(key => { 61 | it('should satisfy the schema: ' + key, () => { 62 | const valid = validator(mappersJson[key].json); 63 | if (!valid) console.log(validator.errors); 64 | expect(valid).toBeTruthy(); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/reduction.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'Max', 23 | 'category': 'reduction', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 26 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 27 | ], 28 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 29 | }, 30 | { 31 | 'tfOpName': 'Mean', 32 | 'category': 'reduction', 33 | 'inputs': [ 34 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 35 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 36 | ], 37 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 38 | }, 39 | { 40 | 'tfOpName': 'Min', 41 | 'category': 'reduction', 42 | 'inputs': [ 43 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 44 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 45 | ], 46 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 47 | }, 48 | { 49 | 'tfOpName': 'Sum', 50 | 'category': 'reduction', 51 | 'inputs': [ 52 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 53 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 54 | ], 55 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 56 | }, 57 | { 58 | 'tfOpName': 'All', 59 | 'category': 'reduction', 60 | 'inputs': [ 61 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 62 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 63 | ], 64 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 65 | }, 66 | { 67 | 'tfOpName': 'Any', 68 | 'category': 'reduction', 69 | 'inputs': [ 70 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 71 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 72 | ], 73 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 74 | }, 75 | { 76 | 'tfOpName': 'ArgMax', 77 | 'category': 'reduction', 78 | 'inputs': [ 79 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 80 | {'start': 1, 'name': 'axis', 'type': 'number'} 81 | ] 82 | }, 83 | { 84 | 'tfOpName': 'ArgMin', 85 | 'category': 'reduction', 86 | 'inputs': [ 87 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 88 | {'start': 1, 'name': 'axis', 'type': 'number'} 89 | ] 90 | }, 91 | { 92 | 'tfOpName': 'Prod', 93 | 'category': 'reduction', 94 | 'inputs': [ 95 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 96 | {'start': 1, 'name': 'axis', 'type': 'number[]'}, 97 | ], 98 | 'attrs': [{'tfName': 'keep_dims', 'name': 'keepDims', 'type': 'bool'}] 99 | } 100 | ]; 101 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/spectral.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'FFT', 23 | 'category': 'spectral', 24 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 25 | }, 26 | { 27 | 'tfOpName': 'IFFT', 28 | 'category': 'spectral', 29 | 'inputs': [{'start': 0, 'name': 'x', 'type': 'tensor'}] 30 | }, 31 | { 32 | 'tfOpName': 'RFFT', 33 | 'category': 'spectral', 34 | 'inputs': [ 35 | {'start': 0, 'name': 'x', 'type': 'tensor'}, { 36 | 'start': 1, 37 | 'name': 'fft_length', 38 | 'type': 'number', 39 | 'notSupported': true 40 | } 41 | ] 42 | }, 43 | { 44 | 'tfOpName': 'IRFFT', 45 | 'category': 'spectral', 46 | 'inputs': [ 47 | {'start': 0, 'name': 'x', 'type': 'tensor'}, { 48 | 'start': 1, 49 | 'name': 'fft_length', 50 | 'type': 'number', 51 | 'notSupported': true 52 | } 53 | ] 54 | } 55 | ]; 56 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_list/transformation.ts: -------------------------------------------------------------------------------- 1 | import {OpMapper} from '../types'; 2 | 3 | /** 4 | * @license 5 | * Copyright 2018 Google LLC. All Rights Reserved. 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================================= 18 | */ 19 | 20 | export const json: OpMapper[] = [ 21 | { 22 | 'tfOpName': 'Cast', 23 | 'category': 'transformation', 24 | 'inputs': [ 25 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 26 | ], 27 | 'attrs': [ 28 | { 29 | 'tfName': 'SrcT', 30 | 'name': 'sdtype', 31 | 'type': 'dtype', 32 | 'notSupported': true 33 | }, 34 | {'tfName': 'DstT', 'name': 'dtype', 'type': 'dtype'} 35 | ] 36 | }, 37 | { 38 | 'tfOpName': 'ExpandDims', 39 | 'category': 'transformation', 40 | 'inputs': [ 41 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 42 | {'start': 1, 'name': 'axis', 'type': 'number'} 43 | ] 44 | }, 45 | { 46 | 'tfOpName': 'Pad', 47 | 'category': 'transformation', 48 | 'inputs': [ 49 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 50 | {'start': 1, 'name': 'padding', 'type': 'number[]'}, 51 | ], 52 | 'attrs': [{ 53 | 'tfName': 'constant_value', 54 | 'name': 'constantValue', 55 | 'type': 'number', 56 | 'defaultValue': 0 57 | }] 58 | }, 59 | { 60 | 'tfOpName': 'PadV2', 61 | 'category': 'transformation', 62 | 'inputs': [ 63 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 64 | {'start': 1, 'name': 'padding', 'type': 'number[]'}, { 65 | 'start': 2, 66 | 'name': 'constantValue', 67 | 'type': 'number', 68 | 'defaultValue': 0 69 | } 70 | ] 71 | }, 72 | { 73 | 'tfOpName': 'Reshape', 74 | 'category': 'transformation', 75 | 'inputs': [ 76 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 77 | {'start': 1, 'name': 'shape', 'type': 'number[]'} 78 | ] 79 | }, 80 | { 81 | 'tfOpName': 'Squeeze', 82 | 'category': 'transformation', 83 | 'inputs': [ 84 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 85 | ], 86 | 'attrs': [{ 87 | 'tfName': 'axis', 88 | 'tfDeprecatedName': 'squeeze_dims', 89 | 'name': 'axis', 90 | 'type': 'number[]' 91 | }] 92 | }, 93 | { 94 | 'tfOpName': 'SpaceToBatchND', 95 | 'category': 'transformation', 96 | 'inputs': [ 97 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 98 | {'start': 1, 'name': 'blockShape', 'type': 'number[]'}, 99 | {'start': 2, 'name': 'paddings', 'type': 'number[]'} 100 | ] 101 | }, 102 | { 103 | 'tfOpName': 'BatchToSpaceND', 104 | 'category': 'transformation', 105 | 'inputs': [ 106 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 107 | {'start': 1, 'name': 'blockShape', 'type': 'number[]'}, 108 | {'start': 2, 'name': 'crops', 'type': 'number[]'} 109 | ] 110 | }, 111 | { 112 | 'tfOpName': 'DepthToSpace', 113 | 'category': 'transformation', 114 | 'inputs': [ 115 | {'start': 0, 'name': 'x', 'type': 'tensor'}, 116 | ], 117 | 'attrs': [ 118 | {'tfName': 'block_size', 'name': 'blockSize', 'type': 'number'}, 119 | {'tfName': 'data_format', 'name': 'dataFormat', 'type': 'string'} 120 | ] 121 | } 122 | ]; 123 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/op_mapper_schema.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | export const json = { 19 | '$schema': 'http://json-schema.org/draft-07/schema#', 20 | 'definitions': { 21 | 'OpMapper': { 22 | 'type': 'object', 23 | 'properties': { 24 | 'tfOpName': {'type': 'string'}, 25 | 'category': {'$ref': '#/definitions/Category'}, 26 | 'inputs': { 27 | 'type': 'array', 28 | 'items': {'$ref': '#/definitions/InputParamMapper'} 29 | }, 30 | 'attrs': { 31 | 'type': 'array', 32 | 'items': {'$ref': '#/definitions/AttrParamMapper'} 33 | }, 34 | 'customExecutor': {'$ref': '#/definitions/OpExecutor'} 35 | }, 36 | 'required': ['tfOpName'], 37 | 'additionalProperties': false 38 | }, 39 | 'Category': { 40 | 'type': 'string', 41 | 'enum': [ 42 | 'arithmetic', 'basic_math', 'control', 'convolution', 'custom', 43 | 'dynamic', 'evaluation', 'image', 'creation', 'graph', 'logical', 44 | 'matrices', 'normalization', 'reduction', 'slice_join', 'spectral', 45 | 'transformation' 46 | ] 47 | }, 48 | 'InputParamMapper': { 49 | 'type': 'object', 50 | 'properties': { 51 | 'name': {'type': 'string'}, 52 | 'type': {'$ref': '#/definitions/ParamTypes'}, 53 | 'defaultValue': { 54 | 'anyOf': [ 55 | {'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}, 56 | {'type': 'number'}, {'type': 'array', 'items': {'type': 'number'}}, 57 | {'type': 'boolean'}, 58 | {'type': 'array', 'items': {'type': 'boolean'}} 59 | ] 60 | }, 61 | 'notSupported': {'type': 'boolean'}, 62 | 'start': {'type': 'number'}, 63 | 'end': {'type': 'number'} 64 | }, 65 | 'required': ['name', 'start', 'type'], 66 | 'additionalProperties': false 67 | }, 68 | 'ParamTypes': { 69 | 'type': 'string', 70 | 'enum': [ 71 | 'number', 'string', 'number[]', 'bool', 'shape', 'tensor', 'tensors', 72 | 'dtype' 73 | ] 74 | }, 75 | 'AttrParamMapper': { 76 | 'type': 'object', 77 | 'properties': { 78 | 'name': {'type': 'string'}, 79 | 'type': {'$ref': '#/definitions/ParamTypes'}, 80 | 'defaultValue': { 81 | 'anyOf': [ 82 | {'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}, 83 | {'type': 'number'}, {'type': 'array', 'items': {'type': 'number'}}, 84 | {'type': 'boolean'}, 85 | {'type': 'array', 'items': {'type': 'boolean'}} 86 | ] 87 | }, 88 | 'notSupported': {'type': 'boolean'}, 89 | 'tfName': {'type': 'string'}, 90 | 'tfDeprecatedName': {'type': 'string'} 91 | }, 92 | 'required': ['name', 'tfName', 'type'], 93 | 'additionalProperties': false 94 | }, 95 | 'OpExecutor': {'type': 'object', 'additionalProperties': false} 96 | }, 97 | 'items': {'$ref': '#/definitions/OpMapper'}, 98 | 'type': 'array' 99 | }; 100 | -------------------------------------------------------------------------------- /tfjs-converter/src/operations/operation_executor_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | 18 | import {add, mul, scalar, Tensor, test_util} from '@tensorflow/tfjs-core'; 19 | 20 | import {ExecutionContext} from '../executor/execution_context'; 21 | 22 | import {deregisterOp, registerOp} from './custom_op/register'; 23 | import * as arithmetic from './executors/arithmetic_executor'; 24 | import * as basic_math from './executors/basic_math_executor'; 25 | import * as convolution from './executors/convolution_executor'; 26 | import * as creation from './executors/creation_executor'; 27 | import * as dynamic from './executors/dynamic_executor'; 28 | import * as evaluation from './executors/evaluation_executor'; 29 | import * as graph from './executors/graph_executor'; 30 | import * as image from './executors/image_executor'; 31 | import * as logical from './executors/logical_executor'; 32 | import * as matrices from './executors/matrices_executor'; 33 | import * as normalization from './executors/normalization_executor'; 34 | import * as reduction from './executors/reduction_executor'; 35 | import * as slice_join from './executors/slice_join_executor'; 36 | import * as spectral from './executors/spectral_executor'; 37 | import * as transformation from './executors/transformation_executor'; 38 | import {executeOp} from './operation_executor'; 39 | import {Node} from './types'; 40 | 41 | describe('OperationExecutor', () => { 42 | let node: Node; 43 | const context = new ExecutionContext({}, {}); 44 | 45 | beforeEach(() => { 46 | node = { 47 | name: 'test', 48 | op: 'const', 49 | category: 'graph', 50 | inputNames: [], 51 | inputs: [], 52 | inputParams: {}, 53 | attrParams: {}, 54 | children: [] 55 | }; 56 | }); 57 | 58 | describe('executeOp', () => { 59 | [arithmetic, basic_math, convolution, creation, dynamic, evaluation, image, 60 | graph, logical, matrices, normalization, reduction, slice_join, spectral, 61 | transformation] 62 | .forEach(category => { 63 | it('should call ' + category.CATEGORY + ' executor', () => { 64 | spyOn(category, 'executeOp'); 65 | node.category = category.CATEGORY; 66 | executeOp(node, {}, context); 67 | expect(category.executeOp).toHaveBeenCalledWith(node, {}, context); 68 | }); 69 | }); 70 | }); 71 | 72 | describe('custom op executeOp', () => { 73 | it('should throw exception if custom op is not registered', () => { 74 | node.category = 'custom'; 75 | expect(() => executeOp(node, {}, context)) 76 | .toThrowError('Custom op const is not registered.'); 77 | }); 78 | }); 79 | 80 | describe('custom op executeOp', () => { 81 | it('should call the registered custom op', async () => { 82 | registerOp('const', () => [scalar(1)]); 83 | registerOp('const2', () => [scalar(2)]); 84 | node.category = 'custom'; 85 | const result = executeOp(node, {}, context) as Tensor[]; 86 | test_util.expectArraysClose(await result[0].data(), [1]); 87 | deregisterOp('const'); 88 | deregisterOp('const2'); 89 | }); 90 | 91 | it('should handle custom op with inputs and attrs', async () => { 92 | registerOp('const', (node) => { 93 | const a = node.inputs[0]; 94 | const b = node.inputs[1]; 95 | const attrC = node.attrs['c'] as Tensor; 96 | const attrD = node.attrs['d'] as number; 97 | return [add(mul(attrC.dataSync()[0], a), mul(attrD, b))]; 98 | }); 99 | 100 | node.category = 'custom'; 101 | node.inputNames = ['a', 'b']; 102 | node.rawAttrs = {c: {tensor: {}}, d: {i: 3}}; 103 | const result = executeOp( 104 | node, {a: [scalar(1)], b: [scalar(2)], c: [scalar(2)]}, 105 | context) as Tensor[]; 106 | // result = 2 * 1 + 3 * 2 107 | test_util.expectArraysClose(await result[0].data(), [8]); 108 | deregisterOp('const'); 109 | }); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /tfjs-converter/src/version.ts: -------------------------------------------------------------------------------- 1 | /** @license See the LICENSE file. */ 2 | 3 | // This code is auto-generated, do not modify this file! 4 | const version = '1.2.7'; 5 | export {version}; 6 | -------------------------------------------------------------------------------- /tfjs-converter/src/version_test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. 4 | * 5 | * Use of this source code is governed by an MIT-style 6 | * license that can be found in the LICENSE file or at 7 | * https://opensource.org/licenses/MIT. 8 | * ============================================================================= 9 | */ 10 | 11 | // tslint:disable-next-line:no-require-imports 12 | const packageJSON = require('../package.json'); 13 | import {version_converter} from './index'; 14 | 15 | describe('tfjs-core version consistency', () => { 16 | it('dev-peer match', () => { 17 | const tfjsCoreDevDepVersion = 18 | packageJSON.devDependencies['@tensorflow/tfjs-core']; 19 | const tfjsCorePeerDepVersion = 20 | packageJSON.peerDependencies['@tensorflow/tfjs-core']; 21 | expect(tfjsCoreDevDepVersion).toEqual(tfjsCorePeerDepVersion); 22 | }); 23 | 24 | it('version.ts matches package version', () => { 25 | // tslint:disable-next-line:no-require-imports 26 | const expected = require('../package.json').version; 27 | expect(version_converter).toBe(expected); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /tfjs-converter/tools/pb2json_converter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC. All Rights Reserved. 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * ============================================================================= 16 | */ 17 | import * as fs from 'fs'; 18 | import * as Long from 'long'; 19 | import * as path from 'path'; 20 | 21 | import {tensorflow} from './compiled_api'; 22 | 23 | function replacer(key: string, value: any) { 24 | if (value instanceof Long) { 25 | return (value as Long).toString(); 26 | } 27 | if (value instanceof Uint8Array) { 28 | return Array.from(value); 29 | } 30 | return value; 31 | } 32 | const PB_MODEL_FILENAME = 'tensorflowjs_model.pb'; 33 | const WEIGHT_FILENAME = 'weights_manifest.json'; 34 | const JSON_MODEL_FILENAME = 'model.json'; 35 | function convert(argv: string[]) { 36 | if (argv.length < 4) { 37 | console.log( 38 | 'Usage: ts-node pb2json.ts pb_model_directory json_model_directory'); 39 | return; 40 | } 41 | 42 | const sourcePath = process.argv[2]; 43 | console.log('reading pb model directory: ' + sourcePath); 44 | fs.readdir(sourcePath, (err, files) => { 45 | if (![PB_MODEL_FILENAME, WEIGHT_FILENAME].every( 46 | file => files.indexOf(file) !== -1)) { 47 | console.log( 48 | 'Please make sure the pb model directory contains ' + 49 | 'tensorflowjs_model.pb and weights_manifest.json files.'); 50 | return; 51 | } 52 | 53 | const modelFile = path.join(sourcePath, PB_MODEL_FILENAME); 54 | console.log('reading pb file: ' + modelFile); 55 | const buffer = fs.readFileSync(modelFile); 56 | 57 | const modelTopology = tensorflow.GraphDef.decode(new Uint8Array(buffer)); 58 | 59 | const manifestFile = path.join(sourcePath, WEIGHT_FILENAME); 60 | console.log('reading manifest file: ' + manifestFile); 61 | const weightsManifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8')); 62 | 63 | const destPath = process.argv[3]; 64 | 65 | if (!fs.existsSync(destPath)) { 66 | fs.mkdirSync(destPath); 67 | } 68 | const destModelFile = path.join(destPath, JSON_MODEL_FILENAME); 69 | console.log('writing json file: ' + destModelFile); 70 | fs.writeFileSync( 71 | destModelFile, 72 | JSON.stringify({modelTopology, weightsManifest}, replacer)); 73 | 74 | files.forEach(file => { 75 | if (file !== PB_MODEL_FILENAME && file !== WEIGHT_FILENAME) { 76 | fs.copyFile( 77 | path.join(sourcePath, file), path.join(destPath, file), (err) => { 78 | if (err) throw err; 79 | console.log(`Weight file: ${file} copied.`); 80 | }); 81 | } 82 | }); 83 | }); 84 | } 85 | 86 | convert(process.argv); 87 | -------------------------------------------------------------------------------- /tfjs-converter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "noImplicitAny": true, 6 | "sourceMap": true, 7 | "removeComments": false, 8 | "preserveConstEnums": true, 9 | "declaration": true, 10 | "target": "es5", 11 | "lib": [ 12 | "es2015", 13 | "dom" 14 | ], 15 | "outDir": "./dist", 16 | "noUnusedLocals": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "alwaysStrict": true, 20 | "noUnusedParameters": false, 21 | "pretty": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "allowUnreachableCode": false 24 | }, 25 | "include": [ 26 | "src/", 27 | "scripts/" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /tfjs-converter/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint-no-circular-imports"], 3 | "linterOptions": { 4 | "exclude": [ 5 | "src/data/compiled_api.ts" 6 | ] 7 | }, 8 | "rules": { 9 | "array-type": [true, "array-simple"], 10 | "arrow-return-shorthand": true, 11 | "ban": [true, 12 | ["fit"], 13 | ["fdescribe"], 14 | ["xit"], 15 | ["xdescribe"], 16 | ["fitAsync"], 17 | ["xitAsync"], 18 | ["fitFakeAsync"], 19 | ["xitFakeAsync"] 20 | ], 21 | "ban-types": [true, 22 | ["Object", "Use {} instead."], 23 | ["String", "Use 'string' instead."], 24 | ["Number", "Use 'number' instead."], 25 | ["Boolean", "Use 'boolean' instead."] 26 | ], 27 | "class-name": true, 28 | "interface-name": [true, "never-prefix"], 29 | "jsdoc-format": true, 30 | "forin": false, 31 | "label-position": true, 32 | "max-line-length": { 33 | "options": {"limit": 80, "ignore-pattern": "^import |^export "} 34 | }, 35 | "new-parens": true, 36 | "no-angle-bracket-type-assertion": true, 37 | "no-any": true, 38 | "no-construct": true, 39 | "no-consecutive-blank-lines": true, 40 | "no-debugger": true, 41 | "no-default-export": true, 42 | "no-inferrable-types": true, 43 | "no-namespace": [true, "allow-declarations"], 44 | "no-reference": true, 45 | "no-require-imports": true, 46 | "no-string-throw": true, 47 | "no-unused-expression": true, 48 | "no-unused-variable": [true, {"ignore-pattern": "^_"}], 49 | "no-var-keyword": true, 50 | "object-literal-shorthand": true, 51 | "only-arrow-functions": [true, "allow-declarations", "allow-named-functions"], 52 | "prefer-const": true, 53 | "radix": true, 54 | "restrict-plus-operands": true, 55 | "semicolon": [true, "always", "ignore-bound-class-methods"], 56 | "switch-default": true, 57 | "triple-equals": [true, "allow-null-check"], 58 | "use-isnan": true, 59 | "variable-name": [ 60 | true, 61 | "check-format", 62 | "ban-keywords", 63 | "allow-leading-underscore", 64 | "allow-trailing-underscore" 65 | ] 66 | } 67 | } 68 | --------------------------------------------------------------------------------