/**
|
* @license
|
* Copyright 2018 Google LLC. All Rights Reserved.
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
* =============================================================================
|
*/
|
import * as tf from '../index';
|
import { ALL_ENVS, describeWithFlags } from '../jasmine_util';
|
import { expectArraysClose } from '../test_util';
|
describeWithFlags('AdamOptimizer', ALL_ENVS, () => {
|
it('basic', async () => {
|
const initialTensors = tf.memory().numTensors;
|
const learningRate = .1;
|
const beta1 = .8;
|
const beta2 = .9;
|
const optimizer = tf.train.adam(learningRate, beta1, beta2);
|
const x = tf.tensor1d([2, 4]).variable();
|
const f = () => x.square().sum();
|
let numTensors = tf.memory().numTensors;
|
let cost = optimizer.minimize(f, /* returnCost */ true);
|
// Cost & 2 accumulators should be the only additional arrays.
|
expect(tf.memory().numTensors).toBe(numTensors + 3);
|
// new_first_m = [
|
// beta1 * old_first_m_w1 + (1-beta1) * grad_w1,
|
// beta1 * old_first_m_w2 + (1-beta1) * grad_w2
|
// ] = [.8, 1.6]
|
// new_second_m = [
|
// beta2 * old_second_m_w1 + (1-beta2) * grad_w1**2,
|
// beta2 * old_second_m_w2 + (1-beta2) * grad_w2**2
|
// ] = [1.6, 6.4]
|
// m = [new_first_m/(1-acc_beta1)] = [4, 8]
|
// v = [new_second_m/(1-acc_beta2)] = [16, 64]
|
// x = [x - lr * m / sqrt(v)] = [1.9, 3.9]
|
//
|
expectArraysClose(await x.data(), [1.9, 3.9]);
|
cost.dispose();
|
numTensors = tf.memory().numTensors;
|
cost = optimizer.minimize(f, /* returnCost */ false);
|
// new_first_m = [
|
// beta1 * old_first_m_w1 + (1-beta1) * grad_w1,
|
// beta1 * old_first_m_w2 + (1-beta1) * grad_w2
|
// ] = [1.4, 2.84]
|
// new_second_m = [
|
// beta2 * old_second_m_w1 + (1-beta2) * grad_w1**2,
|
// beta2 * old_second_m_w2 + (1-beta2) * grad_w2**2
|
// ] = [2.884, 11.884]
|
// m = [new_first_m/(1-acc_beta1)] = [3.888888, 7.88889]
|
// v = [new_second_m/(1-acc_beta2)] = [15.1789, 62.5473]
|
// x = [x - lr * m / sqrt(v)] = [1.8000001, 3.8002]
|
//
|
expectArraysClose(await x.data(), [1.8000001, 3.8002]);
|
// There should be no new additional Tensors.
|
expect(tf.memory().numTensors).toBe(numTensors);
|
expect(cost).toBe(null);
|
x.dispose();
|
optimizer.dispose();
|
// The only additional tensor remaining should be the argument to
|
// variable().
|
expect(tf.memory().numTensors).toBe(initialTensors + 1);
|
});
|
it('Continue training after loading weights', async () => {
|
const initialTensors = tf.memory().numTensors;
|
const learningRate = .1;
|
const beta1 = .8;
|
const beta2 = .9;
|
const optimizer1 = tf.train.adam(learningRate, beta1, beta2);
|
const x = tf.tensor1d([2, 4]).variable();
|
const f = () => x.square().sum();
|
let cost = optimizer1.minimize(f, /* returnCost */ true);
|
expect(optimizer1.iterations).toEqual(1);
|
expectArraysClose(await cost.data(), 20);
|
const weights = await optimizer1.getWeights();
|
expect(weights.length).toEqual(3);
|
expect(weights[0].name).toEqual('iter');
|
expect(weights[1].name).toEqual(`${x.name}/m`);
|
expect(weights[2].name).toEqual(`${x.name}/v`);
|
const optimizer2 = tf.train.adam(learningRate, beta1, beta2);
|
await optimizer2.setWeights(weights);
|
cost = optimizer2.minimize(f, /* returnCost */ true);
|
expectArraysClose(await cost.data(), 18.82);
|
expect(optimizer2.iterations).toEqual(2);
|
const optimizer3 = tf.train.adam(learningRate, beta1, beta2);
|
await optimizer3.setWeights(await optimizer2.getWeights());
|
cost = optimizer2.minimize(f, /* returnCost */ true);
|
expectArraysClose(await cost.data(), 17.681284);
|
expect(optimizer3.iterations).toEqual(initialTensors + 2);
|
});
|
it('serialization round-trip', () => {
|
const originalOpt = tf.train.adam(0.1, 0.2, 0.3, 2e-8);
|
const reserialized = tf.AdamOptimizer.fromConfig(tf.AdamOptimizer, originalOpt.getConfig());
|
expect(reserialized.getConfig()).toEqual(originalOpt.getConfig());
|
});
|
});
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRhbV9vcHRpbWl6ZXJfdGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtY29yZS9zcmMvb3B0aW1pemVycy9hZGFtX29wdGltaXplcl90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9CLE9BQU8sRUFBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUM1RCxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFFL0MsaUJBQWlCLENBQUMsZUFBZSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7SUFDaEQsRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLElBQUksRUFBRTtRQUNyQixNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDO1FBQzlDLE1BQU0sWUFBWSxHQUFHLEVBQUUsQ0FBQztRQUN4QixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7UUFDakIsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2pCLE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFNUQsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRXpDLE1BQU0sQ0FBQyxHQUFvQixHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFbEQsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQztRQUV4QyxJQUFJLElBQUksR0FBRyxTQUFTLENBQUMs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QyxFQUFFLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JELGlCQUFpQixDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsT0FBTyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM1RCxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQywwQkFBMEIsRUFBRSxHQUFHLEVBQUU7UUFDbEMsTUFBTSxXQUFXLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdkQsTUFBTSxZQUFZLEdBQ2QsRUFBRSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUMzRSxNQUFNLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOCBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCAqIGFzIHRmIGZyb20gJy4uL2luZGV4JztcbmltcG9ydCB7QUxMX0VOVlMsIGRlc2NyaWJlV2l0aEZsYWdzfSBmcm9tICcuLi9qYXNtaW5lX3V0aWwnO1xuaW1wb3J0IHtleHBlY3RBcnJheXNDbG9zZX0gZnJvbSAnLi4vdGVzdF91dGlsJztcblxuZGVzY3JpYmVXaXRoRmxhZ3MoJ0FkYW1PcHRpbWl6ZXInLCBBTExfRU5WUywgKCkgPT4ge1xuICBpdCgnYmFzaWMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgaW5pdGlhbFRlbnNvcnMgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IGJldGExID0gLjg7XG4gICAgY29uc3QgYmV0YTIgPSAuOTtcbiAgICBjb25zdCBvcHRpbWl6ZXIgPSB0Zi50cmFpbi5hZGFtKGxlYXJuaW5nUmF0ZSwgYmV0YTEsIGJldGEyKTtcblxuICAgIGNvbnN0IHggPSB0Zi50ZW5zb3IxZChbMiwgNF0pLnZhcmlhYmxlKCk7XG5cbiAgICBjb25zdCBmOiAoKSA9PiB0Zi5TY2FsYXIgPSAoKSA9PiB4LnNxdWFyZSgpLnN1bSgpO1xuXG4gICAgbGV0IG51bVRlbnNvcnMgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuXG4gICAgbGV0IGNvc3QgPSBvcHRpbWl6ZXIubWluaW1pemUoZiwgLyogcmV0dXJuQ29zdCAqLyB0cnVlKTtcblxuICAgIC8vIENvc3QgJiAyIGFjY3VtdWxhdG9ycyBzaG91bGQgYmUgdGhlIG9ubHkgYWRkaXRpb25hbCBhcnJheXMuXG4gICAgZXhwZWN0KHRmLm1lbW9yeSgpLm51bVRlbnNvcnMpLnRvQmUobnVtVGVuc29ycyArIDMpO1xuICAgIC8vIG5ld19maXJzdF9tID0gW1xuICAgIC8vICAgIGJldGExICogb2xkX2ZpcnN0X21fdzEgKyAoMS1iZXRhMSkgKiBncmFkX3cxLFxuICAgIC8vICAgIGJldGExICogb2xkX2ZpcnN0X21fdzIgKyAoMS1iZXRhMSkgKiBncmFkX3cyXG4gICAgLy8gXSA9IFsuOCwgMS42XVxuICAgIC8vIG5ld19zZWNvbmRfbSA9IFtcbiAgICAvLyAgICBiZXRhMiAqIG9sZF9zZWNvbmRfbV93MSArICgxLWJldGEyKSAqIGdyYWRfdzEqKjIsXG4gICAgLy8gICAgYmV0YTIgKiBvbGRfc2Vjb25kX21fdzIgKyAoMS1iZXRhMikgKiBncmFkX3cyKioyXG4gICAgLy8gXSA9IFsxLjYsIDYuNF1cbiAgICAvLyBtID0gW25ld19maXJzdF9tLygxLWFjY19iZXRhMSldID0gWzQsIDhdXG4gICAgLy8gdiA9IFtuZXdfc2Vjb25kX20vKDEtYWNjX2JldGEyKV0gPSBbMTYsIDY0XVxuICAgIC8vIHggPSBbeCAtIGxyICogbSAvIHNxcnQodildID0gWzEuOSwgMy45XVxuICAgIC8vXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgeC5kYXRhKCksIFsxLjksIDMuOV0pO1xuXG4gICAgY29zdC5kaXNwb3NlKCk7XG4gICAgbnVtVGVuc29ycyA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG5cbiAgICBjb3N0ID0gb3B0aW1pemVyLm1pbmltaXplKGYsIC8qIHJldHVybkNvc3QgKi8gZmFsc2UpO1xuXG4gICAgLy8gbmV3X2ZpcnN0X20gPSBbXG4gICAgLy8gICAgYmV0YTEgKiBvbGRfZmlyc3RfbV93MSArICgxLWJldGExKSAqIGdyYWRfdzEsXG4gICAgLy8gICAgYmV0YTEgKiBvbGRfZmlyc3RfbV93MiArICgxLWJldGExKSAqIGdyYWRfdzJcbiAgICAvLyBdID0gWzEuNCwgMi44NF1cbiAgICAvLyBuZXdfc2Vjb25kX20gPSBbXG4gICAgLy8gICAgYmV0YTIgKiBvbGRfc2Vjb25kX21fdzEgKyAoMS1iZXRhMikgKiBncmFkX3cxKioyLFxuICAgIC8vICAgIGJldGEyICogb2xkX3NlY29uZF9tX3cyICsgKDEtYmV0YTIpICogZ3JhZF93MioqMlxuICAgIC8vIF0gPSBbMi44ODQsIDExLjg4NF1cbiAgICAvLyBtID0gW25ld19maXJzdF9tLygxLWFjY19iZXRhMSldID0gWzMuODg4ODg4LCA3Ljg4ODg5XVxuICAgIC8vIHYgPSBbbmV3X3NlY29uZF9tLygxLWFjY19iZXRhMildID0gWzE1LjE3ODksIDYyLjU0NzNdXG4gICAgLy8geCA9IFt4IC0gbHIgKiBtIC8gc3FydCh2KV0gPSBbMS44MDAwMDAxLCAzLjgwMDJdXG4gICAgLy9cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB4LmRhdGEoKSwgWzEuODAwMDAwMSwgMy44MDAyXSk7XG4gICAgLy8gVGhlcmUgc2hvdWxkIGJlIG5vIG5ldyBhZGRpdGlvbmFsIFRlbnNvcnMuXG4gICAgZXhwZWN0KHRmLm1lbW9yeSgpLm51bVRlbnNvcnMpLnRvQmUobnVtVGVuc29ycyk7XG5cbiAgICBleHBlY3QoY29zdCkudG9CZShudWxsKTtcblxuICAgIHguZGlzcG9zZSgpO1xuICAgIG9wdGltaXplci5kaXNwb3NlKCk7XG5cbiAgICAvLyBUaGUgb25seSBhZGRpdGlvbmFsIHRlbnNvciByZW1haW5pbmcgc2hvdWxkIGJlIHRoZSBhcmd1bWVudCB0b1xuICAgIC8vIHZhcmlhYmxlKCkuXG4gICAgZXhwZWN0KHRmLm1lbW9yeSgpLm51bVRlbnNvcnMpLnRvQmUoaW5pdGlhbFRlbnNvcnMgKyAxKTtcbiAgfSk7XG5cbiAgaXQoJ0NvbnRpbnVlIHRyYWluaW5nIGFmdGVyIGxvYWRpbmcgd2VpZ2h0cycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBpbml0aWFsVGVuc29ycyA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG4gICAgY29uc3QgbGVhcm5pbmdSYXRlID0gLjE7XG4gICAgY29uc3QgYmV0YTEgPSAuODtcbiAgICBjb25zdCBiZXRhMiA9IC45O1xuICAgIGNvbnN0IG9wdGltaXplcjEgPSB0Zi50cmFpbi5hZGFtKGxlYXJuaW5nUmF0ZSwgYmV0YTEsIGJldGEyKTtcblxuICAgIGNvbnN0IHggPSB0Zi50ZW5zb3IxZChbMiwgNF0pLnZhcmlhYmxlKCk7XG4gICAgY29uc3QgZjogKCkgPT4gdGYuU2NhbGFyID0gKCkgPT4geC5zcXVhcmUoKS5zdW0oKTtcbiAgICBsZXQgY29zdCA9IG9wdGltaXplcjEubWluaW1pemUoZiwgLyogcmV0dXJuQ29zdCAqLyB0cnVlKTtcbiAgICBleHBlY3Qob3B0aW1pemVyMS5pdGVyYXRpb25zKS50b0VxdWFsKDEpO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGNvc3QuZGF0YSgpLCAyMCk7XG5cbiAgICBjb25zdCB3ZWlnaHRzID0gYXdhaXQgb3B0aW1pemVyMS5nZXRXZWlnaHRzKCk7XG4gICAgZXhwZWN0KHdlaWdodHMubGVuZ3RoKS50b0VxdWFsKDMpO1xuICAgIGV4cGVjdCh3ZWlnaHRzWzBdLm5hbWUpLnRvRXF1YWwoJ2l0ZXInKTtcbiAgICBleHBlY3Qod2VpZ2h0c1sxXS5uYW1lKS50b0VxdWFsKGAke3gubmFtZX0vbWApO1xuICAgIGV4cGVjdCh3ZWlnaHRzWzJdLm5hbWUpLnRvRXF1YWwoYCR7eC5uYW1lfS92YCk7XG5cbiAgICBjb25zdCBvcHRpbWl6ZXIyID0gdGYudHJhaW4uYWRhbShsZWFybmluZ1JhdGUsIGJldGExLCBiZXRhMik7XG4gICAgYXdhaXQgb3B0aW1pemVyMi5zZXRXZWlnaHRzKHdlaWdodHMpO1xuXG4gICAgY29zdCA9IG9wdGltaXplcjIubWluaW1pemUoZiwgLyogcmV0dXJuQ29zdCAqLyB0cnVlKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBjb3N0LmRhdGEoKSwgMTguODIpO1xuICAgIGV4cGVjdChvcHRpbWl6ZXIyLml0ZXJhdGlvbnMpLnRvRXF1YWwoMik7XG5cbiAgICBjb25zdCBvcHRpbWl6ZXIzID0gdGYudHJhaW4uYWRhbShsZWFybmluZ1JhdGUsIGJldGExLCBiZXRhMik7XG4gICAgYXdhaXQgb3B0aW1pemVyMy5zZXRXZWlnaHRzKGF3YWl0IG9wdGltaXplcjIuZ2V0V2VpZ2h0cygpKTtcbiAgICBjb3N0ID0gb3B0aW1pemVyMi5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUpO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGNvc3QuZGF0YSgpLCAxNy42ODEyODQpO1xuICAgIGV4cGVjdChvcHRpbWl6ZXIzLml0ZXJhdGlvbnMpLnRvRXF1YWwoaW5pdGlhbFRlbnNvcnMgKyAyKTtcbiAgfSk7XG5cbiAgaXQoJ3NlcmlhbGl6YXRpb24gcm91bmQtdHJpcCcsICgpID0+IHtcbiAgICBjb25zdCBvcmlnaW5hbE9wdCA9IHRmLnRyYWluLmFkYW0oMC4xLCAwLjIsIDAuMywgMmUtOCk7XG4gICAgY29uc3QgcmVzZXJpYWxpemVkID1cbiAgICAgICAgdGYuQWRhbU9wdGltaXplci5mcm9tQ29uZmlnKHRmLkFkYW1PcHRpbWl6ZXIsIG9yaWdpbmFsT3B0LmdldENvbmZpZygpKTtcbiAgICBleHBlY3QocmVzZXJpYWxpemVkLmdldENvbmZpZygpKS50b0VxdWFsKG9yaWdpbmFsT3B0LmdldENvbmZpZygpKTtcbiAgfSk7XG59KTtcbiJdfQ==
|